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