#!/usr/bin/env python import sys import os import platform import getopt LOG = None VERBOSE = False # standard line print def lprint(x): print x LOG.write(x + "\n") # verbose print def vprint(x=""): if VERBOSE: print x LOG.write(x + "\n") # immediate (no newline) print def iprint(x): sys.stdout.write(x) sys.stdout.flush() LOG.write(x) class IniParser: def __init__(self, file): self.__d = {} sectiondata = None for x in file.readlines(): x = x.replace("\r\n", "").replace("\n", "") xs = x.strip() if xs == "" or xs.startswith("#"): continue if x.startswith("[") and x.endswith("]"): sectiondata = {} keydata = [] self.__d[x[1:-1]] = (sectiondata, keydata) continue i = x.index("=") key = x[:i] sectiondata[key] = x[i+1:] keydata.append((key, sectiondata[key])) def has_key(self, key): return self.__d.has_key(key) def setdefault(self, key, value=None): if self.has_key(key): return self[key] return value def __getitem__(self, key): return self.__d[key][0] def keys(self, key): return self.__d[key][1] class ConfigureIniParser(IniParser): def __init__(self, file): IniParser.__init__(self, file) self.modules = {} self.buildorder = [] self.updatemodules(self.keys("modules")) self.selectlibs = {} for k, v in self.setdefault("selectlibs", {}).items(): self.selectlibs[k] = v.split() libs = self.setdefault("core", {"libs": ""})["libs"].split() libs = [(x, self["lib%s" % x]) for x in libs] for k, v in libs: v.setdefault("libname", k) v.setdefault("format", "lib%s.so") v.setdefault("headerpath", None) v.setdefault("additionaldirs", None) v.setdefault("alwayspresent", None) if v["additionaldirs"]: v["additionaldirs"] = v["additionaldirs"].split() v["libname"] = v["libname"].split() self.libs = dict(libs) self.searchincludes = self["search"]["include"].split() self.searchlibs = self["search"]["lib"].split() self.makes = {} for k, v in self.setdefault("makes", {}).items(): self.makes[k] = v self.osflags = {} if self.has_key("osvars"): for k, v in self.keys("osvars"): self.osflags.setdefault(k, []).append(v) self.subs = [("-%s-" % k, v) for k, v in self.setdefault("subs", {}).items()] self.options = self["options"] def configprint(self): vprint("--- config --------------------------------------------") for x in dir(self): if x.startswith("_"): continue v = getattr(self, x) if not isinstance(v, list) and not isinstance(v, dict): continue vprint("%-50s: %s" % (`x`, `v`)) vprint("--- config --------------------------------------------") def updatemodules(self, x, workspace = None): for k, v in x: if workspace and workspace != ".": name = workspace + "/" + k else: name = k self.buildorder.append(name) self.modules[name] = v.split() class MultiConfigureIniParser(ConfigureIniParser): def __init__(self, files): ConfigureIniParser.__init__(self, files[0][1]) for workspace, file in files[1:]: c2 = IniParser(file) if c2.has_key("modules"): self.updatemodules(c2.keys("modules"), workspace) if c2.has_key("search"): if c2["search"].has_key("include"): self.searchincludes = self.searchincludes + c2["search"]["include"].split() if c2["search"].has_key("lib"): self.searchlibs = self.searchlibs + c2["search"]["lib"].split() if c2.has_key("options"): self.options.update(c2["options"]) if c2.has_key("osvars"): for k, v in c2.keys("osvars"): self.osflags.setdefault(k, []).append(v) def librarycheck(libraries, includes, libs): def findlibrarypaths(library, x, includes, libs): if x["alwayspresent"]: return True def locate(needle, haystack): vprint() vprint("searching for %s in: %s" % (needle, haystack)) for x in haystack: p = os.path.join(x, needle) if os.path.exists(p): return x found = [] def mergepaths(a, b): ret = list(a[:]) for x in a: for y in b: ret.append(os.path.join(x, y)) return ret libname = x["libname"] searchdir = mergepaths(includes, libname) incpath = locate(x["include"], searchdir) if not incpath: return if x["headerpath"]: incpath = os.path.abspath(os.path.join(incpath, x["headerpath"])) searchdir = mergepaths(libs, libname) if x["additionaldirs"]: searchdir = mergepaths(searchdir, [""] + x["additionaldirs"]) for l in x.has_key("soname") and [x["soname"]] or libname: libpath = locate(x["format"] % l, searchdir) if libpath: return libpath, l, incpath libsfound = [] output = [] for k in libraries.keys(): iprint("checking for %s... " % k) ret = findlibrarypaths(k, libraries[k], includes, libs) if not ret: lprint("failed") continue libsfound.append(k) if ret is not True: libpath, libname, incpath = ret uk = k.upper() x = libraries[k] libline = "LIB%s=-L%s -l%s" % (uk, libpath, libname) incline = "INC%s=-I%s" % (uk, incpath) output.append(libline) output.append(incline) lprint("ok") if ret is not True: vprint("library path: %s" % libline) vprint("include path: %s" % incline) return output, libsfound def systemcheck(makes, osflags): output = [] iprint("checking for system... ") system = platform.system() lprint(system) iprint("checking for make version... ") make = makes.setdefault(system, "gmake") lprint(make) for v in osflags.setdefault(system, []): output.append(v) return output, make def modulecheck(modules, libsfound, buildorder, selectlibs, overrides): defaultselections = {} for k, v in selectlibs.items(): if overrides.has_key(k): assert overrides[k] in libsfound libsfound.append(k) defaultselections[k] = overrides[k] else: for x in v: if x in libsfound: libsfound.append(k) defaultselections[k] = x break building = set() for k, v in modules.items(): for x in v: if x not in libsfound: break else: building.add(k) notfound = set(filter(lambda x: not os.path.exists(x), building)) cantbuild = set(modules) - building building = building - notfound orderedbuild = [] for x in buildorder: if x in building: orderedbuild.append(x) build = ["DIRS=%s" % (" ".join(orderedbuild))] return build, orderedbuild, notfound, cantbuild, defaultselections def writemakefile(inc, out, appendstart=None, appendend=None, silent=False): p = open(out, "w") p.write("## AUTOMATICALLY GENERATED -- EDIT %s INSTEAD\n\n" % inc) if appendstart: p.write("\n".join(appendstart)) p.write("\n") f = open(inc, "r") try: for l in f.readlines(): p.write(l) finally: f.close() if appendend: p.write("\n".join(appendend)) p.write("\n") p.close() if not silent: lprint("configure: wrote %s" % out) def writeconfigh(file, modules, defaultselections): f = open(file, "w") f.write("/* AUTOMATICALLY GENERATED -- DO NOT EDIT */\n") for x in modules: f.write("#define HAVE_%s\n" % x.upper()) for k, v in defaultselections.items(): f.write("#define USE_%s_%s\n" % (k.upper(), v.upper())) f.close() lprint("configure: wrote %s" % file) def configure(config, selectoverrides, workspaces): # figure out make and any custom OS flags flags, make = systemcheck(config.makes, config.osflags) # find the libraries/includes we have and their paths f, libsfound = librarycheck(config.libs, config.searchincludes, config.searchlibs) for k, v in selectoverrides.items(): if not v in libsfound: lprint("configure: can't set %s to %s as %s was not found." % (k, v, v)) return flags = flags + f # see which modules we can build buildlines, building, notfound, cantbuild, defaultselections = modulecheck(config.modules, libsfound, config.buildorder, config.selectlibs, selectoverrides) for k, v in defaultselections.items(): lprint("configure: selected %s as %s" % (v, k)) flags.append("LIB%s=$(LIB%s)" % (k.upper(), v.upper())) flags.append("INC%s=$(INC%s)" % (k.upper(), v.upper())) writemakefile("build.mk.in", "build.mk", appendend=flags + ["=".join(x) for x in config.options.items()] + ["DIRS=" + " ".join(building), "WORKSPACES=" + " ".join(workspaces)]) writeconfigh("config.h", libsfound, defaultselections) lprint("configure: selected: %s" % " ".join(building)) if len(notfound) > 0: lprint("configure: couldn't find: %s" % " ".join(notfound)) if len(cantbuild) > 0: lprint("configure: can't select: %s" % " ".join(cantbuild)) def usage(): print print " Usage: %s [-h] [-v] [options]" % sys.argv[0] print print " Additional options are:" for k, v in validopts.items(): print " --with-%s=[%s]" % (v[0], "|".join(v[1])) print " -L [additional lib dir]" print " -I [additional include dir]" print " -m [additional module]" print " -v: verbose" def main(): global LOG, VERBOSE files, workspaces = [], [] for root, _, file_list in os.walk("."): if "configure.ini" not in file_list: continue print "found workspace: %s" % root workspaces.append(root) path = os.path.join(root, "configure.ini") files.append( (root, open(path, "r")) ) local_path = os.path.join(root, "configure.ini.local") if os.path.exists(local_path): files.append( (root, open(local_path, "r")) ) config = MultiConfigureIniParser(files) mopts = [] validopts = {} for k, v in config.selectlibs.items(): mopts.append("with-%s=" % k) validopts["--with-%s" % k] = (k, v) try: opts, args = getopt.getopt(sys.argv[1:], "hvcI:L:m:", mopts) except getopt.GetoptError, err: print str(err) usage() return overrides = {} libs = [] includes = [] modules = [] for o, a in opts: if validopts.has_key(o): v = validopts[o] if not a in v[1]: usage() return overrides[v[0]] = a elif o == "-h": usage() return elif o == "-v": VERBOSE = True elif o == "-L": libs.append(a) elif o == "-I": includes.append(a) elif o == "-m": modules.append(a) else: assert False, "bad option" LOG = open(".configure.log", "w") vprint("invoked as: %r" % sys.argv) config.updatemodules([(x, "") for x in modules]) config.searchlibs.extend(libs) config.searchincludes.extend(includes) config.configprint() configure(config, overrides, workspaces) if __name__ == "__main__": main()