forked from mrlan/EnglishPal
105 lines
4.4 KiB
Python
105 lines
4.4 KiB
Python
|
import distutils.command.build_clib as orig
|
||
|
from distutils.errors import DistutilsSetupError
|
||
|
from distutils import log
|
||
|
|
||
|
try:
|
||
|
from distutils._modified import newer_pairwise_group
|
||
|
except ImportError:
|
||
|
# fallback for SETUPTOOLS_USE_DISTUTILS=stdlib
|
||
|
from .._distutils._modified 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 = sorted(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')
|
||
|
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
|
||
|
)
|