codekingpro/portable-devtools
114k
1import distutils.command.build_clib as orig2from distutils.errors import DistutilsSetupError3from distutils import log4 5try:6 from distutils._modified import newer_pairwise_group7except ImportError:8 # fallback for SETUPTOOLS_USE_DISTUTILS=stdlib9 from .._distutils._modified import newer_pairwise_group10 11 12class build_clib(orig.build_clib):13 """14 Override the default build_clib behaviour to do the following:15 16 1. Implement a rudimentary timestamp-based dependency system17 so 'compile()' doesn't run every time.18 2. Add more keys to the 'build_info' dictionary:19 * obj_deps - specify dependencies for each object compiled.20 this should be a dictionary mapping a key21 with the source filename to a list of22 dependencies. Use an empty string for global23 dependencies.24 * cflags - specify a list of additional flags to pass to25 the compiler.26 """27 28 def build_libraries(self, libraries):29 for lib_name, build_info in libraries:30 sources = build_info.get('sources')31 if sources is None or not isinstance(sources, (list, tuple)):32 raise DistutilsSetupError(33 "in 'libraries' option (library '%s'), "34 "'sources' must be present and must be "35 "a list of source filenames" % lib_name36 )37 sources = sorted(list(sources))38 39 log.info("building '%s' library", lib_name)40 41 # Make sure everything is the correct type.42 # obj_deps should be a dictionary of keys as sources43 # and a list/tuple of files that are its dependencies.44 obj_deps = build_info.get('obj_deps', dict())45 if not isinstance(obj_deps, dict):46 raise DistutilsSetupError(47 "in 'libraries' option (library '%s'), "48 "'obj_deps' must be a dictionary of "49 "type 'source: list'" % lib_name50 )51 dependencies = []52 53 # Get the global dependencies that are specified by the '' key.54 # These will go into every source's dependency list.55 global_deps = obj_deps.get('', list())56 if not isinstance(global_deps, (list, tuple)):57 raise DistutilsSetupError(58 "in 'libraries' option (library '%s'), "59 "'obj_deps' must be a dictionary of "60 "type 'source: list'" % lib_name61 )62 63 # Build the list to be used by newer_pairwise_group64 # each source will be auto-added to its dependencies.65 for source in sources:66 src_deps = [source]67 src_deps.extend(global_deps)68 extra_deps = obj_deps.get(source, list())69 if not isinstance(extra_deps, (list, tuple)):70 raise DistutilsSetupError(71 "in 'libraries' option (library '%s'), "72 "'obj_deps' must be a dictionary of "73 "type 'source: list'" % lib_name74 )75 src_deps.extend(extra_deps)76 dependencies.append(src_deps)77 78 expected_objects = self.compiler.object_filenames(79 sources,80 output_dir=self.build_temp,81 )82 83 if newer_pairwise_group(dependencies, expected_objects) != ([], []):84 # First, compile the source code to object files in the library85 # directory. (This should probably change to putting object86 # files in a temporary build directory.)87 macros = build_info.get('macros')88 include_dirs = build_info.get('include_dirs')89 cflags = build_info.get('cflags')90 self.compiler.compile(91 sources,92 output_dir=self.build_temp,93 macros=macros,94 include_dirs=include_dirs,95 extra_postargs=cflags,96 debug=self.debug,97 )98 99 # Now "link" the object files together into a static library.100 # (On Unix at least, this isn't really linking -- it just101 # builds an archive. Whatever.)102 self.compiler.create_static_lib(103 expected_objects, lib_name, output_dir=self.build_clib, debug=self.debug104 )105 