diff options
-rw-r--r-- | giscanner/ccompiler.py | 136 | ||||
-rw-r--r-- | giscanner/dumper.py | 55 |
2 files changed, 113 insertions, 78 deletions
diff --git a/giscanner/ccompiler.py b/giscanner/ccompiler.py index 2db535cb..884fc2cc 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 45a09fc8..94231771 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" % ( |