build_clib.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import distutils.command.build_clib as orig
  2. from distutils.errors import DistutilsSetupError
  3. from distutils import log
  4. from setuptools.dep_util import newer_pairwise_group
  5. class build_clib(orig.build_clib):
  6. """
  7. Override the default build_clib behaviour to do the following:
  8. 1. Implement a rudimentary timestamp-based dependency system
  9. so 'compile()' doesn't run every time.
  10. 2. Add more keys to the 'build_info' dictionary:
  11. * obj_deps - specify dependencies for each object compiled.
  12. this should be a dictionary mapping a key
  13. with the source filename to a list of
  14. dependencies. Use an empty string for global
  15. dependencies.
  16. * cflags - specify a list of additional flags to pass to
  17. the compiler.
  18. """
  19. def build_libraries(self, libraries):
  20. for (lib_name, build_info) in libraries:
  21. sources = build_info.get('sources')
  22. if sources is None or not isinstance(sources, (list, tuple)):
  23. raise DistutilsSetupError(
  24. "in 'libraries' option (library '%s'), "
  25. "'sources' must be present and must be "
  26. "a list of source filenames" % lib_name)
  27. sources = list(sources)
  28. log.info("building '%s' library", lib_name)
  29. # Make sure everything is the correct type.
  30. # obj_deps should be a dictionary of keys as sources
  31. # and a list/tuple of files that are its dependencies.
  32. obj_deps = build_info.get('obj_deps', dict())
  33. if not isinstance(obj_deps, dict):
  34. raise DistutilsSetupError(
  35. "in 'libraries' option (library '%s'), "
  36. "'obj_deps' must be a dictionary of "
  37. "type 'source: list'" % lib_name)
  38. dependencies = []
  39. # Get the global dependencies that are specified by the '' key.
  40. # These will go into every source's dependency list.
  41. global_deps = obj_deps.get('', list())
  42. if not isinstance(global_deps, (list, tuple)):
  43. raise DistutilsSetupError(
  44. "in 'libraries' option (library '%s'), "
  45. "'obj_deps' must be a dictionary of "
  46. "type 'source: list'" % lib_name)
  47. # Build the list to be used by newer_pairwise_group
  48. # each source will be auto-added to its dependencies.
  49. for source in sources:
  50. src_deps = [source]
  51. src_deps.extend(global_deps)
  52. extra_deps = obj_deps.get(source, list())
  53. if not isinstance(extra_deps, (list, tuple)):
  54. raise DistutilsSetupError(
  55. "in 'libraries' option (library '%s'), "
  56. "'obj_deps' must be a dictionary of "
  57. "type 'source: list'" % lib_name)
  58. src_deps.extend(extra_deps)
  59. dependencies.append(src_deps)
  60. expected_objects = self.compiler.object_filenames(
  61. sources,
  62. output_dir=self.build_temp,
  63. )
  64. if (
  65. newer_pairwise_group(dependencies, expected_objects)
  66. != ([], [])
  67. ):
  68. # First, compile the source code to object files in the library
  69. # directory. (This should probably change to putting object
  70. # files in a temporary build directory.)
  71. macros = build_info.get('macros')
  72. include_dirs = build_info.get('include_dirs')
  73. cflags = build_info.get('cflags')
  74. self.compiler.compile(
  75. sources,
  76. output_dir=self.build_temp,
  77. macros=macros,
  78. include_dirs=include_dirs,
  79. extra_postargs=cflags,
  80. debug=self.debug
  81. )
  82. # Now "link" the object files together into a static library.
  83. # (On Unix at least, this isn't really linking -- it just
  84. # builds an archive. Whatever.)
  85. self.compiler.create_static_lib(
  86. expected_objects,
  87. lib_name,
  88. output_dir=self.build_clib,
  89. debug=self.debug
  90. )