diff options
-rw-r--r-- | Makefile-giscanner.am | 1 | ||||
-rw-r--r-- | giscanner/ccompiler.py | 202 | ||||
-rw-r--r-- | giscanner/dumper.py | 87 | ||||
-rw-r--r-- | giscanner/shlibs.py | 89 |
4 files changed, 222 insertions, 157 deletions
diff --git a/Makefile-giscanner.am b/Makefile-giscanner.am index bccd8151..c2273cd6 100644 --- a/Makefile-giscanner.am +++ b/Makefile-giscanner.am @@ -31,6 +31,7 @@ pkgpyexec_PYTHON = \ giscanner/annotationparser.py \ giscanner/ast.py \ giscanner/cachestore.py \ + giscanner/ccompiler.py \ giscanner/codegen.py \ giscanner/docmain.py \ giscanner/docwriter.py \ diff --git a/giscanner/ccompiler.py b/giscanner/ccompiler.py new file mode 100644 index 00000000..63110a22 --- /dev/null +++ b/giscanner/ccompiler.py @@ -0,0 +1,202 @@ +# -*- Mode: Python -*- +# GObject-Introspection - a framework for introspecting GObject libraries +# Copyright (C) 2014 Chun-wei Fan +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# + +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 + + +class CCompiler(object): + + compiler_cmd = '' + 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): + # 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 == '': + 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: + 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') + + 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 library.endswith(".la"): # explicitly specified libtool library + args.append(library) + else: + args.append('-l' + library) + + for library_path in libpaths: + # Not used/needed on Visual C++, and -Wl,-rpath options + # will cause grief + if pkgconfig_msvc_flags == '': + args.append('-L' + library_path) + if os.path.isabs(library_path): + if libtool: + args.append('-rpath') + args.append(library_path) + else: + args.append('-Wl,-rpath=' + library_path) + + def get_external_link_flags(self, args, libraries, pkgconfig_msvc_flags): + # 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 library.endswith(".la"): # explicitly specified libtool library + args.append(library) + else: + args.append('-l' + library) + + 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: + # 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(';') + + # Use the dumpbin utility that's included in + # every Visual C++ installation to find out which + # DLL the library gets linked to + args.append('dumpbin.exe') + args.append('-symbols') + + # When we are not using Visual C++ (i.e. we are using GCC)... + else: + is_msvc = False + libtool = get_libtool_command(options) + if libtool: + args.append(which(os.environ.get('SHELL', 'sh.exe'))) + args.extend(libtool) + 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'], + stdout=subprocess.PIPE) + o, e = proc.communicate() + for line in o.splitlines(): + if line.startswith('libraries: '): + libsearch = line[len('libraries: '):].split(';') + + shlibs = [] + not_resolved = [] + for lib in libraries: + found = False + candidates = [ + 'lib%s.dll.a' % lib, + 'lib%s.a' % lib, + '%s.dll.a' % lib, + '%s.a' % lib, + '%s.lib' % lib, + ] + for l in libsearch: + if found: + break + if l.startswith('='): + l = l[1:] + for c in candidates: + if found: + break + implib = os.path.join(l, c) + if os.path.exists(implib): + proc = subprocess.Popen(args + [implib], + stdout=subprocess.PIPE) + o, e = proc.communicate() + for line in o.splitlines(): + if 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 + # __IMPORT_DESCRIPTOR_<dll_filename_that_something.lib_links_to> + + if '__IMPORT_DESCRIPTOR_' in line: + line_tokens = line.split() + for item in line_tokens: + if item.startswith('__IMPORT_DESCRIPTOR_'): + shlibs.append(item[20:] + '.dll') + found = True + break + if found: + break + else: + shlibs.append(line) + found = True + break + if not found: + not_resolved.append(lib) + if len(not_resolved) > 0: + raise SystemExit( + "ERROR: can't resolve libraries to shared libraries: " + + ", ".join(not_resolved)) + return shlibs diff --git a/giscanner/dumper.py b/giscanner/dumper.py index ce119619..45a09fc8 100644 --- a/giscanner/dumper.py +++ b/giscanner/dumper.py @@ -27,6 +27,7 @@ import tempfile from .gdumpparser import IntrospectionBinary from . import utils +from .ccompiler import CCompiler # bugzilla.gnome.org/558436 # Compile a binary program which is then linked to a library @@ -287,10 +288,23 @@ class DumpCompiler(object): "Could not find object file: %s" % (source, )) args.extend(list(sources)) + cc = CCompiler() + if not self._options.external_library: - self._add_link_internal_args(args, libtool) + 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')) + else: - self._add_link_external_args(args) + args.extend(self._run_pkgconfig('--libs')) + cc.get_external_link_flags(args, + self._options.libraries, + self._pkgconfig_msvc_flags) if not self._options.quiet: print "g-ir-scanner: link: %s" % ( @@ -317,75 +331,6 @@ class DumpCompiler(object): if msys: os.remove(tf_name) - def _add_link_internal_args(self, args, libtool): - # 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 self._pkgconfig_msvc_flags == '': - 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 self._pkgconfig_msvc_flags: - if self._options.namespace_version: - args.append(str.lower(self._options.namespace_name) + - '-' + - self._options.namespace_version + '.lib') - else: - args.append(str.lower(self._options.namespace_name) + '.lib') - else: - 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 self._pkgconfig_msvc_flags == '': - args.append('-Wl,--no-as-needed') - - for library in self._options.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 self._pkgconfig_msvc_flags == '': - if library.endswith(".la"): # explicitly specified libtool library - args.append(library) - else: - args.append('-l' + library) - - for library_path in self._options.library_paths: - # Not used/needed on Visual C++, and -Wl,-rpath options - # will cause grief - if self._pkgconfig_msvc_flags == '': - args.append('-L' + library_path) - if os.path.isabs(library_path): - if libtool: - args.append('-rpath') - args.append(library_path) - else: - args.append('-Wl,-rpath=' + library_path) - - args.extend(self._run_pkgconfig('--libs')) - - def _add_link_external_args(self, args): - # 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. - - args.extend(self._run_pkgconfig('--libs')) - for library in self._options.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 self._pkgconfig_msvc_flags == '': - if library.endswith(".la"): # explicitly specified libtool library - args.append(library) - else: - args.append('-l' + library) - def compile_introspection_binary(options, get_type_functions, error_quark_functions): diff --git a/giscanner/shlibs.py b/giscanner/shlibs.py index ec974fa4..1ad75ee6 100644 --- a/giscanner/shlibs.py +++ b/giscanner/shlibs.py @@ -25,6 +25,7 @@ import re import subprocess from .utils import get_libtool_command, extract_libtool_shlib, which +from .ccompiler import CCompiler # For .la files, the situation is easy. @@ -89,92 +90,8 @@ def _resolve_non_libtool(options, binary, libraries): binary.args[0] = old_argdir if os.name == 'nt': - 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: - # 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(';') - - # Use the dumpbin utility that's included in - # every Visual C++ installation to find out which - # DLL the library gets linked to - args.append('dumpbin.exe') - args.append('-symbols') - - # When we are not using Visual C++ (i.e. we are using GCC)... - else: - is_msvc = False - libtool = get_libtool_command(options) - if libtool: - args.append(which(os.environ.get('SHELL', 'sh.exe'))) - args.extend(libtool) - 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'], - stdout=subprocess.PIPE) - o, e = proc.communicate() - for line in o.splitlines(): - if line.startswith('libraries: '): - libsearch = line[len('libraries: '):].split(';') - - shlibs = [] - not_resolved = [] - for lib in libraries: - found = False - candidates = [ - 'lib%s.dll.a' % lib, - 'lib%s.a' % lib, - '%s.dll.a' % lib, - '%s.a' % lib, - '%s.lib' % lib, - ] - for l in libsearch: - if found: - break - if l.startswith('='): - l = l[1:] - for c in candidates: - if found: - break - implib = os.path.join(l, c) - if os.path.exists(implib): - proc = subprocess.Popen(args + [implib], - stdout=subprocess.PIPE) - o, e = proc.communicate() - for line in o.splitlines(): - if 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 - # __IMPORT_DESCRIPTOR_<dll_filename_that_something.lib_links_to> - - if '__IMPORT_DESCRIPTOR_' in line: - line_tokens = line.split() - for item in line_tokens: - if item.startswith('__IMPORT_DESCRIPTOR_'): - shlibs.append(item[20:] + '.dll') - found = True - break - if found: - break - else: - shlibs.append(line) - found = True - break - if not found: - not_resolved.append(lib) - if len(not_resolved) > 0: - raise SystemExit( - "ERROR: can't resolve libraries to shared libraries: " + - ", ".join(not_resolved)) + cc = CCompiler() + shlibs = cc.resolve_windows_libs(libraries, options) else: args = [] |