Path: blob/master/venv/Lib/site-packages/setuptools/_distutils/cygwinccompiler.py
811 views
"""distutils.cygwinccompiler12Provides the CygwinCCompiler class, a subclass of UnixCCompiler that3handles the Cygwin port of the GNU C compiler to Windows. It also contains4the Mingw32CCompiler class which handles the mingw32 port of GCC (same as5cygwin in no-cygwin mode).6"""78# problems:9#10# * if you use a msvc compiled python version (1.5.2)11# 1. you have to insert a __GNUC__ section in its config.h12# 2. you have to generate an import library for its dll13# - create a def-file for python??.dll14# - create an import library using15# dlltool --dllname python15.dll --def python15.def \16# --output-lib libpython15.a17#18# see also http://starship.python.net/crew/kernr/mingw32/Notes.html19#20# * We put export_symbols in a def-file, and don't use21# --export-all-symbols because it doesn't worked reliable in some22# tested configurations. And because other windows compilers also23# need their symbols specified this no serious problem.24#25# tested configurations:26#27# * cygwin gcc 2.91.57/ld 2.9.4/dllwrap 0.2.4 works28# (after patching python's config.h and for C++ some other include files)29# see also http://starship.python.net/crew/kernr/mingw32/Notes.html30# * mingw32 gcc 2.95.2/ld 2.9.4/dllwrap 0.2.4 works31# (ld doesn't support -shared, so we use dllwrap)32# * cygwin gcc 2.95.2/ld 2.10.90/dllwrap 2.10.90 works now33# - its dllwrap doesn't work, there is a bug in binutils 2.10.9034# see also http://sources.redhat.com/ml/cygwin/2000-06/msg01274.html35# - using gcc -mdll instead dllwrap doesn't work without -static because36# it tries to link against dlls instead their import libraries. (If37# it finds the dll first.)38# By specifying -static we force ld to link against the import libraries,39# this is windows standard and there are normally not the necessary symbols40# in the dlls.41# *** only the version of June 2000 shows these problems42# * cygwin gcc 3.2/ld 2.13.90 works43# (ld supports -shared)44# * mingw gcc 3.2/ld 2.13 works45# (ld supports -shared)4647import os48import sys49import copy50from subprocess import Popen, PIPE, check_output51import re5253from distutils.unixccompiler import UnixCCompiler54from distutils.file_util import write_file55from distutils.errors import (DistutilsExecError, CCompilerError,56CompileError, UnknownFileError)57from distutils.version import LooseVersion58from distutils.spawn import find_executable5960def get_msvcr():61"""Include the appropriate MSVC runtime library if Python was built62with MSVC 7.0 or later.63"""64msc_pos = sys.version.find('MSC v.')65if msc_pos != -1:66msc_ver = sys.version[msc_pos+6:msc_pos+10]67if msc_ver == '1300':68# MSVC 7.069return ['msvcr70']70elif msc_ver == '1310':71# MSVC 7.172return ['msvcr71']73elif msc_ver == '1400':74# VS2005 / MSVC 8.075return ['msvcr80']76elif msc_ver == '1500':77# VS2008 / MSVC 9.078return ['msvcr90']79elif msc_ver == '1600':80# VS2010 / MSVC 10.081return ['msvcr100']82else:83raise ValueError("Unknown MS Compiler version %s " % msc_ver)848586class CygwinCCompiler(UnixCCompiler):87""" Handles the Cygwin port of the GNU C compiler to Windows.88"""89compiler_type = 'cygwin'90obj_extension = ".o"91static_lib_extension = ".a"92shared_lib_extension = ".dll"93static_lib_format = "lib%s%s"94shared_lib_format = "%s%s"95exe_extension = ".exe"9697def __init__(self, verbose=0, dry_run=0, force=0):9899UnixCCompiler.__init__(self, verbose, dry_run, force)100101status, details = check_config_h()102self.debug_print("Python's GCC status: %s (details: %s)" %103(status, details))104if status is not CONFIG_H_OK:105self.warn(106"Python's pyconfig.h doesn't seem to support your compiler. "107"Reason: %s. "108"Compiling may fail because of undefined preprocessor macros."109% details)110111self.gcc_version, self.ld_version, self.dllwrap_version = \112get_versions()113self.debug_print(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" %114(self.gcc_version,115self.ld_version,116self.dllwrap_version) )117118# ld_version >= "2.10.90" and < "2.13" should also be able to use119# gcc -mdll instead of dllwrap120# Older dllwraps had own version numbers, newer ones use the121# same as the rest of binutils ( also ld )122# dllwrap 2.10.90 is buggy123if self.ld_version >= "2.10.90":124self.linker_dll = "gcc"125else:126self.linker_dll = "dllwrap"127128# ld_version >= "2.13" support -shared so use it instead of129# -mdll -static130if self.ld_version >= "2.13":131shared_option = "-shared"132else:133shared_option = "-mdll -static"134135# Hard-code GCC because that's what this is all about.136# XXX optimization, warnings etc. should be customizable.137self.set_executables(compiler='gcc -mcygwin -O -Wall',138compiler_so='gcc -mcygwin -mdll -O -Wall',139compiler_cxx='g++ -mcygwin -O -Wall',140linker_exe='gcc -mcygwin',141linker_so=('%s -mcygwin %s' %142(self.linker_dll, shared_option)))143144# cygwin and mingw32 need different sets of libraries145if self.gcc_version == "2.91.57":146# cygwin shouldn't need msvcrt, but without the dlls will crash147# (gcc version 2.91.57) -- perhaps something about initialization148self.dll_libraries=["msvcrt"]149self.warn(150"Consider upgrading to a newer version of gcc")151else:152# Include the appropriate MSVC runtime library if Python was built153# with MSVC 7.0 or later.154self.dll_libraries = get_msvcr()155156def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):157"""Compiles the source by spawning GCC and windres if needed."""158if ext == '.rc' or ext == '.res':159# gcc needs '.res' and '.rc' compiled to object files !!!160try:161self.spawn(["windres", "-i", src, "-o", obj])162except DistutilsExecError as msg:163raise CompileError(msg)164else: # for other files use the C-compiler165try:166self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +167extra_postargs)168except DistutilsExecError as msg:169raise CompileError(msg)170171def link(self, target_desc, objects, output_filename, output_dir=None,172libraries=None, library_dirs=None, runtime_library_dirs=None,173export_symbols=None, debug=0, extra_preargs=None,174extra_postargs=None, build_temp=None, target_lang=None):175"""Link the objects."""176# use separate copies, so we can modify the lists177extra_preargs = copy.copy(extra_preargs or [])178libraries = copy.copy(libraries or [])179objects = copy.copy(objects or [])180181# Additional libraries182libraries.extend(self.dll_libraries)183184# handle export symbols by creating a def-file185# with executables this only works with gcc/ld as linker186if ((export_symbols is not None) and187(target_desc != self.EXECUTABLE or self.linker_dll == "gcc")):188# (The linker doesn't do anything if output is up-to-date.189# So it would probably better to check if we really need this,190# but for this we had to insert some unchanged parts of191# UnixCCompiler, and this is not what we want.)192193# we want to put some files in the same directory as the194# object files are, build_temp doesn't help much195# where are the object files196temp_dir = os.path.dirname(objects[0])197# name of dll to give the helper files the same base name198(dll_name, dll_extension) = os.path.splitext(199os.path.basename(output_filename))200201# generate the filenames for these files202def_file = os.path.join(temp_dir, dll_name + ".def")203lib_file = os.path.join(temp_dir, 'lib' + dll_name + ".a")204205# Generate .def file206contents = [207"LIBRARY %s" % os.path.basename(output_filename),208"EXPORTS"]209for sym in export_symbols:210contents.append(sym)211self.execute(write_file, (def_file, contents),212"writing %s" % def_file)213214# next add options for def-file and to creating import libraries215216# dllwrap uses different options than gcc/ld217if self.linker_dll == "dllwrap":218extra_preargs.extend(["--output-lib", lib_file])219# for dllwrap we have to use a special option220extra_preargs.extend(["--def", def_file])221# we use gcc/ld here and can be sure ld is >= 2.9.10222else:223# doesn't work: bfd_close build\...\libfoo.a: Invalid operation224#extra_preargs.extend(["-Wl,--out-implib,%s" % lib_file])225# for gcc/ld the def-file is specified as any object files226objects.append(def_file)227228#end: if ((export_symbols is not None) and229# (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")):230231# who wants symbols and a many times larger output file232# should explicitly switch the debug mode on233# otherwise we let dllwrap/ld strip the output file234# (On my machine: 10KiB < stripped_file < ??100KiB235# unstripped_file = stripped_file + XXX KiB236# ( XXX=254 for a typical python extension))237if not debug:238extra_preargs.append("-s")239240UnixCCompiler.link(self, target_desc, objects, output_filename,241output_dir, libraries, library_dirs,242runtime_library_dirs,243None, # export_symbols, we do this in our def-file244debug, extra_preargs, extra_postargs, build_temp,245target_lang)246247# -- Miscellaneous methods -----------------------------------------248249def object_filenames(self, source_filenames, strip_dir=0, output_dir=''):250"""Adds supports for rc and res files."""251if output_dir is None:252output_dir = ''253obj_names = []254for src_name in source_filenames:255# use normcase to make sure '.rc' is really '.rc' and not '.RC'256base, ext = os.path.splitext(os.path.normcase(src_name))257if ext not in (self.src_extensions + ['.rc','.res']):258raise UnknownFileError("unknown file type '%s' (from '%s')" % \259(ext, src_name))260if strip_dir:261base = os.path.basename (base)262if ext in ('.res', '.rc'):263# these need to be compiled to object files264obj_names.append (os.path.join(output_dir,265base + ext + self.obj_extension))266else:267obj_names.append (os.path.join(output_dir,268base + self.obj_extension))269return obj_names270271# the same as cygwin plus some additional parameters272class Mingw32CCompiler(CygwinCCompiler):273""" Handles the Mingw32 port of the GNU C compiler to Windows.274"""275compiler_type = 'mingw32'276277def __init__(self, verbose=0, dry_run=0, force=0):278279CygwinCCompiler.__init__ (self, verbose, dry_run, force)280281# ld_version >= "2.13" support -shared so use it instead of282# -mdll -static283if self.ld_version >= "2.13":284shared_option = "-shared"285else:286shared_option = "-mdll -static"287288# A real mingw32 doesn't need to specify a different entry point,289# but cygwin 2.91.57 in no-cygwin-mode needs it.290if self.gcc_version <= "2.91.57":291entry_point = '--entry _DllMain@12'292else:293entry_point = ''294295if is_cygwingcc():296raise CCompilerError(297'Cygwin gcc cannot be used with --compiler=mingw32')298299self.set_executables(compiler='gcc -O -Wall',300compiler_so='gcc -mdll -O -Wall',301compiler_cxx='g++ -O -Wall',302linker_exe='gcc',303linker_so='%s %s %s'304% (self.linker_dll, shared_option,305entry_point))306# Maybe we should also append -mthreads, but then the finished307# dlls need another dll (mingwm10.dll see Mingw32 docs)308# (-mthreads: Support thread-safe exception handling on `Mingw32')309310# no additional libraries needed311self.dll_libraries=[]312313# Include the appropriate MSVC runtime library if Python was built314# with MSVC 7.0 or later.315self.dll_libraries = get_msvcr()316317# Because these compilers aren't configured in Python's pyconfig.h file by318# default, we should at least warn the user if he is using an unmodified319# version.320321CONFIG_H_OK = "ok"322CONFIG_H_NOTOK = "not ok"323CONFIG_H_UNCERTAIN = "uncertain"324325def check_config_h():326"""Check if the current Python installation appears amenable to building327extensions with GCC.328329Returns a tuple (status, details), where 'status' is one of the following330constants:331332- CONFIG_H_OK: all is well, go ahead and compile333- CONFIG_H_NOTOK: doesn't look good334- CONFIG_H_UNCERTAIN: not sure -- unable to read pyconfig.h335336'details' is a human-readable string explaining the situation.337338Note there are two ways to conclude "OK": either 'sys.version' contains339the string "GCC" (implying that this Python was built with GCC), or the340installed "pyconfig.h" contains the string "__GNUC__".341"""342343# XXX since this function also checks sys.version, it's not strictly a344# "pyconfig.h" check -- should probably be renamed...345346from distutils import sysconfig347348# if sys.version contains GCC then python was compiled with GCC, and the349# pyconfig.h file should be OK350if "GCC" in sys.version:351return CONFIG_H_OK, "sys.version mentions 'GCC'"352353# let's see if __GNUC__ is mentioned in python.h354fn = sysconfig.get_config_h_filename()355try:356config_h = open(fn)357try:358if "__GNUC__" in config_h.read():359return CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn360else:361return CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn362finally:363config_h.close()364except OSError as exc:365return (CONFIG_H_UNCERTAIN,366"couldn't read '%s': %s" % (fn, exc.strerror))367368RE_VERSION = re.compile(br'(\d+\.\d+(\.\d+)*)')369370def _find_exe_version(cmd):371"""Find the version of an executable by running `cmd` in the shell.372373If the command is not found, or the output does not match374`RE_VERSION`, returns None.375"""376executable = cmd.split()[0]377if find_executable(executable) is None:378return None379out = Popen(cmd, shell=True, stdout=PIPE).stdout380try:381out_string = out.read()382finally:383out.close()384result = RE_VERSION.search(out_string)385if result is None:386return None387# LooseVersion works with strings388# so we need to decode our bytes389return LooseVersion(result.group(1).decode())390391def get_versions():392""" Try to find out the versions of gcc, ld and dllwrap.393394If not possible it returns None for it.395"""396commands = ['gcc -dumpversion', 'ld -v', 'dllwrap --version']397return tuple([_find_exe_version(cmd) for cmd in commands])398399def is_cygwingcc():400'''Try to determine if the gcc that would be used is from cygwin.'''401out_string = check_output(['gcc', '-dumpmachine'])402return out_string.strip().endswith(b'cygwin')403404405