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

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

#countcontent
1n/a"""CCompiler implementation for Unix compilers.
2n/a
3n/aThis module contains the UnixCCompiler class, a subclass of CCompiler
4n/athat handles the "typical" Unix-style command-line C compiler:
5n/a * macros defined with -Dname[=value]
6n/a * macros undefined with -Uname
7n/a * include search directories specified with -Idir
8n/a * libraries specified with -lllib
9n/a * library search directories specified with -Ldir
10n/a * compile handled by 'cc' (or similar) executable with -c option:
11n/a compiles .c to .o
12n/a * link static library handled by 'ar' command (possibly with 'ranlib')
13n/a * link shared library handled by 'cc -shared'
14n/a"""
15n/a
16n/aimport os, sys
17n/a
18n/afrom packaging.util import newer
19n/afrom packaging.compiler.ccompiler import CCompiler
20n/afrom packaging.compiler import gen_preprocess_options, gen_lib_options
21n/afrom packaging.errors import (PackagingExecError, CompileError,
22n/a LibError, LinkError)
23n/afrom packaging import logger
24n/aimport sysconfig
25n/a
26n/a
27n/a# XXX Things not currently handled:
28n/a# * optimization/debug/warning flags; we just use whatever's in Python's
29n/a# Makefile and live with it. Is this adequate? If not, we might
30n/a# have to have a bunch of subclasses GNUCCompiler, SGICCompiler,
31n/a# SunCCompiler, and I suspect down that road lies madness.
32n/a# * even if we don't know a warning flag from an optimization flag,
33n/a# we need some way for outsiders to feed preprocessor/compiler/linker
34n/a# flags in to us -- eg. a sysadmin might want to mandate certain flags
35n/a# via a site config file, or a user might want to set something for
36n/a# compiling this module distribution only via the pysetup command
37n/a# line, whatever. As long as these options come from something on the
38n/a# current system, they can be as system-dependent as they like, and we
39n/a# should just happily stuff them into the preprocessor/compiler/linker
40n/a# options and carry on.
41n/a
42n/adef _darwin_compiler_fixup(compiler_so, cc_args):
43n/a """
44n/a This function will strip '-isysroot PATH' and '-arch ARCH' from the
45n/a compile flags if the user has specified one them in extra_compile_flags.
46n/a
47n/a This is needed because '-arch ARCH' adds another architecture to the
48n/a build, without a way to remove an architecture. Furthermore GCC will
49n/a barf if multiple '-isysroot' arguments are present.
50n/a """
51n/a stripArch = stripSysroot = False
52n/a
53n/a compiler_so = list(compiler_so)
54n/a kernel_version = os.uname()[2] # 8.4.3
55n/a major_version = int(kernel_version.split('.')[0])
56n/a
57n/a if major_version < 8:
58n/a # OSX before 10.4.0, these don't support -arch and -isysroot at
59n/a # all.
60n/a stripArch = stripSysroot = True
61n/a else:
62n/a stripArch = '-arch' in cc_args
63n/a stripSysroot = '-isysroot' in cc_args
64n/a
65n/a if stripArch or 'ARCHFLAGS' in os.environ:
66n/a while True:
67n/a try:
68n/a index = compiler_so.index('-arch')
69n/a # Strip this argument and the next one:
70n/a del compiler_so[index:index+2]
71n/a except ValueError:
72n/a break
73n/a
74n/a if 'ARCHFLAGS' in os.environ and not stripArch:
75n/a # User specified different -arch flags in the environ,
76n/a # see also the sysconfig
77n/a compiler_so = compiler_so + os.environ['ARCHFLAGS'].split()
78n/a
79n/a if stripSysroot:
80n/a try:
81n/a index = compiler_so.index('-isysroot')
82n/a # Strip this argument and the next one:
83n/a del compiler_so[index:index+2]
84n/a except ValueError:
85n/a pass
86n/a
87n/a # Check if the SDK that is used during compilation actually exists,
88n/a # the universal build requires the usage of a universal SDK and not all
89n/a # users have that installed by default.
90n/a sysroot = None
91n/a if '-isysroot' in cc_args:
92n/a idx = cc_args.index('-isysroot')
93n/a sysroot = cc_args[idx+1]
94n/a elif '-isysroot' in compiler_so:
95n/a idx = compiler_so.index('-isysroot')
96n/a sysroot = compiler_so[idx+1]
97n/a
98n/a if sysroot and not os.path.isdir(sysroot):
99n/a logger.warning(
100n/a "compiling with an SDK that doesn't seem to exist: %r;\n"
101n/a "please check your Xcode installation", sysroot)
102n/a
103n/a return compiler_so
104n/a
105n/aclass UnixCCompiler(CCompiler):
106n/a
107n/a name = 'unix'
108n/a description = 'Standard UNIX-style compiler'
109n/a
110n/a # These are used by CCompiler in two places: the constructor sets
111n/a # instance attributes 'preprocessor', 'compiler', etc. from them, and
112n/a # 'set_executable()' allows any of these to be set. The defaults here
113n/a # are pretty generic; they will probably have to be set by an outsider
114n/a # (eg. using information discovered by the sysconfig about building
115n/a # Python extensions).
116n/a executables = {'preprocessor' : None,
117n/a 'compiler' : ["cc"],
118n/a 'compiler_so' : ["cc"],
119n/a 'compiler_cxx' : ["cc"],
120n/a 'linker_so' : ["cc", "-shared"],
121n/a 'linker_exe' : ["cc"],
122n/a 'archiver' : ["ar", "-cr"],
123n/a 'ranlib' : None,
124n/a }
125n/a
126n/a if sys.platform[:6] == "darwin":
127n/a executables['ranlib'] = ["ranlib"]
128n/a
129n/a # Needed for the filename generation methods provided by the base
130n/a # class, CCompiler. XXX whoever instantiates/uses a particular
131n/a # UnixCCompiler instance should set 'shared_lib_ext' -- we set a
132n/a # reasonable common default here, but it's not necessarily used on all
133n/a # Unices!
134n/a
135n/a src_extensions = [".c",".C",".cc",".cxx",".cpp",".m"]
136n/a obj_extension = ".o"
137n/a static_lib_extension = ".a"
138n/a shared_lib_extension = ".so"
139n/a dylib_lib_extension = ".dylib"
140n/a static_lib_format = shared_lib_format = dylib_lib_format = "lib%s%s"
141n/a if sys.platform == "cygwin":
142n/a exe_extension = ".exe"
143n/a
144n/a def preprocess(self, source,
145n/a output_file=None, macros=None, include_dirs=None,
146n/a extra_preargs=None, extra_postargs=None):
147n/a ignore, macros, include_dirs = \
148n/a self._fix_compile_args(None, macros, include_dirs)
149n/a pp_opts = gen_preprocess_options(macros, include_dirs)
150n/a pp_args = self.preprocessor + pp_opts
151n/a if output_file:
152n/a pp_args.extend(('-o', output_file))
153n/a if extra_preargs:
154n/a pp_args[:0] = extra_preargs
155n/a if extra_postargs:
156n/a pp_args.extend(extra_postargs)
157n/a pp_args.append(source)
158n/a
159n/a # We need to preprocess: either we're being forced to, or we're
160n/a # generating output to stdout, or there's a target output file and
161n/a # the source file is newer than the target (or the target doesn't
162n/a # exist).
163n/a if self.force or output_file is None or newer(source, output_file):
164n/a if output_file:
165n/a self.mkpath(os.path.dirname(output_file))
166n/a try:
167n/a self.spawn(pp_args)
168n/a except PackagingExecError as msg:
169n/a raise CompileError(msg)
170n/a
171n/a def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
172n/a compiler_so = self.compiler_so
173n/a if sys.platform == 'darwin':
174n/a compiler_so = _darwin_compiler_fixup(compiler_so, cc_args + extra_postargs)
175n/a try:
176n/a self.spawn(compiler_so + cc_args + [src, '-o', obj] +
177n/a extra_postargs)
178n/a except PackagingExecError as msg:
179n/a raise CompileError(msg)
180n/a
181n/a def create_static_lib(self, objects, output_libname,
182n/a output_dir=None, debug=False, target_lang=None):
183n/a objects, output_dir = self._fix_object_args(objects, output_dir)
184n/a
185n/a output_filename = \
186n/a self.library_filename(output_libname, output_dir=output_dir)
187n/a
188n/a if self._need_link(objects, output_filename):
189n/a self.mkpath(os.path.dirname(output_filename))
190n/a self.spawn(self.archiver +
191n/a [output_filename] +
192n/a objects + self.objects)
193n/a
194n/a # Not many Unices required ranlib anymore -- SunOS 4.x is, I
195n/a # think the only major Unix that does. Maybe we need some
196n/a # platform intelligence here to skip ranlib if it's not
197n/a # needed -- or maybe Python's configure script took care of
198n/a # it for us, hence the check for leading colon.
199n/a if self.ranlib:
200n/a try:
201n/a self.spawn(self.ranlib + [output_filename])
202n/a except PackagingExecError as msg:
203n/a raise LibError(msg)
204n/a else:
205n/a logger.debug("skipping %s (up-to-date)", output_filename)
206n/a
207n/a def link(self, target_desc, objects,
208n/a output_filename, output_dir=None, libraries=None,
209n/a library_dirs=None, runtime_library_dirs=None,
210n/a export_symbols=None, debug=False, extra_preargs=None,
211n/a extra_postargs=None, build_temp=None, target_lang=None):
212n/a objects, output_dir = self._fix_object_args(objects, output_dir)
213n/a libraries, library_dirs, runtime_library_dirs = \
214n/a self._fix_lib_args(libraries, library_dirs, runtime_library_dirs)
215n/a
216n/a lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs,
217n/a libraries)
218n/a if type(output_dir) not in (str, type(None)):
219n/a raise TypeError("'output_dir' must be a string or None")
220n/a if output_dir is not None:
221n/a output_filename = os.path.join(output_dir, output_filename)
222n/a
223n/a if self._need_link(objects, output_filename):
224n/a ld_args = (objects + self.objects +
225n/a lib_opts + ['-o', output_filename])
226n/a if debug:
227n/a ld_args[:0] = ['-g']
228n/a if extra_preargs:
229n/a ld_args[:0] = extra_preargs
230n/a if extra_postargs:
231n/a ld_args.extend(extra_postargs)
232n/a self.mkpath(os.path.dirname(output_filename))
233n/a try:
234n/a if target_desc == CCompiler.EXECUTABLE:
235n/a linker = self.linker_exe[:]
236n/a else:
237n/a linker = self.linker_so[:]
238n/a if target_lang == "c++" and self.compiler_cxx:
239n/a # skip over environment variable settings if /usr/bin/env
240n/a # is used to set up the linker's environment.
241n/a # This is needed on OSX. Note: this assumes that the
242n/a # normal and C++ compiler have the same environment
243n/a # settings.
244n/a i = 0
245n/a if os.path.basename(linker[0]) == "env":
246n/a i = 1
247n/a while '=' in linker[i]:
248n/a i = i + 1
249n/a
250n/a linker[i] = self.compiler_cxx[i]
251n/a
252n/a if sys.platform == 'darwin':
253n/a linker = _darwin_compiler_fixup(linker, ld_args)
254n/a
255n/a self.spawn(linker + ld_args)
256n/a except PackagingExecError as msg:
257n/a raise LinkError(msg)
258n/a else:
259n/a logger.debug("skipping %s (up-to-date)", output_filename)
260n/a
261n/a # -- Miscellaneous methods -----------------------------------------
262n/a # These are all used by the 'gen_lib_options() function, in
263n/a # ccompiler.py.
264n/a
265n/a def library_dir_option(self, dir):
266n/a return "-L" + dir
267n/a
268n/a def _is_gcc(self, compiler_name):
269n/a return "gcc" in compiler_name or "g++" in compiler_name
270n/a
271n/a def runtime_library_dir_option(self, dir):
272n/a # XXX Hackish, at the very least. See Python bug #445902:
273n/a # http://sourceforge.net/tracker/index.php
274n/a # ?func=detail&aid=445902&group_id=5470&atid=105470
275n/a # Linkers on different platforms need different options to
276n/a # specify that directories need to be added to the list of
277n/a # directories searched for dependencies when a dynamic library
278n/a # is sought. GCC on GNU systems (Linux, FreeBSD, ...) has to
279n/a # be told to pass the -R option through to the linker, whereas
280n/a # other compilers and gcc on other systems just know this.
281n/a # Other compilers may need something slightly different. At
282n/a # this time, there's no way to determine this information from
283n/a # the configuration data stored in the Python installation, so
284n/a # we use this hack.
285n/a
286n/a compiler = os.path.basename(sysconfig.get_config_var("CC"))
287n/a if sys.platform[:6] == "darwin":
288n/a # MacOSX's linker doesn't understand the -R flag at all
289n/a return "-L" + dir
290n/a elif sys.platform[:5] == "hp-ux":
291n/a if self._is_gcc(compiler):
292n/a return ["-Wl,+s", "-L" + dir]
293n/a return ["+s", "-L" + dir]
294n/a elif sys.platform[:7] == "irix646" or sys.platform[:6] == "osf1V5":
295n/a return ["-rpath", dir]
296n/a elif self._is_gcc(compiler):
297n/a # gcc on non-GNU systems does not need -Wl, but can
298n/a # use it anyway. Since distutils has always passed in
299n/a # -Wl whenever gcc was used in the past it is probably
300n/a # safest to keep doing so.
301n/a if sysconfig.get_config_var("GNULD") == "yes":
302n/a # GNU ld needs an extra option to get a RUNPATH
303n/a # instead of just an RPATH.
304n/a return "-Wl,--enable-new-dtags,-R" + dir
305n/a else:
306n/a return "-Wl,-R" + dir
307n/a elif sys.platform[:3] == "aix":
308n/a return "-blibpath:" + dir
309n/a else:
310n/a # No idea how --enable-new-dtags would be passed on to
311n/a # ld if this system was using GNU ld. Don't know if a
312n/a # system like this even exists.
313n/a return "-R" + dir
314n/a
315n/a def library_option(self, lib):
316n/a return "-l" + lib
317n/a
318n/a def find_library_file(self, dirs, lib, debug=False):
319n/a shared_f = self.library_filename(lib, lib_type='shared')
320n/a dylib_f = self.library_filename(lib, lib_type='dylib')
321n/a static_f = self.library_filename(lib, lib_type='static')
322n/a
323n/a for dir in dirs:
324n/a shared = os.path.join(dir, shared_f)
325n/a dylib = os.path.join(dir, dylib_f)
326n/a static = os.path.join(dir, static_f)
327n/a # We're second-guessing the linker here, with not much hard
328n/a # data to go on: GCC seems to prefer the shared library, so I'm
329n/a # assuming that *all* Unix C compilers do. And of course I'm
330n/a # ignoring even GCC's "-static" option. So sue me.
331n/a if os.path.exists(dylib):
332n/a return dylib
333n/a elif os.path.exists(shared):
334n/a return shared
335n/a elif os.path.exists(static):
336n/a return static
337n/a
338n/a # Oops, didn't find it in *any* of 'dirs'
339n/a return None