Globally rename all occurrences of "XCode" to "Xcode".
[wxWidgets.git] / build / tools / builder.py
1 import os
2 import string
3 import subprocess
4 import sys
5 import time
6
7 class BuildError(Exception):
8 def __init__(self, value):
9 self.value = value
10
11 def __repr__(self):
12 return repr(self.value)
13
14 def runInDir(command, dir=None, verbose=True):
15 if dir:
16 olddir = os.getcwd()
17 os.chdir(dir)
18
19 commandStr = " ".join(command)
20 if verbose:
21 print commandStr
22 result = os.system(commandStr)
23
24 if dir:
25 os.chdir(olddir)
26
27 return result
28
29 class Builder:
30 """
31 Base class exposing the Builder interface.
32 """
33
34 def __init__(self, formatName="", commandName="", programDir=None):
35 """
36 formatName = human readable name for project format (should correspond with Bakefile names)
37 commandName = name of command line program used to invoke builder
38 programDir = directory program is located in, if not on the path
39 """
40
41 self.dir = dir
42 self.name = commandName
43 self.formatName = formatName
44 self.programDir = programDir
45 self.doSetup()
46
47 def doSetup(self):
48 """
49 Do anything special needed to configure the environment to build with this builder.
50 """
51
52 pass
53
54 def isAvailable(self):
55 """
56 Run sanity checks before attempting to build with this format
57 """
58 # Make sure the builder program exists
59 programPath = self.getProgramPath()
60 if os.path.exists(programPath):
61 return True
62 else:
63 # check the PATH for the program
64 # TODO: How do we check if we're in Cygwin?
65 if sys.platform.startswith("win"):
66 result = os.system(self.name)
67 if result == 0:
68 return True
69 dirs = os.environ["PATH"].split(":")
70
71 for dir in dirs:
72 if os.path.isfile(os.path.join(dir, self.name)):
73 return True
74
75 else:
76 result = os.system("which %s" % self.name)
77
78 if result == 0:
79 return True
80
81 return False
82
83 def getProgramPath(self):
84 if self.programDir:
85 path = os.path.join(self.programDir, self.name)
86 if sys.platform.startswith("win"):
87 path = '"%s"' % path
88 return path
89
90 return self.name
91
92 def clean(self, dir=None, projectFile=None):
93 """
94 dir = the directory containing the project file
95 projectFile = Some formats need to explicitly specify the project file's name
96 """
97
98 args = [self.getProgramPath(), "clean"]
99 if dir:
100 args.append(dir)
101 if self.isAvailable():
102 result = runInDir(args)
103 return result
104
105 return False
106
107 def configure(self, options=None):
108 # if we don't have configure, just report success
109 return True
110
111 def build(self, dir=None, projectFile=None, targets=None, options=None):
112 if self.isAvailable():
113 if options:
114 optionList = list(options)
115 else:
116 optionList = []
117
118 optionList.insert(0, self.getProgramPath())
119
120 result = runInDir(optionList, dir)
121
122 return result
123
124 return 1
125
126 def install(self, dir=None, options=None):
127 if self.isAvailable():
128
129 args = ["make", "install"]
130 if options:
131 args.extend(options)
132 result = runInDir(args, dir)
133 return result
134
135 return 1
136
137 # Concrete subclasses of abstract Builder interface
138
139 class GNUMakeBuilder(Builder):
140 def __init__(self, commandName="make", formatName="GNUMake"):
141 Builder.__init__(self, commandName=commandName, formatName=formatName)
142
143
144 class XcodeBuilder(Builder):
145 def __init__(self, commandName="xcodebuild", formatName="Xcode"):
146 Builder.__init__(self, commandName=commandName, formatName=formatName)
147
148
149 class AutoconfBuilder(GNUMakeBuilder):
150 def __init__(self, formatName="autoconf"):
151 GNUMakeBuilder.__init__(self, formatName=formatName)
152
153 def configure(self, dir=None, options=None):
154 #olddir = os.getcwd()
155 #os.chdir(dir)
156
157 configdir = dir
158 if not dir:
159 configdir = os.getcwd()
160
161 configure_cmd = ""
162 while os.path.exists(configdir):
163 config_cmd = os.path.join(configdir, "configure")
164 if not os.path.exists(config_cmd):
165 parentdir = os.path.abspath(os.path.join(configdir, ".."))
166 if configdir == parentdir:
167 break
168
169 configdir = parentdir
170 else:
171 configure_cmd = config_cmd
172 break
173
174 if not configure_cmd:
175 sys.stderr.write("Could not find configure script at %r. Have you run autoconf?\n" % dir)
176 return 1
177
178 optionsStr = string.join(options, " ") if options else ""
179 command = "%s %s" % (configure_cmd, optionsStr)
180 print command
181 result = os.system(command)
182 #os.chdir(olddir)
183 return result
184
185
186 class MSVCBuilder(Builder):
187 def __init__(self):
188 Builder.__init__(self, commandName="nmake.exe", formatName="msvc")
189
190 def isAvailable(self):
191 PATH = os.environ['PATH'].split(os.path.pathsep)
192 for p in PATH:
193 if os.path.exists(os.path.join(p, self.name)):
194 return True
195 return False
196
197
198 class MSVCProjectBuilder(Builder):
199 def __init__(self):
200 Builder.__init__(self, commandName="VCExpress.exe", formatName="msvcProject")
201 for key in ["VS90COMNTOOLS", "VC80COMNTOOLS", "VC71COMNTOOLS"]:
202 if os.environ.has_key(key):
203 self.prgoramDir = os.path.join(os.environ[key], "..", "IDE")
204
205 if self.programDir == None:
206 for version in ["9.0", "8", ".NET 2003"]:
207 msvcDir = "C:\\Program Files\\Microsoft Visual Studio %s\\Common7\\IDE" % version
208 if os.path.exists(msvcDir):
209 self.programDir = msvcDir
210
211 def isAvailable(self):
212 if self.programDir:
213 path = os.path.join(self.programDir, self.name)
214 if os.path.exists(path):
215 return True
216 else:
217 # I don't have commercial versions of MSVC so I can't test this
218 name = "devenv.com"
219 path = os.path.join(self.programDir, name)
220 if os.path.exists(path):
221 self.name = "devenv.com"
222 return True
223
224 return False
225
226 builders = [GNUMakeBuilder, XcodeBuilder, AutoconfBuilder, MSVCBuilder, MSVCProjectBuilder]
227
228 def getAvailableBuilders():
229 availableBuilders = {}
230 for symbol in builders:
231 thisBuilder = symbol()
232 if thisBuilder.isAvailable():
233 availableBuilders[thisBuilder.formatName] = symbol
234
235 return availableBuilders