Line endings fixes in bakefile-generated files.
[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, options=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 if self.isAvailable():
98 if options:
99 optionList = list(options)
100 else:
101 optionList = []
102
103 optionList.insert(0, self.getProgramPath())
104 optionList.append("clean")
105
106 result = runInDir(optionList, dir)
107 return result
108
109 return False
110
111 def configure(self, options=None):
112 # if we don't have configure, just report success
113 return True
114
115 def build(self, dir=None, projectFile=None, targets=None, options=None):
116 if self.isAvailable():
117 if options:
118 optionList = list(options)
119 else:
120 optionList = []
121
122 optionList.insert(0, self.getProgramPath())
123
124 result = runInDir(optionList, dir)
125
126 return result
127
128 return 1
129
130 def install(self, dir=None, options=None):
131 if self.isAvailable():
132
133 args = ["make", "install"]
134 if options:
135 args.extend(options)
136 result = runInDir(args, dir)
137 return result
138
139 return 1
140
141 # Concrete subclasses of abstract Builder interface
142
143 class GNUMakeBuilder(Builder):
144 def __init__(self, commandName="make", formatName="GNUMake"):
145 Builder.__init__(self, commandName=commandName, formatName=formatName)
146
147
148 class XcodeBuilder(Builder):
149 def __init__(self, commandName="xcodebuild", formatName="Xcode"):
150 Builder.__init__(self, commandName=commandName, formatName=formatName)
151
152
153 class AutoconfBuilder(GNUMakeBuilder):
154 def __init__(self, formatName="autoconf"):
155 GNUMakeBuilder.__init__(self, formatName=formatName)
156
157 def configure(self, dir=None, options=None):
158 #olddir = os.getcwd()
159 #os.chdir(dir)
160
161 configdir = dir
162 if not dir:
163 configdir = os.getcwd()
164
165 configure_cmd = ""
166 while os.path.exists(configdir):
167 config_cmd = os.path.join(configdir, "configure")
168 if not os.path.exists(config_cmd):
169 parentdir = os.path.abspath(os.path.join(configdir, ".."))
170 if configdir == parentdir:
171 break
172
173 configdir = parentdir
174 else:
175 configure_cmd = config_cmd
176 break
177
178 if not configure_cmd:
179 sys.stderr.write("Could not find configure script at %r. Have you run autoconf?\n" % dir)
180 return 1
181
182 optionsStr = string.join(options, " ") if options else ""
183 command = "%s %s" % (configure_cmd, optionsStr)
184 print(command)
185 result = os.system(command)
186 #os.chdir(olddir)
187 return result
188
189
190 class MSVCBuilder(Builder):
191 def __init__(self, commandName="nmake.exe"):
192 Builder.__init__(self, commandName=commandName, formatName="msvc")
193
194 def isAvailable(self):
195 PATH = os.environ['PATH'].split(os.path.pathsep)
196 for p in PATH:
197 if os.path.exists(os.path.join(p, self.name)):
198 return True
199 return False
200
201
202 class MSVCProjectBuilder(Builder):
203 def __init__(self):
204 Builder.__init__(self, commandName="VCExpress.exe", formatName="msvcProject")
205 for key in ["VS90COMNTOOLS", "VC80COMNTOOLS", "VC71COMNTOOLS"]:
206 if os.environ.has_key(key):
207 self.programDir = os.path.join(os.environ[key], "..", "IDE")
208
209 if self.programDir == None:
210 for version in ["9.0", "8", ".NET 2003"]:
211 msvcDir = "C:\\Program Files\\Microsoft Visual Studio %s\\Common7\\IDE" % version
212 if os.path.exists(msvcDir):
213 self.programDir = msvcDir
214
215 def isAvailable(self):
216 if self.programDir:
217 path = os.path.join(self.programDir, self.name)
218 if os.path.exists(path):
219 return True
220 else:
221 # I don't have commercial versions of MSVC so I can't test this
222 name = "devenv.com"
223 path = os.path.join(self.programDir, name)
224 if os.path.exists(path):
225 self.name = "devenv.com"
226 return True
227
228 return False
229
230 builders = [GNUMakeBuilder, XcodeBuilder, AutoconfBuilder, MSVCBuilder, MSVCProjectBuilder]
231
232 def getAvailableBuilders():
233 availableBuilders = {}
234 for symbol in builders:
235 thisBuilder = symbol()
236 if thisBuilder.isAvailable():
237 availableBuilders[thisBuilder.formatName] = symbol
238
239 return availableBuilders