[gobject-introspection] giscanner/ccompiler.py: Initiate Distutils Compiler Instance



commit 0638f9f130fe080f945d07cde5cc01835a80553a
Author: Chun-wei Fan <fanchunwei src gnome org>
Date:   Thu Jul 30 10:58:59 2015 +0800

    giscanner/ccompiler.py: Initiate Distutils Compiler Instance
    
    This updates the __init__ constructor method of CCompiler so that distutils
    can be used, with some environment or user-supplied options to create the
    compiler instance that is appropriate with the platform that the giscanner
    scripts are being run on, and sets some specific environment for the
    compilers as necessary.  This also adds a check_is_msvc() method that will
    progressively replace calls in the other giscanner scripts that attempt to
    check for CC=cl (or so), where a part of which is done in this patch.  This
    is done for dumper.py as well as it needs to be updated in this patch to
    use the updated ccompiler.py which uses distutils to initiate the compiler
    instance.
    
    Also, as we have been using the --library option on Windows to pass in the
    library (not DLL) to deduce the correct DLL to link to in the introspection
    files for some time, we no longer need to make a copy of the library (.lib)
    to introspect that matches the <namespace>-<namespace_version>.lib
    convention, but use the libraries that were passed in with --library
    directly, so that we can link the dumper program during the introspection
    build.
    
    Please note that this also partially reverts commit c9cfa2b as the
    distutils items are clearly needed for these to work.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=728313

 giscanner/ccompiler.py |  136 +++++++++++++++++++++++++++++++----------------
 giscanner/dumper.py    |   55 ++++++++-----------
 2 files changed, 113 insertions(+), 78 deletions(-)
---
diff --git a/giscanner/ccompiler.py b/giscanner/ccompiler.py
index 2db535c..884fc2c 100644
--- a/giscanner/ccompiler.py
+++ b/giscanner/ccompiler.py
@@ -21,6 +21,13 @@
 import os
 import subprocess
 
+import sys
+import distutils
+
+from distutils.msvccompiler import MSVCCompiler
+from distutils.cygwinccompiler import Mingw32CCompiler
+from distutils.sysconfig import customize_compiler
+
 from . import utils
 
 
@@ -30,51 +37,85 @@ class CCompiler(object):
     compiler = None
     _cflags_no_deprecation_warnings = ''
 
-    def __init__(self, compiler_name=None):
-        pass
-
-    def get_internal_link_flags(self,
-                                args,
-                                libtool,
-                                libraries,
-                                libpaths,
-                                pkgconfig_msvc_flags,
-                                ns,
-                                ns_version):
+    def __init__(self,
+                 environ=os.environ,
+                 osname=os.name,
+                 compiler_name=None):
+
+        if osname == 'nt':
+            # The compiler used here on Windows may well not be
+            # the same compiler that was used to build Python,
+            # as the official Python binaries are built with
+            # Visual Studio
+            if compiler_name is None:
+                if environ.get('MSYSTEM') == 'MINGW32' or environ.get('MSYSTEM') == 'MINGW64':
+                    compiler_name = 'mingw32'
+                else:
+                    compiler_name = distutils.ccompiler.get_default_compiler()
+            if compiler_name != 'msvc' and \
+               compiler_name != 'mingw32':
+                raise SystemExit('Specified Compiler \'%s\' is unsupported.' % compiler_name)
+        else:
+            # XXX: Is it common practice to use a non-Unix compiler
+            #      class instance on non-Windows on platforms g-i supports?
+            compiler_name = distutils.ccompiler.get_default_compiler()
+
+        # Now, create the distutils ccompiler instance based on the info we have.
+        self.compiler = distutils.ccompiler.new_compiler(compiler=compiler_name)
+        customize_compiler(self.compiler)
+
+        # customize_compiler from distutils only does customization
+        # for 'unix' compiler type.  Also, avoid linking to msvcrxx.dll
+        # for MinGW builds as the dumper binary does not link to the
+        # Python DLL, but link to msvcrt.dll if necessary.
+        if isinstance(self.compiler, Mingw32CCompiler):
+            if self.compiler.dll_libraries != ['msvcrt']:
+                self.compiler.dll_libraries = []
+            if self.compiler.preprocessor is None:
+                self.compiler.preprocessor = self.compiler.compiler + ['-E']
+
+        if self.check_is_msvc():
+            # We trick distutils to believe that we are (always) using a
+            # compiler supplied by a Windows SDK, so that we avoid launching
+            # a new build environment to detect the compiler that is used to
+            # build Python itself, which is not desirable, so that we use the
+            # compiler commands (and env) as-is.
+            os.environ['DISTUTILS_USE_SDK'] = '1'
+            if 'MSSdk' not in os.environ:
+                if 'WindowsSDKDir' in os.environ:
+                    os.environ['MSSdk'] = os.environ.get('WindowsSDKDir')
+                elif os.environ.get('VCInstallDir'):
+                    os.environ['MSSdk'] = os.environ.get('VCInstallDir')
+
+            self.compiler_cmd = 'cl.exe'
+
+            self._cflags_no_deprecation_warnings = "-wd4996"
+        else:
+            if (isinstance(self.compiler, Mingw32CCompiler)):
+                self.compiler_cmd = self.compiler.compiler[0]
+            else:
+                self.compiler_cmd = ''.join(self.compiler.executables['compiler'])
+
+            self._cflags_no_deprecation_warnings = "-Wno-deprecated-declarations"
+
+    def get_internal_link_flags(self, args, libtool, libraries, libpaths):
         # An "internal" link is where the library to be introspected
         # is being built in the current directory.
 
         # Search the current directory first
         # (This flag is not supported nor needed for Visual C++)
-        if pkgconfig_msvc_flags == '':
+        if not self.check_is_msvc():
             args.append('-L.')
 
-        # https://bugzilla.gnome.org/show_bug.cgi?id=625195
-        if not libtool:
-            # We don't have -Wl,-rpath for Visual C++, and that's
-            # going to cause a problem.  Instead, link to internal
-            # libraries by deducing the .lib file name using
-            # the namespace name and version
-            if pkgconfig_msvc_flags:
-                if ns_version:
-                    args.append(str.lower(ns) +
-                                '-' +
-                                ns_version + '.lib')
-                else:
-                    args.append(str.lower(ns) + '.lib')
-            else:
+            # https://bugzilla.gnome.org/show_bug.cgi?id=625195
+            if not libtool:
                 args.append('-Wl,-rpath=.')
-
-        # Ensure libraries are always linked as we are going to use ldd to work
-        # out their names later
-        if not libtool and pkgconfig_msvc_flags == '':
-            args.append('-Wl,--no-as-needed')
+                args.append('-Wl,--no-as-needed')
 
         for library in libraries:
-            # Visual C++: We have the needed .lib files now, and we need to link
-            # to .lib files, not the .dll as the --library option specifies the
-            # .dll(s) the .gir file refers to
-            if pkgconfig_msvc_flags == '':
+            if self.check_is_msvc():
+                args.append(library + '.lib')
+            else:
                 if library.endswith(".la"):  # explicitly specified libtool library
                     args.append(library)
                 else:
@@ -83,7 +124,7 @@ class CCompiler(object):
         for library_path in libpaths:
             # Not used/needed on Visual C++, and -Wl,-rpath options
             # will cause grief
-            if pkgconfig_msvc_flags == '':
+            if not self.check_is_msvc():
                 args.append('-L' + library_path)
                 if os.path.isabs(library_path):
                     if libtool:
@@ -92,15 +133,15 @@ class CCompiler(object):
                     else:
                         args.append('-Wl,-rpath=' + library_path)
 
-    def get_external_link_flags(self, args, libraries, pkgconfig_msvc_flags):
+    def get_external_link_flags(self, args, libraries):
         # An "external" link is where the library to be introspected
         # is installed on the system; this case is used for the scanning
         # of GLib in gobject-introspection itself.
 
         for library in libraries:
-            # The --library option on Windows pass in the .dll file(s) the
-            # .gir files refer to, so don't link to them on Visual C++
-            if pkgconfig_msvc_flags == '':
+            if self.check_is_msvc():
+                args.append(library + '.lib')
+            else:
                 if library.endswith(".la"):  # explicitly specified libtool library
                     args.append(library)
                 else:
@@ -108,15 +149,13 @@ class CCompiler(object):
 
     def resolve_windows_libs(self, libraries, options):
         args = []
-        compiler_cmd = os.environ.get('CC', 'cc')
         libsearch = []
 
         # When we are using Visual C++...
-        if 'cl.exe' in compiler_cmd or 'cl' in compiler_cmd:
+        if self.check_is_msvc():
             # The search path of the .lib's on Visual C++
             # is dependent on the LIB environmental variable,
             # so just query for that
-            is_msvc = True
             libpath = os.environ.get('LIB')
             libsearch = libpath.split(';')
 
@@ -128,7 +167,6 @@ class CCompiler(object):
 
         # When we are not using Visual C++ (i.e. we are using GCC)...
         else:
-            is_msvc = False
             libtool = utils.get_libtool_command(options)
             if libtool:
                 args.append(utils.which(os.environ.get('SHELL', 'sh.exe')))
@@ -136,7 +174,7 @@ class CCompiler(object):
                 args.append('--mode=execute')
             # FIXME: it could have prefix (i686-w64-mingw32-dlltool.exe)
             args.extend(['dlltool.exe', '--identify'])
-            proc = subprocess.Popen([compiler_cmd, '-print-search-dirs'],
+            proc = subprocess.Popen([self.compiler_cmd, '-print-search-dirs'],
                                     stdout=subprocess.PIPE)
             o, e = proc.communicate()
             for line in o.splitlines():
@@ -168,7 +206,7 @@ class CCompiler(object):
                                                 stdout=subprocess.PIPE)
                         o, e = proc.communicate()
                         for line in o.splitlines():
-                            if is_msvc:
+                            if self.check_is_msvc():
                                 # On Visual Studio, dumpbin -symbols something.lib gives the
                                 # filename of DLL without the '.dll' extension that something.lib
                                 # links to, in the line that contains
@@ -194,3 +232,9 @@ class CCompiler(object):
                 "ERROR: can't resolve libraries to shared libraries: " +
                 ", ".join(not_resolved))
         return shlibs
+
+    def check_is_msvc(self):
+        if isinstance(self.compiler, MSVCCompiler):
+            return True
+        else:
+            return False
diff --git a/giscanner/dumper.py b/giscanner/dumper.py
index 45a09fc..9423177 100644
--- a/giscanner/dumper.py
+++ b/giscanner/dumper.py
@@ -78,25 +78,21 @@ class LinkerError(Exception):
 
 class DumpCompiler(object):
 
+    _compiler = None
+
     def __init__(self, options, get_type_functions, error_quark_functions):
         self._options = options
         self._get_type_functions = get_type_functions
         self._error_quark_functions = error_quark_functions
 
-        self._compiler_cmd = os.environ.get('CC', 'cc')
-        self._linker_cmd = os.environ.get('CC', self._compiler_cmd)
+        # Acquire the compiler (and linker) commands via the CCompiler class in ccompiler.py
+        self._compiler = CCompiler()
+
         self._pkgconfig_cmd = os.environ.get('PKG_CONFIG', 'pkg-config')
-        self._pkgconfig_msvc_flags = ''
-        # Enable the --msvc-syntax pkg-config flag when
-        # the Microsoft compiler is used
-        # (This is the other way to check whether Visual C++ is used subsequently)
-        args = self._compiler_cmd.split()
-        if 'cl.exe' in args or 'cl' in args:
-            self._pkgconfig_msvc_flags = '--msvc-syntax'
-        self._uninst_srcdir = os.environ.get(
-            'UNINSTALLED_INTROSPECTION_SRCDIR')
+        self._uninst_srcdir = os.environ.get('UNINSTALLED_INTROSPECTION_SRCDIR')
         self._packages = ['gio-2.0 gmodule-2.0']
         self._packages.extend(options.packages)
+        self._linker_cmd = os.environ.get('CC', 'cc')
 
     # Public API
 
@@ -155,7 +151,7 @@ class DumpCompiler(object):
 
         # Microsoft compilers generate intermediate .obj files
         # during compilation, unlike .o files like GCC and others
-        if self._pkgconfig_msvc_flags:
+        if self._compiler.check_is_msvc():
             o_path = self._generate_tempfile(tmpdir, '.obj')
         else:
             o_path = self._generate_tempfile(tmpdir, '.o')
@@ -193,8 +189,8 @@ class DumpCompiler(object):
     def _run_pkgconfig(self, flag):
         # Enable the --msvc-syntax pkg-config flag when
         # the Microsoft compiler is used
-        if self._pkgconfig_msvc_flags:
-            cmd = [self._pkgconfig_cmd, self._pkgconfig_msvc_flags, flag]
+        if self._compiler.check_is_msvc():
+            cmd = [self._pkgconfig_cmd, '--msvc-syntax', flag]
         else:
             cmd = [self._pkgconfig_cmd, flag]
         proc = subprocess.Popen(
@@ -204,14 +200,14 @@ class DumpCompiler(object):
 
     def _compile(self, output, *sources):
         # Not strictly speaking correct, but easier than parsing shell
-        args = self._compiler_cmd.split()
+        args = self._compiler.compiler_cmd.split()
         # Do not add -Wall when using init code as we do not include any
         # header of the library being introspected
-        if self._compiler_cmd == 'gcc' and not self._options.init_sections:
+        if self._compiler.compiler_cmd == 'gcc' and not self._options.init_sections:
             args.append('-Wall')
         # The Microsoft compiler uses different option flags for
         # silencing warnings on deprecated function usage
-        if self._pkgconfig_msvc_flags:
+        if self._compiler.check_is_msvc():
             args.append("-wd4996")
         else:
             args.append("-Wno-deprecated-declarations")
@@ -227,7 +223,7 @@ class DumpCompiler(object):
             args.append('-I' + include)
         # The Microsoft compiler uses different option flags for
         # compilation result output
-        if self._pkgconfig_msvc_flags:
+        if self._compiler.check_is_msvc():
             args.extend(['-c', '-Fe' + output, '-Fo' + output])
         else:
             args.extend(['-c', '-o', output])
@@ -258,7 +254,7 @@ class DumpCompiler(object):
         args.extend(self._linker_cmd.split())
         # We can use -o for the Microsoft compiler/linker,
         # but it is considered deprecated usage with that
-        if self._pkgconfig_msvc_flags:
+        if self._compiler.check_is_msvc():
             args.extend(['-Fe' + output])
         else:
             args.extend(['-o', output])
@@ -288,23 +284,18 @@ class DumpCompiler(object):
                     "Could not find object file: %s" % (source, ))
         args.extend(list(sources))
 
-        cc = CCompiler()
+        pkg_config_libs = self._run_pkgconfig('--libs')
 
         if not self._options.external_library:
-            cc.get_internal_link_flags(args,
-                                       libtool,
-                                       self._options.libraries,
-                                       self._options.library_paths,
-                                       self._pkgconfig_msvc_flags,
-                                       self._options.namespace_name,
-                                       self._options.namespace_version)
-            args.extend(self._run_pkgconfig('--libs'))
+            self._compiler.get_internal_link_flags(args,
+                                                   libtool,
+                                                   self._options.libraries,
+                                                   self._options.library_paths)
+            args.extend(pkg_config_libs)
 
         else:
-            args.extend(self._run_pkgconfig('--libs'))
-            cc.get_external_link_flags(args,
-                                       self._options.libraries,
-                                       self._pkgconfig_msvc_flags)
+            args.extend(pkg_config_libs)
+            self._compiler.get_external_link_flags(args, self._options.libraries)
 
         if not self._options.quiet:
             print "g-ir-scanner: link: %s" % (


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]