| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- import os
- import subprocess
- import sys
- import time
- class BuildError(Exception):
- def __init__(self, value):
- self.value = value
- def __repr__(self):
- return repr(self.value)
- def runInDir(command, dir=None, verbose=True):
- if dir:
- olddir = os.getcwd()
- os.chdir(dir)
- commandStr = " ".join(command)
- if verbose:
- print(commandStr)
- result = os.system(commandStr)
- if dir:
- os.chdir(olddir)
- return result
- class Builder:
- """
- Base class exposing the Builder interface.
- """
- def __init__(self, formatName="", commandName="", programDir=None):
- """
- formatName = human readable name for project format (should correspond with Bakefile names)
- commandName = name of command line program used to invoke builder
- programDir = directory program is located in, if not on the path
- """
- self.dir = dir
- self.name = commandName
- self.formatName = formatName
- self.programDir = programDir
- self.doSetup()
- def doSetup(self):
- """
- Do anything special needed to configure the environment to build with this builder.
- """
- pass
- def isAvailable(self):
- """
- Run sanity checks before attempting to build with this format
- """
- # Make sure the builder program exists
- programPath = self.getProgramPath()
- if os.path.exists(programPath):
- return True
- else:
- # check the PATH for the program
- # TODO: How do we check if we're in Cygwin?
- if sys.platform.startswith("win"):
- result = os.system(self.name)
- if result == 0:
- return True
- dirs = os.environ["PATH"].split(":")
- for dir in dirs:
- if os.path.isfile(os.path.join(dir, self.name)):
- return True
- else:
- result = os.system("which %s" % self.name)
- if result == 0:
- return True
- return False
- def getProgramPath(self):
- if self.programDir:
- path = os.path.join(self.programDir, self.name)
- if sys.platform.startswith("win"):
- path = '"%s"' % path
- return path
- return self.name
- def getProjectFileArg(self, projectFile = None):
- result = []
- if projectFile:
- result.append(projectFile)
- return result
-
- def clean(self, dir=None, projectFile=None, options=[]):
- """
- dir = the directory containing the project file
- projectFile = Some formats need to explicitly specify the project file's name
- """
- if self.isAvailable():
- args = [self.getProgramPath()]
- pfArg = self.getProjectFileArg(projectFile)
- if pfArg:
- args.extend(pfArg)
- args.append("clean")
- if options:
- args.extend(options)
- result = runInDir(args, dir)
- return result
- return False
- def configure(self, dir=None, options=[]):
- # if we don't have configure, just report success
- return 0
- def build(self, dir=None, projectFile=None, targets=None, options=[]):
- if self.isAvailable():
- args = [self.getProgramPath()]
- pfArg = self.getProjectFileArg(projectFile)
- if pfArg:
- args.extend(pfArg)
- # Important Note: if extending args, check it first!
- # NoneTypes are not iterable and will crash the clean, build, or install!
- # Very very irritating when this happens right at the end.
- if options:
- args.extend(options)
- result = runInDir(args, dir)
- return result
- return 1
- def install(self, dir=None, projectFile=None, options=[]):
- if self.isAvailable():
- args = [self.getProgramPath()]
- pfArg = self.getProjectFileArg(projectFile)
- if pfArg:
- args.extend(pfArg)
- args.append("install")
- if options:
- args.extend(options)
- result = runInDir(args, dir)
- return result
- return 1
- # Concrete subclasses of abstract Builder interface
- class GNUMakeBuilder(Builder):
- def __init__(self, commandName="make", formatName="GNUMake"):
- Builder.__init__(self, commandName=commandName, formatName=formatName)
- class XcodeBuilder(Builder):
- def __init__(self, commandName="xcodebuild", formatName="Xcode"):
- Builder.__init__(self, commandName=commandName, formatName=formatName)
- class AutoconfBuilder(GNUMakeBuilder):
- def __init__(self, formatName="autoconf"):
- GNUMakeBuilder.__init__(self, formatName=formatName)
- def configure(self, dir=None, options=None):
- #olddir = os.getcwd()
- #os.chdir(dir)
- configdir = dir
- if not dir:
- configdir = os.getcwd()
- configure_cmd = ""
- while os.path.exists(configdir):
- config_cmd = os.path.join(configdir, "configure")
- if not os.path.exists(config_cmd):
- parentdir = os.path.abspath(os.path.join(configdir, ".."))
- if configdir == parentdir:
- break
- configdir = parentdir
- else:
- configure_cmd = config_cmd
- break
- if not configure_cmd:
- sys.stderr.write("Could not find configure script at %r. Have you run autoconf?\n" % dir)
- return 1
- optionsStr = " ".join(options) if options else ""
- command = "%s %s" % (configure_cmd, optionsStr)
- print(command)
- result = os.system(command)
- #os.chdir(olddir)
- return result
- class MSVCBuilder(Builder):
- def __init__(self, commandName="nmake.exe"):
- Builder.__init__(self, commandName=commandName, formatName="msvc")
- def isAvailable(self):
- PATH = os.environ['PATH'].split(os.path.pathsep)
- for p in PATH:
- if os.path.exists(os.path.join(p, self.name)):
- return True
- return False
- def getProjectFileArg(self, projectFile = None):
- result = []
- if projectFile:
- result.extend(['-f', projectFile])
-
- return result
-
- class MSVCProjectBuilder(Builder):
- def __init__(self):
- Builder.__init__(self, commandName="VCExpress.exe", formatName="msvcProject")
- for key in ["VS90COMNTOOLS", "VC80COMNTOOLS", "VC71COMNTOOLS"]:
- if os.environ.has_key(key):
- self.programDir = os.path.join(os.environ[key], "..", "IDE")
- if self.programDir == None:
- for version in ["9.0", "8", ".NET 2003"]:
- msvcDir = "C:\\Program Files\\Microsoft Visual Studio %s\\Common7\\IDE" % version
- if os.path.exists(msvcDir):
- self.programDir = msvcDir
- def isAvailable(self):
- if self.programDir:
- path = os.path.join(self.programDir, self.name)
- if os.path.exists(path):
- return True
- else:
- # I don't have commercial versions of MSVC so I can't test this
- name = "devenv.com"
- path = os.path.join(self.programDir, name)
- if os.path.exists(path):
- self.name = "devenv.com"
- return True
- return False
- builders = [GNUMakeBuilder, XcodeBuilder, AutoconfBuilder, MSVCBuilder, MSVCProjectBuilder]
- def getAvailableBuilders():
- availableBuilders = {}
- for symbol in builders:
- thisBuilder = symbol()
- if thisBuilder.isAvailable():
- availableBuilders[thisBuilder.formatName] = symbol
- return availableBuilders
|