]>
Commit | Line | Data |
---|---|---|
d5713c3b Q |
1 | #!/usr/bin/env python |
2 | ||
3 | import sys | |
4 | import os | |
5 | import platform | |
6 | import getopt | |
7 | ||
8 | LOG = None | |
9 | VERBOSE = False | |
10 | ||
11 | # standard line print | |
12 | def lprint(x): | |
13 | print x | |
14 | LOG.write(x + "\n") | |
15 | ||
16 | # verbose print | |
17 | def vprint(x=""): | |
18 | if VERBOSE: | |
19 | print x | |
20 | LOG.write(x + "\n") | |
21 | ||
22 | # immediate (no newline) print | |
23 | def iprint(x): | |
24 | sys.stdout.write(x) | |
25 | sys.stdout.flush() | |
26 | LOG.write(x) | |
27 | ||
28 | class IniParser: | |
29 | def __init__(self, file): | |
30 | self.__d = {} | |
31 | sectiondata = None | |
32 | for x in file.readlines(): | |
33 | x = x.replace("\r\n", "").replace("\n", "") | |
34 | xs = x.strip() | |
35 | if xs == "" or xs.startswith("#"): | |
36 | continue | |
37 | ||
38 | if x.startswith("[") and x.endswith("]"): | |
39 | sectiondata = {} | |
40 | keydata = [] | |
41 | self.__d[x[1:-1]] = (sectiondata, keydata) | |
42 | continue | |
43 | ||
44 | i = x.index("=") | |
45 | key = x[:i] | |
46 | sectiondata[key] = x[i+1:] | |
47 | keydata.append((key, sectiondata[key])) | |
48 | ||
49 | def has_key(self, key): | |
50 | return self.__d.has_key(key) | |
51 | ||
52 | def setdefault(self, key, value=None): | |
53 | if self.has_key(key): | |
54 | return self[key] | |
55 | return value | |
56 | ||
57 | def __getitem__(self, key): | |
58 | return self.__d[key][0] | |
59 | ||
60 | def keys(self, key): | |
61 | return self.__d[key][1] | |
62 | ||
63 | class ConfigureIniParser(IniParser): | |
64 | def __init__(self, file): | |
65 | IniParser.__init__(self, file) | |
66 | ||
67 | self.modules = {} | |
68 | self.buildorder = [] | |
69 | self.updatemodules(self.keys("modules")) | |
70 | ||
71 | self.selectlibs = {} | |
72 | for k, v in self.setdefault("selectlibs", {}).items(): | |
73 | self.selectlibs[k] = v.split() | |
74 | ||
75 | libs = self.setdefault("core", {"libs": ""})["libs"].split() | |
76 | libs = [(x, self["lib%s" % x]) for x in libs] | |
77 | for k, v in libs: | |
78 | v.setdefault("libname", k) | |
79 | v.setdefault("format", "lib%s.so") | |
80 | v.setdefault("headerpath", None) | |
81 | v.setdefault("additionaldirs", None) | |
82 | v.setdefault("alwayspresent", None) | |
83 | ||
84 | if v["additionaldirs"]: | |
85 | v["additionaldirs"] = v["additionaldirs"].split() | |
86 | v["libname"] = v["libname"].split() | |
87 | ||
88 | self.libs = dict(libs) | |
89 | self.searchincludes = self["search"]["include"].split() | |
90 | self.searchlibs = self["search"]["lib"].split() | |
91 | self.makes = {} | |
92 | for k, v in self.setdefault("makes", {}).items(): | |
93 | self.makes[k] = v | |
94 | ||
95 | self.osflags = {} | |
96 | if self.has_key("osvars"): | |
97 | for k, v in self.keys("osvars"): | |
98 | self.osflags.setdefault(k, []).append(v) | |
99 | ||
100 | self.subs = [("-%s-" % k, v) for k, v in self.setdefault("subs", {}).items()] | |
101 | self.options = self["options"] | |
102 | ||
103 | def configprint(self): | |
104 | vprint("--- config --------------------------------------------") | |
105 | for x in dir(self): | |
106 | if x.startswith("_"): | |
107 | continue | |
108 | v = getattr(self, x) | |
109 | if not isinstance(v, list) and not isinstance(v, dict): | |
110 | continue | |
111 | vprint("%-50s: %s" % (`x`, `v`)) | |
112 | vprint("--- config --------------------------------------------") | |
113 | ||
114 | def updatemodules(self, x, workspace = None): | |
115 | for k, v in x: | |
116 | if workspace and workspace != ".": | |
117 | name = workspace + "/" + k | |
118 | else: | |
119 | name = k | |
120 | self.buildorder.append(name) | |
121 | self.modules[name] = v.split() | |
122 | ||
123 | class MultiConfigureIniParser(ConfigureIniParser): | |
124 | def __init__(self, files): | |
125 | ConfigureIniParser.__init__(self, files[0][1]) | |
126 | ||
127 | for workspace, file in files[1:]: | |
128 | c2 = IniParser(file) | |
129 | if c2.has_key("modules"): | |
130 | self.updatemodules(c2.keys("modules"), workspace) | |
131 | ||
132 | if c2.has_key("search"): | |
133 | if c2["search"].has_key("include"): | |
134 | self.searchincludes = self.searchincludes + c2["search"]["include"].split() | |
135 | if c2["search"].has_key("lib"): | |
136 | self.searchlibs = self.searchlibs + c2["search"]["lib"].split() | |
137 | ||
138 | if c2.has_key("options"): | |
139 | self.options.update(c2["options"]) | |
140 | ||
141 | def librarycheck(libraries, includes, libs): | |
142 | def findlibrarypaths(library, x, includes, libs): | |
143 | if x["alwayspresent"]: | |
144 | return True | |
145 | def locate(needle, haystack): | |
146 | vprint() | |
147 | vprint("searching for %s in: %s" % (needle, haystack)) | |
148 | ||
149 | for x in haystack: | |
150 | p = os.path.join(x, needle) | |
151 | if os.path.exists(p): | |
152 | return x | |
153 | ||
154 | found = [] | |
155 | ||
156 | def mergepaths(a, b): | |
157 | ret = list(a[:]) | |
158 | for x in a: | |
159 | for y in b: | |
160 | ret.append(os.path.join(x, y)) | |
161 | return ret | |
162 | ||
163 | libname = x["libname"] | |
164 | ||
165 | searchdir = mergepaths(includes, libname) | |
166 | incpath = locate(x["include"], searchdir) | |
167 | if not incpath: | |
168 | return | |
169 | ||
170 | if x["headerpath"]: | |
171 | incpath = os.path.abspath(os.path.join(incpath, x["headerpath"])) | |
172 | ||
173 | searchdir = mergepaths(libs, libname) | |
174 | if x["additionaldirs"]: | |
175 | searchdir = mergepaths(searchdir, [""] + x["additionaldirs"]) | |
176 | ||
177 | for l in x.has_key("soname") and [x["soname"]] or libname: | |
178 | libpath = locate(x["format"] % l, searchdir) | |
179 | if libpath: | |
180 | return libpath, l, incpath | |
181 | ||
182 | libsfound = [] | |
183 | output = [] | |
184 | ||
185 | for k in libraries.keys(): | |
186 | iprint("checking for %s... " % k) | |
187 | ret = findlibrarypaths(k, libraries[k], includes, libs) | |
188 | if not ret: | |
189 | lprint("failed") | |
190 | continue | |
191 | ||
192 | libsfound.append(k) | |
193 | ||
194 | if ret is not True: | |
195 | libpath, libname, incpath = ret | |
196 | uk = k.upper() | |
197 | ||
198 | x = libraries[k] | |
199 | libline = "LIB%s=-L%s -l%s" % (uk, libpath, libname) | |
200 | incline = "INC%s=-I%s" % (uk, incpath) | |
201 | output.append(libline) | |
202 | output.append(incline) | |
203 | ||
204 | lprint("ok") | |
205 | if ret is not True: | |
206 | vprint("library path: %s" % libline) | |
207 | vprint("include path: %s" % incline) | |
208 | ||
209 | return output, libsfound | |
210 | ||
211 | def systemcheck(makes, osflags): | |
212 | output = [] | |
213 | ||
214 | iprint("checking for system... ") | |
215 | system = platform.system() | |
216 | lprint(system) | |
217 | ||
218 | iprint("checking for make version... ") | |
219 | make = makes.setdefault(system, "gmake") | |
220 | lprint(make) | |
221 | ||
222 | for v in osflags.setdefault(system, []): | |
223 | output.append(v) | |
224 | return output, make | |
225 | ||
226 | def modulecheck(modules, libsfound, buildorder, selectlibs, overrides): | |
227 | defaultselections = {} | |
228 | ||
229 | for k, v in selectlibs.items(): | |
230 | if overrides.has_key(k): | |
231 | assert overrides[k] in libsfound | |
232 | libsfound.append(k) | |
233 | defaultselections[k] = overrides[k] | |
234 | else: | |
235 | for x in v: | |
236 | if x in libsfound: | |
237 | libsfound.append(k) | |
238 | defaultselections[k] = x | |
239 | break | |
240 | ||
241 | building = set() | |
242 | for k, v in modules.items(): | |
243 | for x in v: | |
244 | if x not in libsfound: | |
245 | break | |
246 | else: | |
247 | building.add(k) | |
248 | ||
249 | notfound = set(filter(lambda x: not os.path.exists(x), building)) | |
250 | ||
251 | cantbuild = set(modules) - building | |
252 | building = building - notfound | |
253 | ||
254 | orderedbuild = [] | |
255 | for x in buildorder: | |
256 | if x in building: | |
257 | orderedbuild.append(x) | |
258 | ||
259 | build = ["DIRS=%s" % (" ".join(orderedbuild))] | |
260 | return build, orderedbuild, notfound, cantbuild, defaultselections | |
261 | ||
262 | def writemakefile(inc, out, appendstart=None, appendend=None, silent=False): | |
263 | p = open(out, "w") | |
264 | p.write("## AUTOMATICALLY GENERATED -- EDIT %s INSTEAD\n\n" % inc) | |
265 | if appendstart: | |
266 | p.write("\n".join(appendstart)) | |
267 | p.write("\n") | |
268 | ||
269 | f = open(inc, "r") | |
270 | try: | |
271 | for l in f.readlines(): | |
272 | p.write(l) | |
273 | finally: | |
274 | f.close() | |
275 | ||
276 | if appendend: | |
277 | p.write("\n".join(appendend)) | |
278 | p.write("\n") | |
279 | ||
280 | p.close() | |
281 | if not silent: | |
282 | lprint("configure: wrote %s" % out) | |
283 | ||
284 | def writeconfigh(file, modules, defaultselections): | |
285 | f = open(file, "w") | |
286 | f.write("/* AUTOMATICALLY GENERATED -- DO NOT EDIT */\n") | |
287 | ||
288 | for x in modules: | |
289 | f.write("#define HAVE_%s\n" % x.upper()) | |
290 | for k, v in defaultselections.items(): | |
291 | f.write("#define USE_%s_%s\n" % (k.upper(), v.upper())) | |
292 | f.close() | |
293 | ||
294 | lprint("configure: wrote %s" % file) | |
295 | ||
296 | def configure(config, selectoverrides, workspaces): | |
297 | # figure out make and any custom OS flags | |
298 | flags, make = systemcheck(config.makes, config.osflags) | |
299 | ||
300 | # find the libraries/includes we have and their paths | |
301 | f, libsfound = librarycheck(config.libs, config.searchincludes, config.searchlibs) | |
302 | for k, v in selectoverrides.items(): | |
303 | if not v in libsfound: | |
304 | lprint("configure: can't set %s to %s as %s was not found." % (k, v, v)) | |
305 | return | |
306 | ||
307 | flags = flags + f | |
308 | ||
309 | # see which modules we can build | |
310 | buildlines, building, notfound, cantbuild, defaultselections = modulecheck(config.modules, libsfound, config.buildorder, config.selectlibs, selectoverrides) | |
311 | ||
312 | for k, v in defaultselections.items(): | |
313 | lprint("configure: selected %s as %s" % (v, k)) | |
314 | flags.append("LIB%s=$(LIB%s)" % (k.upper(), v.upper())) | |
315 | flags.append("INC%s=$(INC%s)" % (k.upper(), v.upper())) | |
316 | ||
317 | writemakefile("build.mk.in", "build.mk", appendend=flags + ["=".join(x) for x in config.options.items()] + ["DIRS=" + " ".join(building), "WORKSPACES=" + " ".join(workspaces)]) | |
318 | ||
319 | writeconfigh("config.h", libsfound, defaultselections) | |
320 | ||
321 | lprint("configure: selected: %s" % " ".join(building)) | |
322 | if len(notfound) > 0: | |
323 | lprint("configure: couldn't find: %s" % " ".join(notfound)) | |
324 | ||
325 | if len(cantbuild) > 0: | |
326 | lprint("configure: can't select: %s" % " ".join(cantbuild)) | |
327 | ||
328 | def usage(): | |
329 | ||
330 | print " Usage: %s [-h] [-v] [options]" % sys.argv[0] | |
331 | ||
332 | print " Additional options are:" | |
333 | for k, v in validopts.items(): | |
334 | print " --with-%s=[%s]" % (v[0], "|".join(v[1])) | |
335 | ||
336 | print " -L [additional lib dir]" | |
337 | print " -I [additional include dir]" | |
338 | print " -m [additional module]" | |
339 | print " -v: verbose" | |
340 | ||
341 | def main(workspacesfile): | |
342 | global LOG, VERBOSE | |
343 | ||
344 | workspacesconfig = IniParser(open(workspacesfile, "r")) | |
345 | ||
346 | files = [] | |
347 | workspaces = [] | |
348 | ||
349 | for workspace in ["."] + workspacesconfig["workspaces"].keys(): | |
350 | path = workspace + "/configure.ini" | |
351 | if os.path.exists(path): | |
352 | print "found workspace: %s" % workspace | |
353 | workspaces.append(workspace) | |
354 | files.append( (workspace, open(path, "r")) ) | |
355 | ||
356 | local_path = workspace + "/configure.ini.local" | |
357 | if os.path.exists(local_path): | |
358 | files.append( (workspace, open(local_path, "r")) ) | |
359 | ||
360 | config = MultiConfigureIniParser(files) | |
361 | ||
362 | mopts = [] | |
363 | validopts = {} | |
364 | for k, v in config.selectlibs.items(): | |
365 | mopts.append("with-%s=" % k) | |
366 | validopts["--with-%s" % k] = (k, v) | |
367 | ||
368 | try: | |
369 | opts, args = getopt.getopt(sys.argv[1:], "hvcI:L:m:", mopts) | |
370 | except getopt.GetoptError, err: | |
371 | print str(err) | |
372 | usage() | |
373 | return | |
374 | ||
375 | overrides = {} | |
376 | libs = [] | |
377 | includes = [] | |
378 | modules = [] | |
379 | ||
380 | for o, a in opts: | |
381 | if validopts.has_key(o): | |
382 | v = validopts[o] | |
383 | if not a in v[1]: | |
384 | usage() | |
385 | return | |
386 | overrides[v[0]] = a | |
387 | elif o == "-h": | |
388 | usage() | |
389 | return | |
390 | elif o == "-v": | |
391 | VERBOSE = True | |
392 | elif o == "-L": | |
393 | libs.append(a) | |
394 | elif o == "-I": | |
395 | includes.append(a) | |
396 | elif o == "-m": | |
397 | modules.append(a) | |
398 | else: | |
399 | assert False, "bad option" | |
400 | ||
401 | LOG = open(".configure.log", "w") | |
402 | vprint("invoked as: %r" % sys.argv) | |
403 | config.updatemodules([(x, "") for x in modules]) | |
404 | config.searchlibs.extend(libs) | |
405 | config.searchincludes.extend(includes) | |
406 | config.configprint() | |
407 | ||
408 | configure(config, overrides, workspaces) | |
409 | ||
410 | if __name__ == "__main__": | |
411 | main("workspaces.ini") |