| import distutils.command.build_clib as orig |
| from distutils.errors import DistutilsSetupError |
| from distutils import log |
| from setuptools.dep_util import newer_pairwise_group |
| |
| |
| class build_clib(orig.build_clib): |
| """ |
| Override the default build_clib behaviour to do the following: |
| |
| 1. Implement a rudimentary timestamp-based dependency system |
| so 'compile()' doesn't run every time. |
| 2. Add more keys to the 'build_info' dictionary: |
| * obj_deps - specify dependencies for each object compiled. |
| this should be a dictionary mapping a key |
| with the source filename to a list of |
| dependencies. Use an empty string for global |
| dependencies. |
| * cflags - specify a list of additional flags to pass to |
| the compiler. |
| """ |
| |
| def build_libraries(self, libraries): |
| for (lib_name, build_info) in libraries: |
| sources = build_info.get('sources') |
| if sources is None or not isinstance(sources, (list, tuple)): |
| raise DistutilsSetupError( |
| "in 'libraries' option (library '%s'), " |
| "'sources' must be present and must be " |
| "a list of source filenames" % lib_name) |
| sources = list(sources) |
| |
| log.info("building '%s' library", lib_name) |
| |
| # Make sure everything is the correct type. |
| # obj_deps should be a dictionary of keys as sources |
| # and a list/tuple of files that are its dependencies. |
| obj_deps = build_info.get('obj_deps', dict()) |
| if not isinstance(obj_deps, dict): |
| raise DistutilsSetupError( |
| "in 'libraries' option (library '%s'), " |
| "'obj_deps' must be a dictionary of " |
| "type 'source: list'" % lib_name) |
| dependencies = [] |
| |
| # Get the global dependencies that are specified by the '' key. |
| # These will go into every source's dependency list. |
| global_deps = obj_deps.get('', list()) |
| if not isinstance(global_deps, (list, tuple)): |
| raise DistutilsSetupError( |
| "in 'libraries' option (library '%s'), " |
| "'obj_deps' must be a dictionary of " |
| "type 'source: list'" % lib_name) |
| |
| # Build the list to be used by newer_pairwise_group |
| # each source will be auto-added to its dependencies. |
| for source in sources: |
| src_deps = [source] |
| src_deps.extend(global_deps) |
| extra_deps = obj_deps.get(source, list()) |
| if not isinstance(extra_deps, (list, tuple)): |
| raise DistutilsSetupError( |
| "in 'libraries' option (library '%s'), " |
| "'obj_deps' must be a dictionary of " |
| "type 'source: list'" % lib_name) |
| src_deps.extend(extra_deps) |
| dependencies.append(src_deps) |
| |
| expected_objects = self.compiler.object_filenames( |
| sources, |
| output_dir=self.build_temp |
| ) |
| |
| if newer_pairwise_group(dependencies, expected_objects) != ([], []): |
| # First, compile the source code to object files in the library |
| # directory. (This should probably change to putting object |
| # files in a temporary build directory.) |
| macros = build_info.get('macros') |
| include_dirs = build_info.get('include_dirs') |
| cflags = build_info.get('cflags') |
| objects = self.compiler.compile( |
| sources, |
| output_dir=self.build_temp, |
| macros=macros, |
| include_dirs=include_dirs, |
| extra_postargs=cflags, |
| debug=self.debug |
| ) |
| |
| # Now "link" the object files together into a static library. |
| # (On Unix at least, this isn't really linking -- it just |
| # builds an archive. Whatever.) |
| self.compiler.create_static_lib( |
| expected_objects, |
| lib_name, |
| output_dir=self.build_clib, |
| debug=self.debug |
| ) |