ยปCore Development>Code coverage>Lib/packaging/compiler/__init__.py

Python code coverage for Lib/packaging/compiler/__init__.py

#countcontent
1n/a"""Compiler abstraction model used by packaging.
2n/a
3n/aAn abstract base class is defined in the ccompiler submodule, and
4n/aconcrete implementations suitable for various platforms are defined in
5n/athe other submodules. The extension module is also placed in this
6n/apackage.
7n/a
8n/aIn general, code should not instantiate compiler classes directly but
9n/ause the new_compiler and customize_compiler functions provided in this
10n/amodule.
11n/a
12n/aThe compiler system has a registration API: get_default_compiler,
13n/aset_compiler, show_compilers.
14n/a"""
15n/a
16n/aimport os
17n/aimport sys
18n/aimport re
19n/aimport sysconfig
20n/a
21n/afrom packaging.util import resolve_name
22n/afrom packaging.errors import PackagingPlatformError
23n/afrom packaging import logger
24n/a
25n/adef customize_compiler(compiler):
26n/a """Do any platform-specific customization of a CCompiler instance.
27n/a
28n/a Mainly needed on Unix, so we can plug in the information that
29n/a varies across Unices and is stored in Python's Makefile.
30n/a """
31n/a if compiler.name == "unix":
32n/a cc, cxx, opt, cflags, ccshared, ldshared, so_ext, ar, ar_flags = (
33n/a sysconfig.get_config_vars('CC', 'CXX', 'OPT', 'CFLAGS',
34n/a 'CCSHARED', 'LDSHARED', 'SO', 'AR',
35n/a 'ARFLAGS'))
36n/a
37n/a if 'CC' in os.environ:
38n/a cc = os.environ['CC']
39n/a if 'CXX' in os.environ:
40n/a cxx = os.environ['CXX']
41n/a if 'LDSHARED' in os.environ:
42n/a ldshared = os.environ['LDSHARED']
43n/a if 'CPP' in os.environ:
44n/a cpp = os.environ['CPP']
45n/a else:
46n/a cpp = cc + " -E" # not always
47n/a if 'LDFLAGS' in os.environ:
48n/a ldshared = ldshared + ' ' + os.environ['LDFLAGS']
49n/a if 'CFLAGS' in os.environ:
50n/a cflags = opt + ' ' + os.environ['CFLAGS']
51n/a ldshared = ldshared + ' ' + os.environ['CFLAGS']
52n/a if 'CPPFLAGS' in os.environ:
53n/a cpp = cpp + ' ' + os.environ['CPPFLAGS']
54n/a cflags = cflags + ' ' + os.environ['CPPFLAGS']
55n/a ldshared = ldshared + ' ' + os.environ['CPPFLAGS']
56n/a if 'AR' in os.environ:
57n/a ar = os.environ['AR']
58n/a if 'ARFLAGS' in os.environ:
59n/a archiver = ar + ' ' + os.environ['ARFLAGS']
60n/a else:
61n/a if ar_flags is not None:
62n/a archiver = ar + ' ' + ar_flags
63n/a else:
64n/a # see if its the proper default value
65n/a # mmm I don't want to backport the makefile
66n/a archiver = ar + ' rc'
67n/a
68n/a cc_cmd = cc + ' ' + cflags
69n/a compiler.set_executables(
70n/a preprocessor=cpp,
71n/a compiler=cc_cmd,
72n/a compiler_so=cc_cmd + ' ' + ccshared,
73n/a compiler_cxx=cxx,
74n/a linker_so=ldshared,
75n/a linker_exe=cc,
76n/a archiver=archiver)
77n/a
78n/a compiler.shared_lib_extension = so_ext
79n/a
80n/a
81n/a# Map a sys.platform/os.name ('posix', 'nt') to the default compiler
82n/a# type for that platform. Keys are interpreted as re match
83n/a# patterns. Order is important; platform mappings are preferred over
84n/a# OS names.
85n/a_default_compilers = (
86n/a # Platform string mappings
87n/a
88n/a # on a cygwin built python we can use gcc like an ordinary UNIXish
89n/a # compiler
90n/a ('cygwin.*', 'unix'),
91n/a
92n/a # OS name mappings
93n/a ('posix', 'unix'),
94n/a ('nt', 'msvc'),
95n/a)
96n/a
97n/adef get_default_compiler(osname=None, platform=None):
98n/a """ Determine the default compiler to use for the given platform.
99n/a
100n/a osname should be one of the standard Python OS names (i.e. the
101n/a ones returned by os.name) and platform the common value
102n/a returned by sys.platform for the platform in question.
103n/a
104n/a The default values are os.name and sys.platform in case the
105n/a parameters are not given.
106n/a
107n/a """
108n/a if osname is None:
109n/a osname = os.name
110n/a if platform is None:
111n/a platform = sys.platform
112n/a for pattern, compiler in _default_compilers:
113n/a if re.match(pattern, platform) is not None or \
114n/a re.match(pattern, osname) is not None:
115n/a return compiler
116n/a # Defaults to Unix compiler
117n/a return 'unix'
118n/a
119n/a
120n/a# compiler mapping
121n/a# XXX useful to expose them? (i.e. get_compiler_names)
122n/a_COMPILERS = {
123n/a 'unix': 'packaging.compiler.unixccompiler.UnixCCompiler',
124n/a 'msvc': 'packaging.compiler.msvccompiler.MSVCCompiler',
125n/a 'cygwin': 'packaging.compiler.cygwinccompiler.CygwinCCompiler',
126n/a 'mingw32': 'packaging.compiler.cygwinccompiler.Mingw32CCompiler',
127n/a 'bcpp': 'packaging.compiler.bcppcompiler.BCPPCompiler',
128n/a}
129n/a
130n/adef set_compiler(location):
131n/a """Add or change a compiler"""
132n/a cls = resolve_name(location)
133n/a # XXX we want to check the class here
134n/a _COMPILERS[cls.name] = cls
135n/a
136n/a
137n/adef show_compilers():
138n/a """Print list of available compilers (used by the "--help-compiler"
139n/a options to "build", "build_ext", "build_clib").
140n/a """
141n/a from packaging.fancy_getopt import FancyGetopt
142n/a compilers = []
143n/a
144n/a for name, cls in _COMPILERS.items():
145n/a if isinstance(cls, str):
146n/a cls = resolve_name(cls)
147n/a _COMPILERS[name] = cls
148n/a
149n/a compilers.append(("compiler=" + name, None, cls.description))
150n/a
151n/a compilers.sort()
152n/a pretty_printer = FancyGetopt(compilers)
153n/a pretty_printer.print_help("List of available compilers:")
154n/a
155n/a
156n/adef new_compiler(plat=None, compiler=None, dry_run=False, force=False):
157n/a """Generate an instance of some CCompiler subclass for the supplied
158n/a platform/compiler combination. 'plat' defaults to 'os.name'
159n/a (eg. 'posix', 'nt'), and 'compiler' defaults to the default compiler
160n/a for that platform. Currently only 'posix' and 'nt' are supported, and
161n/a the default compilers are "traditional Unix interface" (UnixCCompiler
162n/a class) and Visual C++ (MSVCCompiler class). Note that it's perfectly
163n/a possible to ask for a Unix compiler object under Windows, and a
164n/a Microsoft compiler object under Unix -- if you supply a value for
165n/a 'compiler', 'plat' is ignored.
166n/a """
167n/a if plat is None:
168n/a plat = os.name
169n/a
170n/a try:
171n/a if compiler is None:
172n/a compiler = get_default_compiler(plat)
173n/a
174n/a cls = _COMPILERS[compiler]
175n/a except KeyError:
176n/a msg = "don't know how to compile C/C++ code on platform '%s'" % plat
177n/a if compiler is not None:
178n/a msg = msg + " with '%s' compiler" % compiler
179n/a raise PackagingPlatformError(msg)
180n/a
181n/a if isinstance(cls, str):
182n/a cls = resolve_name(cls)
183n/a _COMPILERS[compiler] = cls
184n/a
185n/a return cls(dry_run, force)
186n/a
187n/a
188n/adef gen_preprocess_options(macros, include_dirs):
189n/a """Generate C pre-processor options (-D, -U, -I) as used by at least
190n/a two types of compilers: the typical Unix compiler and Visual C++.
191n/a 'macros' is the usual thing, a list of 1- or 2-tuples, where (name,)
192n/a means undefine (-U) macro 'name', and (name,value) means define (-D)
193n/a macro 'name' to 'value'. 'include_dirs' is just a list of directory
194n/a names to be added to the header file search path (-I). Returns a list
195n/a of command-line options suitable for either Unix compilers or Visual
196n/a C++.
197n/a """
198n/a # XXX it would be nice (mainly aesthetic, and so we don't generate
199n/a # stupid-looking command lines) to go over 'macros' and eliminate
200n/a # redundant definitions/undefinitions (ie. ensure that only the
201n/a # latest mention of a particular macro winds up on the command
202n/a # line). I don't think it's essential, though, since most (all?)
203n/a # Unix C compilers only pay attention to the latest -D or -U
204n/a # mention of a macro on their command line. Similar situation for
205n/a # 'include_dirs'. I'm punting on both for now. Anyways, weeding out
206n/a # redundancies like this should probably be the province of
207n/a # CCompiler, since the data structures used are inherited from it
208n/a # and therefore common to all CCompiler classes.
209n/a
210n/a pp_opts = []
211n/a for macro in macros:
212n/a
213n/a if not isinstance(macro, tuple) and 1 <= len(macro) <= 2:
214n/a raise TypeError(
215n/a "bad macro definition '%s': each element of 'macros'"
216n/a "list must be a 1- or 2-tuple" % macro)
217n/a
218n/a if len(macro) == 1: # undefine this macro
219n/a pp_opts.append("-U%s" % macro[0])
220n/a elif len(macro) == 2:
221n/a if macro[1] is None: # define with no explicit value
222n/a pp_opts.append("-D%s" % macro[0])
223n/a else:
224n/a # XXX *don't* need to be clever about quoting the
225n/a # macro value here, because we're going to avoid the
226n/a # shell at all costs when we spawn the command!
227n/a pp_opts.append("-D%s=%s" % macro)
228n/a
229n/a for dir in include_dirs:
230n/a pp_opts.append("-I%s" % dir)
231n/a
232n/a return pp_opts
233n/a
234n/a
235n/adef gen_lib_options(compiler, library_dirs, runtime_library_dirs, libraries):
236n/a """Generate linker options for searching library directories and
237n/a linking with specific libraries.
238n/a
239n/a 'libraries' and 'library_dirs' are, respectively, lists of library names
240n/a (not filenames!) and search directories. Returns a list of command-line
241n/a options suitable for use with some compiler (depending on the two format
242n/a strings passed in).
243n/a """
244n/a lib_opts = []
245n/a
246n/a for dir in library_dirs:
247n/a lib_opts.append(compiler.library_dir_option(dir))
248n/a
249n/a for dir in runtime_library_dirs:
250n/a opt = compiler.runtime_library_dir_option(dir)
251n/a if isinstance(opt, list):
252n/a lib_opts.extend(opt)
253n/a else:
254n/a lib_opts.append(opt)
255n/a
256n/a # XXX it's important that we *not* remove redundant library mentions!
257n/a # sometimes you really do have to say "-lfoo -lbar -lfoo" in order to
258n/a # resolve all symbols. I just hope we never have to say "-lfoo obj.o
259n/a # -lbar" to get things to work -- that's certainly a possibility, but a
260n/a # pretty nasty way to arrange your C code.
261n/a
262n/a for lib in libraries:
263n/a lib_dir, lib_name = os.path.split(lib)
264n/a if lib_dir != '':
265n/a lib_file = compiler.find_library_file([lib_dir], lib_name)
266n/a if lib_file is not None:
267n/a lib_opts.append(lib_file)
268n/a else:
269n/a logger.warning("no library file corresponding to "
270n/a "'%s' found (skipping)" % lib)
271n/a else:
272n/a lib_opts.append(compiler.library_option(lib))
273n/a
274n/a return lib_opts