]>
Commit | Line | Data |
---|---|---|
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 | if c2.has_key("osvars"): | |
142 | for k, v in c2.keys("osvars"): | |
143 | self.osflags.setdefault(k, []).append(v) | |
144 | ||
145 | def librarycheck(libraries, includes, libs): | |
146 | def findlibrarypaths(library, x, includes, libs): | |
147 | if x["alwayspresent"]: | |
148 | return True | |
149 | def locate(needle, haystack): | |
150 | vprint() | |
151 | vprint("searching for %s in: %s" % (needle, haystack)) | |
152 | ||
153 | for x in haystack: | |
154 | p = os.path.join(x, needle) | |
155 | if os.path.exists(p): | |
156 | return x | |
157 | ||
158 | found = [] | |
159 | ||
160 | def mergepaths(a, b): | |
161 | ret = list(a[:]) | |
162 | for x in a: | |
163 | for y in b: | |
164 | ret.append(os.path.join(x, y)) | |
165 | return ret | |
166 | ||
167 | libname = x["libname"] | |
168 | ||
169 | searchdir = mergepaths(includes, libname) | |
170 | incpath = locate(x["include"], searchdir) | |
171 | if not incpath: | |
172 | return | |
173 | ||
174 | if x["headerpath"]: | |
175 | incpath = os.path.abspath(os.path.join(incpath, x["headerpath"])) | |
176 | ||
177 | searchdir = mergepaths(libs, libname) | |
178 | if x["additionaldirs"]: | |
179 | searchdir = mergepaths(searchdir, [""] + x["additionaldirs"]) | |
180 | ||
181 | for l in x.has_key("soname") and [x["soname"]] or libname: | |
182 | libpath = locate(x["format"] % l, searchdir) | |
183 | if libpath: | |
184 | return libpath, l, incpath | |
185 | ||
186 | libsfound = [] | |
187 | output = [] | |
188 | ||
189 | for k in libraries.keys(): | |
190 | iprint("checking for %s... " % k) | |
191 | ret = findlibrarypaths(k, libraries[k], includes, libs) | |
192 | if not ret: | |
193 | lprint("failed") | |
194 | continue | |
195 | ||
196 | libsfound.append(k) | |
197 | ||
198 | if ret is not True: | |
199 | libpath, libname, incpath = ret | |
200 | uk = k.upper() | |
201 | ||
202 | x = libraries[k] | |
203 | libline = "LIB%s=-L%s -l%s" % (uk, libpath, libname) | |
204 | incline = "INC%s=-I%s" % (uk, incpath) | |
205 | output.append(libline) | |
206 | output.append(incline) | |
207 | ||
208 | lprint("ok") | |
209 | if ret is not True: | |
210 | vprint("library path: %s" % libline) | |
211 | vprint("include path: %s" % incline) | |
212 | ||
213 | return output, libsfound | |
214 | ||
215 | def systemcheck(makes, osflags): | |
216 | output = [] | |
217 | ||
218 | iprint("checking for system... ") | |
219 | system = platform.system() | |
220 | lprint(system) | |
221 | ||
222 | iprint("checking for make version... ") | |
223 | make = makes.setdefault(system, "gmake") | |
224 | lprint(make) | |
225 | ||
226 | for v in osflags.setdefault(system, []): | |
227 | output.append(v) | |
228 | return output, make | |
229 | ||
230 | def modulecheck(modules, libsfound, buildorder, selectlibs, overrides): | |
231 | defaultselections = {} | |
232 | ||
233 | for k, v in selectlibs.items(): | |
234 | if overrides.has_key(k): | |
235 | assert overrides[k] in libsfound | |
236 | libsfound.append(k) | |
237 | defaultselections[k] = overrides[k] | |
238 | else: | |
239 | for x in v: | |
240 | if x in libsfound: | |
241 | libsfound.append(k) | |
242 | defaultselections[k] = x | |
243 | break | |
244 | ||
245 | building = set() | |
246 | for k, v in modules.items(): | |
247 | for x in v: | |
248 | if x not in libsfound: | |
249 | break | |
250 | else: | |
251 | building.add(k) | |
252 | ||
253 | notfound = set(filter(lambda x: not os.path.exists(x), building)) | |
254 | ||
255 | cantbuild = set(modules) - building | |
256 | building = building - notfound | |
257 | ||
258 | orderedbuild = [] | |
259 | for x in buildorder: | |
260 | if x in building: | |
261 | orderedbuild.append(x) | |
262 | ||
263 | build = ["DIRS=%s" % (" ".join(orderedbuild))] | |
264 | return build, orderedbuild, notfound, cantbuild, defaultselections | |
265 | ||
266 | def writemakefile(inc, out, appendstart=None, appendend=None, silent=False): | |
267 | p = open(out, "w") | |
268 | p.write("## AUTOMATICALLY GENERATED -- EDIT %s INSTEAD\n\n" % inc) | |
269 | if appendstart: | |
270 | p.write("\n".join(appendstart)) | |
271 | p.write("\n") | |
272 | ||
273 | f = open(inc, "r") | |
274 | try: | |
275 | for l in f.readlines(): | |
276 | p.write(l) | |
277 | finally: | |
278 | f.close() | |
279 | ||
280 | if appendend: | |
281 | p.write("\n".join(appendend)) | |
282 | p.write("\n") | |
283 | ||
284 | p.close() | |
285 | if not silent: | |
286 | lprint("configure: wrote %s" % out) | |
287 | ||
288 | def writeconfigh(file, modules, defaultselections): | |
289 | f = open(file, "w") | |
290 | f.write("/* AUTOMATICALLY GENERATED -- DO NOT EDIT */\n") | |
291 | ||
292 | for x in modules: | |
293 | f.write("#define HAVE_%s\n" % x.upper()) | |
294 | for k, v in defaultselections.items(): | |
295 | f.write("#define USE_%s_%s\n" % (k.upper(), v.upper())) | |
296 | f.close() | |
297 | ||
298 | lprint("configure: wrote %s" % file) | |
299 | ||
300 | def configure(config, selectoverrides, workspaces): | |
301 | # figure out make and any custom OS flags | |
302 | flags, make = systemcheck(config.makes, config.osflags) | |
303 | ||
304 | # find the libraries/includes we have and their paths | |
305 | f, libsfound = librarycheck(config.libs, config.searchincludes, config.searchlibs) | |
306 | for k, v in selectoverrides.items(): | |
307 | if not v in libsfound: | |
308 | lprint("configure: can't set %s to %s as %s was not found." % (k, v, v)) | |
309 | return | |
310 | ||
311 | flags = flags + f | |
312 | ||
313 | # see which modules we can build | |
314 | buildlines, building, notfound, cantbuild, defaultselections = modulecheck(config.modules, libsfound, config.buildorder, config.selectlibs, selectoverrides) | |
315 | ||
316 | for k, v in defaultselections.items(): | |
317 | lprint("configure: selected %s as %s" % (v, k)) | |
318 | flags.append("LIB%s=$(LIB%s)" % (k.upper(), v.upper())) | |
319 | flags.append("INC%s=$(INC%s)" % (k.upper(), v.upper())) | |
320 | ||
321 | writemakefile("build.mk.in", "build.mk", appendend=flags + ["=".join(x) for x in config.options.items()] + ["DIRS=" + " ".join(building), "WORKSPACES=" + " ".join(workspaces)]) | |
322 | ||
323 | writeconfigh("config.h", libsfound, defaultselections) | |
324 | ||
325 | lprint("configure: selected: %s" % " ".join(building)) | |
326 | if len(notfound) > 0: | |
327 | lprint("configure: couldn't find: %s" % " ".join(notfound)) | |
328 | ||
329 | if len(cantbuild) > 0: | |
330 | lprint("configure: can't select: %s" % " ".join(cantbuild)) | |
331 | ||
332 | def usage(): | |
333 | ||
334 | print " Usage: %s [-h] [-v] [options]" % sys.argv[0] | |
335 | ||
336 | print " Additional options are:" | |
337 | for k, v in validopts.items(): | |
338 | print " --with-%s=[%s]" % (v[0], "|".join(v[1])) | |
339 | ||
340 | print " -L [additional lib dir]" | |
341 | print " -I [additional include dir]" | |
342 | print " -m [additional module]" | |
343 | print " -v: verbose" | |
344 | ||
345 | def main(workspacesfile): | |
346 | global LOG, VERBOSE | |
347 | ||
348 | workspacesconfig = IniParser(open(workspacesfile, "r")) | |
349 | ||
350 | files = [] | |
351 | workspaces = [] | |
352 | ||
353 | for workspace in ["."] + workspacesconfig["workspaces"].keys(): | |
354 | path = workspace + "/configure.ini" | |
355 | if os.path.exists(path): | |
356 | print "found workspace: %s" % workspace | |
357 | workspaces.append(workspace) | |
358 | files.append( (workspace, open(path, "r")) ) | |
359 | ||
360 | local_path = workspace + "/configure.ini.local" | |
361 | if os.path.exists(local_path): | |
362 | files.append( (workspace, open(local_path, "r")) ) | |
363 | ||
364 | config = MultiConfigureIniParser(files) | |
365 | ||
366 | mopts = [] | |
367 | validopts = {} | |
368 | for k, v in config.selectlibs.items(): | |
369 | mopts.append("with-%s=" % k) | |
370 | validopts["--with-%s" % k] = (k, v) | |
371 | ||
372 | try: | |
373 | opts, args = getopt.getopt(sys.argv[1:], "hvcI:L:m:", mopts) | |
374 | except getopt.GetoptError, err: | |
375 | print str(err) | |
376 | usage() | |
377 | return | |
378 | ||
379 | overrides = {} | |
380 | libs = [] | |
381 | includes = [] | |
382 | modules = [] | |
383 | ||
384 | for o, a in opts: | |
385 | if validopts.has_key(o): | |
386 | v = validopts[o] | |
387 | if not a in v[1]: | |
388 | usage() | |
389 | return | |
390 | overrides[v[0]] = a | |
391 | elif o == "-h": | |
392 | usage() | |
393 | return | |
394 | elif o == "-v": | |
395 | VERBOSE = True | |
396 | elif o == "-L": | |
397 | libs.append(a) | |
398 | elif o == "-I": | |
399 | includes.append(a) | |
400 | elif o == "-m": | |
401 | modules.append(a) | |
402 | else: | |
403 | assert False, "bad option" | |
404 | ||
405 | LOG = open(".configure.log", "w") | |
406 | vprint("invoked as: %r" % sys.argv) | |
407 | config.updatemodules([(x, "") for x in modules]) | |
408 | config.searchlibs.extend(libs) | |
409 | config.searchincludes.extend(includes) | |
410 | config.configprint() | |
411 | ||
412 | configure(config, overrides, workspaces) | |
413 | ||
414 | if __name__ == "__main__": | |
415 | main("workspaces.ini") |