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