ยปCore Development>Code coverage>Lib/distutils/command/build_clib.py

Python code coverage for Lib/distutils/command/build_clib.py

#countcontent
1n/a"""distutils.command.build_clib
2n/a
3n/aImplements the Distutils 'build_clib' command, to build a C/C++ library
4n/athat is included in the module distribution and needed by an extension
5n/amodule."""
6n/a
7n/a
8n/a# XXX this module has *lots* of code ripped-off quite transparently from
9n/a# build_ext.py -- not surprisingly really, as the work required to build
10n/a# a static library from a collection of C source files is not really all
11n/a# that different from what's required to build a shared object file from
12n/a# a collection of C source files. Nevertheless, I haven't done the
13n/a# necessary refactoring to account for the overlap in code between the
14n/a# two modules, mainly because a number of subtle details changed in the
15n/a# cut 'n paste. Sigh.
16n/a
17n/aimport os
18n/afrom distutils.core import Command
19n/afrom distutils.errors import *
20n/afrom distutils.sysconfig import customize_compiler
21n/afrom distutils import log
22n/a
23n/adef show_compilers():
24n/a from distutils.ccompiler import show_compilers
25n/a show_compilers()
26n/a
27n/a
28n/aclass build_clib(Command):
29n/a
30n/a description = "build C/C++ libraries used by Python extensions"
31n/a
32n/a user_options = [
33n/a ('build-clib=', 'b',
34n/a "directory to build C/C++ libraries to"),
35n/a ('build-temp=', 't',
36n/a "directory to put temporary build by-products"),
37n/a ('debug', 'g',
38n/a "compile with debugging information"),
39n/a ('force', 'f',
40n/a "forcibly build everything (ignore file timestamps)"),
41n/a ('compiler=', 'c',
42n/a "specify the compiler type"),
43n/a ]
44n/a
45n/a boolean_options = ['debug', 'force']
46n/a
47n/a help_options = [
48n/a ('help-compiler', None,
49n/a "list available compilers", show_compilers),
50n/a ]
51n/a
52n/a def initialize_options(self):
53n/a self.build_clib = None
54n/a self.build_temp = None
55n/a
56n/a # List of libraries to build
57n/a self.libraries = None
58n/a
59n/a # Compilation options for all libraries
60n/a self.include_dirs = None
61n/a self.define = None
62n/a self.undef = None
63n/a self.debug = None
64n/a self.force = 0
65n/a self.compiler = None
66n/a
67n/a
68n/a def finalize_options(self):
69n/a # This might be confusing: both build-clib and build-temp default
70n/a # to build-temp as defined by the "build" command. This is because
71n/a # I think that C libraries are really just temporary build
72n/a # by-products, at least from the point of view of building Python
73n/a # extensions -- but I want to keep my options open.
74n/a self.set_undefined_options('build',
75n/a ('build_temp', 'build_clib'),
76n/a ('build_temp', 'build_temp'),
77n/a ('compiler', 'compiler'),
78n/a ('debug', 'debug'),
79n/a ('force', 'force'))
80n/a
81n/a self.libraries = self.distribution.libraries
82n/a if self.libraries:
83n/a self.check_library_list(self.libraries)
84n/a
85n/a if self.include_dirs is None:
86n/a self.include_dirs = self.distribution.include_dirs or []
87n/a if isinstance(self.include_dirs, str):
88n/a self.include_dirs = self.include_dirs.split(os.pathsep)
89n/a
90n/a # XXX same as for build_ext -- what about 'self.define' and
91n/a # 'self.undef' ?
92n/a
93n/a
94n/a def run(self):
95n/a if not self.libraries:
96n/a return
97n/a
98n/a # Yech -- this is cut 'n pasted from build_ext.py!
99n/a from distutils.ccompiler import new_compiler
100n/a self.compiler = new_compiler(compiler=self.compiler,
101n/a dry_run=self.dry_run,
102n/a force=self.force)
103n/a customize_compiler(self.compiler)
104n/a
105n/a if self.include_dirs is not None:
106n/a self.compiler.set_include_dirs(self.include_dirs)
107n/a if self.define is not None:
108n/a # 'define' option is a list of (name,value) tuples
109n/a for (name,value) in self.define:
110n/a self.compiler.define_macro(name, value)
111n/a if self.undef is not None:
112n/a for macro in self.undef:
113n/a self.compiler.undefine_macro(macro)
114n/a
115n/a self.build_libraries(self.libraries)
116n/a
117n/a
118n/a def check_library_list(self, libraries):
119n/a """Ensure that the list of libraries is valid.
120n/a
121n/a `library` is presumably provided as a command option 'libraries'.
122n/a This method checks that it is a list of 2-tuples, where the tuples
123n/a are (library_name, build_info_dict).
124n/a
125n/a Raise DistutilsSetupError if the structure is invalid anywhere;
126n/a just returns otherwise.
127n/a """
128n/a if not isinstance(libraries, list):
129n/a raise DistutilsSetupError(
130n/a "'libraries' option must be a list of tuples")
131n/a
132n/a for lib in libraries:
133n/a if not isinstance(lib, tuple) and len(lib) != 2:
134n/a raise DistutilsSetupError(
135n/a "each element of 'libraries' must a 2-tuple")
136n/a
137n/a name, build_info = lib
138n/a
139n/a if not isinstance(name, str):
140n/a raise DistutilsSetupError(
141n/a "first element of each tuple in 'libraries' "
142n/a "must be a string (the library name)")
143n/a
144n/a if '/' in name or (os.sep != '/' and os.sep in name):
145n/a raise DistutilsSetupError("bad library name '%s': "
146n/a "may not contain directory separators" % lib[0])
147n/a
148n/a if not isinstance(build_info, dict):
149n/a raise DistutilsSetupError(
150n/a "second element of each tuple in 'libraries' "
151n/a "must be a dictionary (build info)")
152n/a
153n/a
154n/a def get_library_names(self):
155n/a # Assume the library list is valid -- 'check_library_list()' is
156n/a # called from 'finalize_options()', so it should be!
157n/a if not self.libraries:
158n/a return None
159n/a
160n/a lib_names = []
161n/a for (lib_name, build_info) in self.libraries:
162n/a lib_names.append(lib_name)
163n/a return lib_names
164n/a
165n/a
166n/a def get_source_files(self):
167n/a self.check_library_list(self.libraries)
168n/a filenames = []
169n/a for (lib_name, build_info) in self.libraries:
170n/a sources = build_info.get('sources')
171n/a if sources is None or not isinstance(sources, (list, tuple)):
172n/a raise DistutilsSetupError(
173n/a "in 'libraries' option (library '%s'), "
174n/a "'sources' must be present and must be "
175n/a "a list of source filenames" % lib_name)
176n/a
177n/a filenames.extend(sources)
178n/a return filenames
179n/a
180n/a
181n/a def build_libraries(self, libraries):
182n/a for (lib_name, build_info) in libraries:
183n/a sources = build_info.get('sources')
184n/a if sources is None or not isinstance(sources, (list, tuple)):
185n/a raise DistutilsSetupError(
186n/a "in 'libraries' option (library '%s'), "
187n/a "'sources' must be present and must be "
188n/a "a list of source filenames" % lib_name)
189n/a sources = list(sources)
190n/a
191n/a log.info("building '%s' library", lib_name)
192n/a
193n/a # First, compile the source code to object files in the library
194n/a # directory. (This should probably change to putting object
195n/a # files in a temporary build directory.)
196n/a macros = build_info.get('macros')
197n/a include_dirs = build_info.get('include_dirs')
198n/a objects = self.compiler.compile(sources,
199n/a output_dir=self.build_temp,
200n/a macros=macros,
201n/a include_dirs=include_dirs,
202n/a debug=self.debug)
203n/a
204n/a # Now "link" the object files together into a static library.
205n/a # (On Unix at least, this isn't really linking -- it just
206n/a # builds an archive. Whatever.)
207n/a self.compiler.create_static_lib(objects, lib_name,
208n/a output_dir=self.build_clib,
209n/a debug=self.debug)