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

Python code coverage for Lib/distutils/cygwinccompiler.py

#countcontent
1n/a"""distutils.cygwinccompiler
2n/a
3n/aProvides the CygwinCCompiler class, a subclass of UnixCCompiler that
4n/ahandles the Cygwin port of the GNU C compiler to Windows. It also contains
5n/athe Mingw32CCompiler class which handles the mingw32 port of GCC (same as
6n/acygwin in no-cygwin mode).
7n/a"""
8n/a
9n/a# problems:
10n/a#
11n/a# * if you use a msvc compiled python version (1.5.2)
12n/a# 1. you have to insert a __GNUC__ section in its config.h
13n/a# 2. you have to generate an import library for its dll
14n/a# - create a def-file for python??.dll
15n/a# - create an import library using
16n/a# dlltool --dllname python15.dll --def python15.def \
17n/a# --output-lib libpython15.a
18n/a#
19n/a# see also http://starship.python.net/crew/kernr/mingw32/Notes.html
20n/a#
21n/a# * We put export_symbols in a def-file, and don't use
22n/a# --export-all-symbols because it doesn't worked reliable in some
23n/a# tested configurations. And because other windows compilers also
24n/a# need their symbols specified this no serious problem.
25n/a#
26n/a# tested configurations:
27n/a#
28n/a# * cygwin gcc 2.91.57/ld 2.9.4/dllwrap 0.2.4 works
29n/a# (after patching python's config.h and for C++ some other include files)
30n/a# see also http://starship.python.net/crew/kernr/mingw32/Notes.html
31n/a# * mingw32 gcc 2.95.2/ld 2.9.4/dllwrap 0.2.4 works
32n/a# (ld doesn't support -shared, so we use dllwrap)
33n/a# * cygwin gcc 2.95.2/ld 2.10.90/dllwrap 2.10.90 works now
34n/a# - its dllwrap doesn't work, there is a bug in binutils 2.10.90
35n/a# see also http://sources.redhat.com/ml/cygwin/2000-06/msg01274.html
36n/a# - using gcc -mdll instead dllwrap doesn't work without -static because
37n/a# it tries to link against dlls instead their import libraries. (If
38n/a# it finds the dll first.)
39n/a# By specifying -static we force ld to link against the import libraries,
40n/a# this is windows standard and there are normally not the necessary symbols
41n/a# in the dlls.
42n/a# *** only the version of June 2000 shows these problems
43n/a# * cygwin gcc 3.2/ld 2.13.90 works
44n/a# (ld supports -shared)
45n/a# * mingw gcc 3.2/ld 2.13 works
46n/a# (ld supports -shared)
47n/a
48n/aimport os
49n/aimport sys
50n/aimport copy
51n/afrom subprocess import Popen, PIPE, check_output
52n/aimport re
53n/a
54n/afrom distutils.ccompiler import gen_preprocess_options, gen_lib_options
55n/afrom distutils.unixccompiler import UnixCCompiler
56n/afrom distutils.file_util import write_file
57n/afrom distutils.errors import (DistutilsExecError, CCompilerError,
58n/a CompileError, UnknownFileError)
59n/afrom distutils import log
60n/afrom distutils.version import LooseVersion
61n/afrom distutils.spawn import find_executable
62n/a
63n/adef get_msvcr():
64n/a """Include the appropriate MSVC runtime library if Python was built
65n/a with MSVC 7.0 or later.
66n/a """
67n/a msc_pos = sys.version.find('MSC v.')
68n/a if msc_pos != -1:
69n/a msc_ver = sys.version[msc_pos+6:msc_pos+10]
70n/a if msc_ver == '1300':
71n/a # MSVC 7.0
72n/a return ['msvcr70']
73n/a elif msc_ver == '1310':
74n/a # MSVC 7.1
75n/a return ['msvcr71']
76n/a elif msc_ver == '1400':
77n/a # VS2005 / MSVC 8.0
78n/a return ['msvcr80']
79n/a elif msc_ver == '1500':
80n/a # VS2008 / MSVC 9.0
81n/a return ['msvcr90']
82n/a elif msc_ver == '1600':
83n/a # VS2010 / MSVC 10.0
84n/a return ['msvcr100']
85n/a else:
86n/a raise ValueError("Unknown MS Compiler version %s " % msc_ver)
87n/a
88n/a
89n/aclass CygwinCCompiler(UnixCCompiler):
90n/a """ Handles the Cygwin port of the GNU C compiler to Windows.
91n/a """
92n/a compiler_type = 'cygwin'
93n/a obj_extension = ".o"
94n/a static_lib_extension = ".a"
95n/a shared_lib_extension = ".dll"
96n/a static_lib_format = "lib%s%s"
97n/a shared_lib_format = "%s%s"
98n/a exe_extension = ".exe"
99n/a
100n/a def __init__(self, verbose=0, dry_run=0, force=0):
101n/a
102n/a UnixCCompiler.__init__(self, verbose, dry_run, force)
103n/a
104n/a status, details = check_config_h()
105n/a self.debug_print("Python's GCC status: %s (details: %s)" %
106n/a (status, details))
107n/a if status is not CONFIG_H_OK:
108n/a self.warn(
109n/a "Python's pyconfig.h doesn't seem to support your compiler. "
110n/a "Reason: %s. "
111n/a "Compiling may fail because of undefined preprocessor macros."
112n/a % details)
113n/a
114n/a self.gcc_version, self.ld_version, self.dllwrap_version = \
115n/a get_versions()
116n/a self.debug_print(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" %
117n/a (self.gcc_version,
118n/a self.ld_version,
119n/a self.dllwrap_version) )
120n/a
121n/a # ld_version >= "2.10.90" and < "2.13" should also be able to use
122n/a # gcc -mdll instead of dllwrap
123n/a # Older dllwraps had own version numbers, newer ones use the
124n/a # same as the rest of binutils ( also ld )
125n/a # dllwrap 2.10.90 is buggy
126n/a if self.ld_version >= "2.10.90":
127n/a self.linker_dll = "gcc"
128n/a else:
129n/a self.linker_dll = "dllwrap"
130n/a
131n/a # ld_version >= "2.13" support -shared so use it instead of
132n/a # -mdll -static
133n/a if self.ld_version >= "2.13":
134n/a shared_option = "-shared"
135n/a else:
136n/a shared_option = "-mdll -static"
137n/a
138n/a # Hard-code GCC because that's what this is all about.
139n/a # XXX optimization, warnings etc. should be customizable.
140n/a self.set_executables(compiler='gcc -mcygwin -O -Wall',
141n/a compiler_so='gcc -mcygwin -mdll -O -Wall',
142n/a compiler_cxx='g++ -mcygwin -O -Wall',
143n/a linker_exe='gcc -mcygwin',
144n/a linker_so=('%s -mcygwin %s' %
145n/a (self.linker_dll, shared_option)))
146n/a
147n/a # cygwin and mingw32 need different sets of libraries
148n/a if self.gcc_version == "2.91.57":
149n/a # cygwin shouldn't need msvcrt, but without the dlls will crash
150n/a # (gcc version 2.91.57) -- perhaps something about initialization
151n/a self.dll_libraries=["msvcrt"]
152n/a self.warn(
153n/a "Consider upgrading to a newer version of gcc")
154n/a else:
155n/a # Include the appropriate MSVC runtime library if Python was built
156n/a # with MSVC 7.0 or later.
157n/a self.dll_libraries = get_msvcr()
158n/a
159n/a def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
160n/a """Compiles the source by spawning GCC and windres if needed."""
161n/a if ext == '.rc' or ext == '.res':
162n/a # gcc needs '.res' and '.rc' compiled to object files !!!
163n/a try:
164n/a self.spawn(["windres", "-i", src, "-o", obj])
165n/a except DistutilsExecError as msg:
166n/a raise CompileError(msg)
167n/a else: # for other files use the C-compiler
168n/a try:
169n/a self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
170n/a extra_postargs)
171n/a except DistutilsExecError as msg:
172n/a raise CompileError(msg)
173n/a
174n/a def link(self, target_desc, objects, output_filename, output_dir=None,
175n/a libraries=None, library_dirs=None, runtime_library_dirs=None,
176n/a export_symbols=None, debug=0, extra_preargs=None,
177n/a extra_postargs=None, build_temp=None, target_lang=None):
178n/a """Link the objects."""
179n/a # use separate copies, so we can modify the lists
180n/a extra_preargs = copy.copy(extra_preargs or [])
181n/a libraries = copy.copy(libraries or [])
182n/a objects = copy.copy(objects or [])
183n/a
184n/a # Additional libraries
185n/a libraries.extend(self.dll_libraries)
186n/a
187n/a # handle export symbols by creating a def-file
188n/a # with executables this only works with gcc/ld as linker
189n/a if ((export_symbols is not None) and
190n/a (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")):
191n/a # (The linker doesn't do anything if output is up-to-date.
192n/a # So it would probably better to check if we really need this,
193n/a # but for this we had to insert some unchanged parts of
194n/a # UnixCCompiler, and this is not what we want.)
195n/a
196n/a # we want to put some files in the same directory as the
197n/a # object files are, build_temp doesn't help much
198n/a # where are the object files
199n/a temp_dir = os.path.dirname(objects[0])
200n/a # name of dll to give the helper files the same base name
201n/a (dll_name, dll_extension) = os.path.splitext(
202n/a os.path.basename(output_filename))
203n/a
204n/a # generate the filenames for these files
205n/a def_file = os.path.join(temp_dir, dll_name + ".def")
206n/a lib_file = os.path.join(temp_dir, 'lib' + dll_name + ".a")
207n/a
208n/a # Generate .def file
209n/a contents = [
210n/a "LIBRARY %s" % os.path.basename(output_filename),
211n/a "EXPORTS"]
212n/a for sym in export_symbols:
213n/a contents.append(sym)
214n/a self.execute(write_file, (def_file, contents),
215n/a "writing %s" % def_file)
216n/a
217n/a # next add options for def-file and to creating import libraries
218n/a
219n/a # dllwrap uses different options than gcc/ld
220n/a if self.linker_dll == "dllwrap":
221n/a extra_preargs.extend(["--output-lib", lib_file])
222n/a # for dllwrap we have to use a special option
223n/a extra_preargs.extend(["--def", def_file])
224n/a # we use gcc/ld here and can be sure ld is >= 2.9.10
225n/a else:
226n/a # doesn't work: bfd_close build\...\libfoo.a: Invalid operation
227n/a #extra_preargs.extend(["-Wl,--out-implib,%s" % lib_file])
228n/a # for gcc/ld the def-file is specified as any object files
229n/a objects.append(def_file)
230n/a
231n/a #end: if ((export_symbols is not None) and
232n/a # (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")):
233n/a
234n/a # who wants symbols and a many times larger output file
235n/a # should explicitly switch the debug mode on
236n/a # otherwise we let dllwrap/ld strip the output file
237n/a # (On my machine: 10KB < stripped_file < ??100KB
238n/a # unstripped_file = stripped_file + XXX KB
239n/a # ( XXX=254 for a typical python extension))
240n/a if not debug:
241n/a extra_preargs.append("-s")
242n/a
243n/a UnixCCompiler.link(self, target_desc, objects, output_filename,
244n/a output_dir, libraries, library_dirs,
245n/a runtime_library_dirs,
246n/a None, # export_symbols, we do this in our def-file
247n/a debug, extra_preargs, extra_postargs, build_temp,
248n/a target_lang)
249n/a
250n/a # -- Miscellaneous methods -----------------------------------------
251n/a
252n/a def object_filenames(self, source_filenames, strip_dir=0, output_dir=''):
253n/a """Adds supports for rc and res files."""
254n/a if output_dir is None:
255n/a output_dir = ''
256n/a obj_names = []
257n/a for src_name in source_filenames:
258n/a # use normcase to make sure '.rc' is really '.rc' and not '.RC'
259n/a base, ext = os.path.splitext(os.path.normcase(src_name))
260n/a if ext not in (self.src_extensions + ['.rc','.res']):
261n/a raise UnknownFileError("unknown file type '%s' (from '%s')" % \
262n/a (ext, src_name))
263n/a if strip_dir:
264n/a base = os.path.basename (base)
265n/a if ext in ('.res', '.rc'):
266n/a # these need to be compiled to object files
267n/a obj_names.append (os.path.join(output_dir,
268n/a base + ext + self.obj_extension))
269n/a else:
270n/a obj_names.append (os.path.join(output_dir,
271n/a base + self.obj_extension))
272n/a return obj_names
273n/a
274n/a# the same as cygwin plus some additional parameters
275n/aclass Mingw32CCompiler(CygwinCCompiler):
276n/a """ Handles the Mingw32 port of the GNU C compiler to Windows.
277n/a """
278n/a compiler_type = 'mingw32'
279n/a
280n/a def __init__(self, verbose=0, dry_run=0, force=0):
281n/a
282n/a CygwinCCompiler.__init__ (self, verbose, dry_run, force)
283n/a
284n/a # ld_version >= "2.13" support -shared so use it instead of
285n/a # -mdll -static
286n/a if self.ld_version >= "2.13":
287n/a shared_option = "-shared"
288n/a else:
289n/a shared_option = "-mdll -static"
290n/a
291n/a # A real mingw32 doesn't need to specify a different entry point,
292n/a # but cygwin 2.91.57 in no-cygwin-mode needs it.
293n/a if self.gcc_version <= "2.91.57":
294n/a entry_point = '--entry _DllMain@12'
295n/a else:
296n/a entry_point = ''
297n/a
298n/a if is_cygwingcc():
299n/a raise CCompilerError(
300n/a 'Cygwin gcc cannot be used with --compiler=mingw32')
301n/a
302n/a self.set_executables(compiler='gcc -O -Wall',
303n/a compiler_so='gcc -mdll -O -Wall',
304n/a compiler_cxx='g++ -O -Wall',
305n/a linker_exe='gcc',
306n/a linker_so='%s %s %s'
307n/a % (self.linker_dll, shared_option,
308n/a entry_point))
309n/a # Maybe we should also append -mthreads, but then the finished
310n/a # dlls need another dll (mingwm10.dll see Mingw32 docs)
311n/a # (-mthreads: Support thread-safe exception handling on `Mingw32')
312n/a
313n/a # no additional libraries needed
314n/a self.dll_libraries=[]
315n/a
316n/a # Include the appropriate MSVC runtime library if Python was built
317n/a # with MSVC 7.0 or later.
318n/a self.dll_libraries = get_msvcr()
319n/a
320n/a# Because these compilers aren't configured in Python's pyconfig.h file by
321n/a# default, we should at least warn the user if he is using an unmodified
322n/a# version.
323n/a
324n/aCONFIG_H_OK = "ok"
325n/aCONFIG_H_NOTOK = "not ok"
326n/aCONFIG_H_UNCERTAIN = "uncertain"
327n/a
328n/adef check_config_h():
329n/a """Check if the current Python installation appears amenable to building
330n/a extensions with GCC.
331n/a
332n/a Returns a tuple (status, details), where 'status' is one of the following
333n/a constants:
334n/a
335n/a - CONFIG_H_OK: all is well, go ahead and compile
336n/a - CONFIG_H_NOTOK: doesn't look good
337n/a - CONFIG_H_UNCERTAIN: not sure -- unable to read pyconfig.h
338n/a
339n/a 'details' is a human-readable string explaining the situation.
340n/a
341n/a Note there are two ways to conclude "OK": either 'sys.version' contains
342n/a the string "GCC" (implying that this Python was built with GCC), or the
343n/a installed "pyconfig.h" contains the string "__GNUC__".
344n/a """
345n/a
346n/a # XXX since this function also checks sys.version, it's not strictly a
347n/a # "pyconfig.h" check -- should probably be renamed...
348n/a
349n/a from distutils import sysconfig
350n/a
351n/a # if sys.version contains GCC then python was compiled with GCC, and the
352n/a # pyconfig.h file should be OK
353n/a if "GCC" in sys.version:
354n/a return CONFIG_H_OK, "sys.version mentions 'GCC'"
355n/a
356n/a # let's see if __GNUC__ is mentioned in python.h
357n/a fn = sysconfig.get_config_h_filename()
358n/a try:
359n/a config_h = open(fn)
360n/a try:
361n/a if "__GNUC__" in config_h.read():
362n/a return CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn
363n/a else:
364n/a return CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn
365n/a finally:
366n/a config_h.close()
367n/a except OSError as exc:
368n/a return (CONFIG_H_UNCERTAIN,
369n/a "couldn't read '%s': %s" % (fn, exc.strerror))
370n/a
371n/aRE_VERSION = re.compile(br'(\d+\.\d+(\.\d+)*)')
372n/a
373n/adef _find_exe_version(cmd):
374n/a """Find the version of an executable by running `cmd` in the shell.
375n/a
376n/a If the command is not found, or the output does not match
377n/a `RE_VERSION`, returns None.
378n/a """
379n/a executable = cmd.split()[0]
380n/a if find_executable(executable) is None:
381n/a return None
382n/a out = Popen(cmd, shell=True, stdout=PIPE).stdout
383n/a try:
384n/a out_string = out.read()
385n/a finally:
386n/a out.close()
387n/a result = RE_VERSION.search(out_string)
388n/a if result is None:
389n/a return None
390n/a # LooseVersion works with strings
391n/a # so we need to decode our bytes
392n/a return LooseVersion(result.group(1).decode())
393n/a
394n/adef get_versions():
395n/a """ Try to find out the versions of gcc, ld and dllwrap.
396n/a
397n/a If not possible it returns None for it.
398n/a """
399n/a commands = ['gcc -dumpversion', 'ld -v', 'dllwrap --version']
400n/a return tuple([_find_exe_version(cmd) for cmd in commands])
401n/a
402n/adef is_cygwingcc():
403n/a '''Try to determine if the gcc that would be used is from cygwin.'''
404n/a out_string = check_output(['gcc', '-dumpmachine'])
405n/a return out_string.strip().endswith(b'cygwin')