| OLD | NEW |
| 1 # | 1 # |
| 2 # gen_base.py -- infrastructure for generating makefiles, dependencies, etc. | 2 # gen_base.py -- infrastructure for generating makefiles, dependencies, etc. |
| 3 # | 3 # |
| 4 | 4 |
| 5 import os | 5 import os |
| 6 import sys | 6 import sys |
| 7 import string | 7 import string |
| 8 import glob | 8 import glob |
| 9 import re | 9 import re |
| 10 import fileinput | 10 import fileinput |
| 11 import ConfigParser | 11 import ConfigParser |
| 12 import generator.swig | 12 import generator.swig |
| 13 | 13 |
| 14 import getversion | 14 import getversion |
| 15 | 15 |
| 16 | 16 |
| 17 def _warning(msg): | 17 def _warning(msg): |
| 18 sys.stderr.write("WARNING: %s\n" % msg) | 18 sys.stderr.write("WARNING: %s\n" % msg) |
| 19 | 19 |
| 20 def _error(msg): | 20 def _error(msg): |
| 21 sys.stderr.write("ERROR: %s\n" % msg) | 21 sys.stderr.write("ERROR: %s\n" % msg) |
| 22 sys.exit(1) | 22 sys.exit(1) |
| 23 | 23 |
| 24 class GeneratorBase: | 24 class GeneratorBase: |
| 25 | 25 |
| 26 # | 26 # |
| 27 # Derived classes should define a class attribute named _extension_map. | 27 # Derived classes should define a class attribute named _extension_map. |
| 28 # This attribute should be a dictionary of the form: | 28 # This attribute should be a dictionary of the form: |
| 29 # { (target-type, file-type): file-extension ...} | 29 # { (target-type, file-type): file-extension ...} |
| 30 # | 30 # |
| 31 # where: target-type is 'exe', 'lib', ... | 31 # where: target-type is 'exe', 'lib', ... |
| 32 # file-type is 'target', 'object', ... | 32 # file-type is 'target', 'object', ... |
| 33 # | 33 # |
| 34 | 34 |
| 35 def __init__(self, fname, verfname, options=None): | 35 def __init__(self, fname, verfname, options=None): |
| 36 # Retrieve major version from the C header, to avoid duplicating it in | 36 # Retrieve major version from the C header, to avoid duplicating it in |
| 37 # build.conf - it is required because some file names include it. | 37 # build.conf - it is required because some file names include it. |
| 38 try: | 38 try: |
| 39 vsn_parser = getversion.Parser() | 39 vsn_parser = getversion.Parser() |
| 40 vsn_parser.search('SVN_VER_MAJOR', 'libver') | 40 vsn_parser.search('SVN_VER_MAJOR', 'libver') |
| 41 self.version = vsn_parser.parse(verfname).libver | 41 self.version = vsn_parser.parse(verfname).libver |
| 42 except: | 42 except: |
| 43 raise GenError('Unable to extract version.') | 43 raise GenError('Unable to extract version.') |
| 44 | 44 |
| 45 # Read options | 45 # Read options |
| 46 self.release_mode = None | 46 self.release_mode = None |
| 47 for opt, val in options: | 47 for opt, val in options: |
| 48 if opt == '--release': | 48 if opt == '--release': |
| 49 self.release_mode = 1 | 49 self.release_mode = 1 |
| 50 | 50 |
| (...skipping 255 matching lines...) Show 10 above Show 10 below |
| 306 "A build target is a node in our dependency graph." | 306 "A build target is a node in our dependency graph." |
| 307 | 307 |
| 308 def __init__(self, name, options, gen_obj): | 308 def __init__(self, name, options, gen_obj): |
| 309 self.name = name | 309 self.name = name |
| 310 self.gen_obj = gen_obj | 310 self.gen_obj = gen_obj |
| 311 self.desc = options.get('description') | 311 self.desc = options.get('description') |
| 312 self.path = options.get('path', '') | 312 self.path = options.get('path', '') |
| 313 self.add_deps = options.get('add-deps', '') | 313 self.add_deps = options.get('add-deps', '') |
| 314 self.add_install_deps = options.get('add-install-deps', '') | 314 self.add_install_deps = options.get('add-install-deps', '') |
| 315 self.msvc_name = options.get('msvc-name') # override project name | 315 self.msvc_name = options.get('msvc-name') # override project name |
| 316 | 316 |
| 317 def add_dependencies(self): | 317 def add_dependencies(self): |
| 318 # subclasses should override to provide behavior, as appropriate | 318 # subclasses should override to provide behavior, as appropriate |
| 319 raise NotImplementedError | 319 raise NotImplementedError |
| 320 | 320 |
| 321 class Section: | 321 class Section: |
| 322 """Represents an individual section of build.conf | 322 """Represents an individual section of build.conf |
| 323 | 323 |
| 324 The Section class is sort of a factory class which is responsible for | 324 The Section class is sort of a factory class which is responsible for |
| 325 creating and keeping track of Target instances associated with a section | 325 creating and keeping track of Target instances associated with a section |
| 326 of the configuration file. By default it only allows one Target per | 326 of the configuration file. By default it only allows one Target per |
| 327 section, but subclasses may create multiple Targets. | 327 section, but subclasses may create multiple Targets. |
| 328 """ | 328 """ |
| 329 | 329 |
| 330 def __init__(self, target_class, name, options, gen_obj): | 330 def __init__(self, target_class, name, options, gen_obj): |
| 331 self.target_class = target_class | 331 self.target_class = target_class |
| 332 self.name = name | 332 self.name = name |
| 333 self.options = options | 333 self.options = options |
| 334 self.gen_obj = gen_obj | 334 self.gen_obj = gen_obj |
| 335 | 335 |
| 336 def create_targets(self): | 336 def create_targets(self): |
| 337 """Create target instances""" | 337 """Create target instances""" |
| 338 self.target = self.target_class(self.name, self.options, self.gen_obj) | 338 self.target = self.target_class(self.name, self.options, self.gen_obj) |
| 339 self.target.add_dependencies() | 339 self.target.add_dependencies() |
| 340 | 340 |
| 341 def get_targets(self): | 341 def get_targets(self): |
| 342 """Return list of target instances associated with this section""" | 342 """Return list of target instances associated with this section""" |
| 343 return [self.target] | 343 return [self.target] |
| 344 | 344 |
| 345 def get_dep_targets(self, target): | 345 def get_dep_targets(self, target): |
| 346 """Return list of targets from this section that "target" depends on""" | 346 """Return list of targets from this section that "target" depends on""" |
| 347 return [self.target] | 347 return [self.target] |
| 348 | 348 |
| 349 class TargetLinked(Target): | 349 class TargetLinked(Target): |
| 350 "The target is linked (by libtool) against other libraries." | 350 "The target is linked (by libtool) against other libraries." |
| 351 | 351 |
| 352 def __init__(self, name, options, gen_obj): | 352 def __init__(self, name, options, gen_obj): |
| 353 Target.__init__(self, name, options, gen_obj) | 353 Target.__init__(self, name, options, gen_obj) |
| 354 self.install = options.get('install') | 354 self.install = options.get('install') |
| 355 self.compile_cmd = options.get('compile-cmd') | 355 self.compile_cmd = options.get('compile-cmd') |
| 356 self.sources = options.get('sources', '*.c') | 356 self.sources = options.get('sources', '*.c *.cpp') |
| 357 self.link_cmd = options.get('link-cmd', '$(LINK)') | 357 self.link_cmd = options.get('link-cmd', '$(LINK)') |
| 358 | 358 |
| 359 self.external_lib = options.get('external-lib') | 359 self.external_lib = options.get('external-lib') |
| 360 self.external_project = options.get('external-project') | 360 self.external_project = options.get('external-project') |
| 361 self.msvc_libs = string.split(options.get('msvc-libs', '')) | 361 self.msvc_libs = string.split(options.get('msvc-libs', '')) |
| 362 | 362 |
| 363 def add_dependencies(self): | 363 def add_dependencies(self): |
| 364 if self.external_lib or self.external_project: | 364 if self.external_lib or self.external_project: |
| 365 if self.external_project: | 365 if self.external_project: |
| 366 self.gen_obj.projects.append(self) | 366 self.gen_obj.projects.append(self) |
| 367 return | 367 return |
| 368 | 368 |
| 369 # the specified install area depends upon this target | 369 # the specified install area depends upon this target |
| 370 self.gen_obj.graph.add(DT_INSTALL, self.install, self) | 370 self.gen_obj.graph.add(DT_INSTALL, self.install, self) |
| 371 | 371 |
| 372 sources = _collect_paths(self.sources or '*.c', self.path) | 372 sources = _collect_paths(self.sources or '*.c' or '*.cpp', self.path) |
| 373 sources.sort() | 373 sources.sort() |
| 374 | 374 |
| 375 for src, reldir in sources: | 375 for srcs, reldir in sources: |
| 376 if src[-2:] == '.c': | 376 for src in srcs.split(" "): |
| 377 objname = src[:-2] + self.objext | 377 if glob.glob(src): |
| 378 elif src[-4:] == '.cpp': | 378 if src[-2:] == '.c': |
| 379 objname = src[:-4] + self.objext | 379 objname = src[:-2] + self.objext |
| 380 else: | 380 elif src[-4:] == '.cpp': |
| 381 raise GenError('ERROR: unknown file extension on ' + src) | 381 objname = src[:-4] + self.objext |
| 382 else: |
| 383 raise GenError('ERROR: unknown file extension on ' + src) |
| 382 | 384 |
| 383 ofile = ObjectFile(objname, self.compile_cmd) | 385 ofile = ObjectFile(objname, self.compile_cmd) |
| 384 | 386 |
| 385 # object depends upon source | 387 # object depends upon source |
| 386 self.gen_obj.graph.add(DT_OBJECT, ofile, SourceFile(src, reldir)) | 388 self.gen_obj.graph.add(DT_OBJECT, ofile, SourceFile(src, reldir)) |
| 387 | 389 |
| 388 # target (a linked item) depends upon object | 390 # target (a linked item) depends upon object |
| 389 self.gen_obj.graph.add(DT_LINK, self.name, ofile) | 391 self.gen_obj.graph.add(DT_LINK, self.name, ofile) |
| 390 | 392 |
| 391 # collect all the paths where stuff might get built | 393 # collect all the paths where stuff might get built |
| 392 ### we should collect this from the dependency nodes rather than | 394 ### we should collect this from the dependency nodes rather than |
| 393 ### the sources. "what dir are you going to put yourself into?" | 395 ### the sources. "what dir are you going to put yourself into?" |
| 394 self.gen_obj.target_dirs.append(self.path) | 396 self.gen_obj.target_dirs.append(self.path) |
| 395 for pattern in string.split(self.sources): | 397 for pattern in string.split(self.sources): |
| 396 dirname = build_path_dirname(pattern) | 398 dirname = build_path_dirname(pattern) |
| 397 if dirname: | 399 if dirname: |
| 398 self.gen_obj.target_dirs.append(build_path_join(self.path, dirname)) | 400 self.gen_obj.target_dirs.append(build_path_join(self.path, dirname)) |
| 399 | 401 |
| 400 class TargetExe(TargetLinked): | 402 class TargetExe(TargetLinked): |
| 401 def __init__(self, name, options, gen_obj): | 403 def __init__(self, name, options, gen_obj): |
| 402 TargetLinked.__init__(self, name, options, gen_obj) | 404 TargetLinked.__init__(self, name, options, gen_obj) |
| 403 | 405 |
| 404 if not (self.external_lib or self.external_project): | 406 if not (self.external_lib or self.external_project): |
| 405 extmap = self.gen_obj._extension_map | 407 extmap = self.gen_obj._extension_map |
| 406 self.objext = extmap['exe', 'object'] | 408 self.objext = extmap['exe', 'object'] |
| 407 self.filename = build_path_join(self.path, name + extmap['exe', 'target']) | 409 self.filename = build_path_join(self.path, name + extmap['exe', 'target']) |
| 408 | 410 |
| 409 self.manpages = options.get('manpages', '') | 411 self.manpages = options.get('manpages', '') |
| 410 self.testing = options.get('testing') | 412 self.testing = options.get('testing') |
| 411 | 413 |
| 412 def add_dependencies(self): | 414 def add_dependencies(self): |
| 413 TargetLinked.add_dependencies(self) | 415 TargetLinked.add_dependencies(self) |
| 414 | 416 |
| 415 # collect test programs | 417 # collect test programs |
| 416 if self.install == 'test': | 418 if self.install == 'test': |
| 417 self.gen_obj.test_deps.append(self.filename) | 419 self.gen_obj.test_deps.append(self.filename) |
| 418 if self.testing != 'skip': | 420 if self.testing != 'skip': |
| 419 self.gen_obj.test_progs.append(self.filename) | 421 self.gen_obj.test_progs.append(self.filename) |
| 420 elif self.install == 'bdb-test': | 422 elif self.install == 'bdb-test': |
| 421 self.gen_obj.bdb_test_deps.append(self.filename) | 423 self.gen_obj.bdb_test_deps.append(self.filename) |
| 422 if self.testing != 'skip': | 424 if self.testing != 'skip': |
| 423 self.gen_obj.bdb_test_progs.append(self.filename) | 425 self.gen_obj.bdb_test_progs.append(self.filename) |
| 424 | 426 |
| 425 self.gen_obj.manpages.extend(string.split(self.manpages)) | 427 self.gen_obj.manpages.extend(string.split(self.manpages)) |
| 426 | 428 |
| 427 class TargetScript(Target): | 429 class TargetScript(Target): |
| 428 def add_dependencies(self): | 430 def add_dependencies(self): |
| 429 # we don't need to "compile" the sources, so there are no dependencies | 431 # we don't need to "compile" the sources, so there are no dependencies |
| 430 # to add here, except to get the script installed in the proper area. | 432 # to add here, except to get the script installed in the proper area. |
| 431 # note that the script might itself be generated, but that isn't a | 433 # note that the script might itself be generated, but that isn't a |
| 432 # concern here. | 434 # concern here. |
| 433 self.gen_obj.graph.add(DT_INSTALL, self.install, self) | 435 self.gen_obj.graph.add(DT_INSTALL, self.install, self) |
| 434 | 436 |
| 435 class TargetLib(TargetLinked): | 437 class TargetLib(TargetLinked): |
| 436 def __init__(self, name, options, gen_obj): | 438 def __init__(self, name, options, gen_obj): |
| 437 TargetLinked.__init__(self, name, options, gen_obj) | 439 TargetLinked.__init__(self, name, options, gen_obj) |
| 438 | 440 |
| 439 if not (self.external_lib or self.external_project): | 441 if not (self.external_lib or self.external_project): |
| (...skipping 621 matching lines...) Show 10 above Show 10 below |
| 1061 s = graph.get_sources(DT_LINK, t.name, Target) \ | 1063 s = graph.get_sources(DT_LINK, t.name, Target) \ |
| 1062 + graph.get_sources(DT_NONLIB, t.name, Target) | 1064 + graph.get_sources(DT_NONLIB, t.name, Target) |
| 1063 for d in s: | 1065 for d in s: |
| 1064 if d in targets: | 1066 if d in targets: |
| 1065 break | 1067 break |
| 1066 else: | 1068 else: |
| 1067 # no dependencies found in the targets list. this is a good "base" | 1069 # no dependencies found in the targets list. this is a good "base" |
| 1068 # to add to the files list now. | 1070 # to add to the files list now. |
| 1069 if isinstance(t, TargetJava): | 1071 if isinstance(t, TargetJava): |
| 1070 # Java targets have no filename, and we just ignore them. | 1072 # Java targets have no filename, and we just ignore them. |
| 1071 pass | 1073 pass |
| 1072 elif isinstance(t, TargetI18N): | 1074 elif isinstance(t, TargetI18N): |
| 1073 # I18N targets have no filename, we recurse one level deeper, and | 1075 # I18N targets have no filename, we recurse one level deeper, and |
| 1074 # get the filenames of their dependencies. | 1076 # get the filenames of their dependencies. |
| 1075 s = graph.get_sources(DT_LINK, t.name) | 1077 s = graph.get_sources(DT_LINK, t.name) |
| 1076 for d in s: | 1078 for d in s: |
| 1077 if d not in targets: | 1079 if d not in targets: |
| 1078 files.append(d.filename) | 1080 files.append(d.filename) |
| 1079 else: | 1081 else: |
| 1080 files.append(t.filename) | 1082 files.append(t.filename) |
| 1081 | 1083 |
| 1082 # don't consider this target any more | 1084 # don't consider this target any more |
| 1083 targets.remove(t) | 1085 targets.remove(t) |
| 1084 | 1086 |
| 1085 # break out of search through targets | 1087 # break out of search through targets |
| 1086 break | 1088 break |
| 1087 else: | 1089 else: |
| 1088 # we went through the entire target list and everything had at least | 1090 # we went through the entire target list and everything had at least |
| 1089 # one dependency on another target. thus, we have a circular dependency | 1091 # one dependency on another target. thus, we have a circular dependency |
| 1090 # tree. somebody messed up the .conf file, or the app truly does have | 1092 # tree. somebody messed up the .conf file, or the app truly does have |
| 1091 # a loop (and if so, they're screwed; libtool can't relink a lib at | 1093 # a loop (and if so, they're screwed; libtool can't relink a lib at |
| 1092 # install time if the dependent libs haven't been installed yet) | 1094 # install time if the dependent libs haven't been installed yet) |
| 1093 raise CircularDependencies() | 1095 raise CircularDependencies() |
| 1094 | 1096 |
| 1095 return files | 1097 return files |
| 1096 | 1098 |
| 1097 class CircularDependencies(Exception): | 1099 class CircularDependencies(Exception): |
| 1098 pass | 1100 pass |
| 1099 | 1101 |
| 1100 def unique(seq): | 1102 def unique(seq): |
| 1101 "Eliminate duplicates from a sequence" | 1103 "Eliminate duplicates from a sequence" |
| 1102 list = [ ] | 1104 list = [ ] |
| 1103 dupes = { } | 1105 dupes = { } |
| 1104 for e in seq: | 1106 for e in seq: |
| 1105 if not dupes.has_key(e): | 1107 if not dupes.has_key(e): |
| 1106 dupes[e] = None | 1108 dupes[e] = None |
| 1107 list.append(e) | 1109 list.append(e) |
| 1108 return list | 1110 return list |
| 1109 | 1111 |
| 1110 ### End of file. | 1112 ### End of file. |
| OLD | NEW |