Commit 5d4cd252 authored by Chun-wei Fan's avatar Chun-wei Fan
Browse files

giscanner: Do not use distutils for linking

...the dumper program for all cases.  It turned out that using distutils
for linking is more troublesome than useful as we need to ensure that
the paths specified by -L need to come before the standard library search
paths, and distutil's ccompiler.add_library_path() and
ccompiler.add_runtime_library_path() does not work for all of its
supported compilers (Visual Studio is an example).

Instead, we go back to constructing our linker command line manually as
we did before (and as we now do in the libtool case), but with some
enhancements:

-Use '-libpath:' on Visual Studio builds, which corresponds to the -L flag
 on GCC/CLang.
-Extend LIB/PATH (Windows/Visual Studio) or LD_LIBRARY_PATH (other
 compilers/envs), which is necessary as we resolve the libraries that
 are passed into g-ir-scanner, at least on Windows.
-Don't attempt to link to or resolve m.lib on Visual Studio builds, as
 the math functions are in the standard CRT .lib/.dll, and there is no
 such thing as m.lib

https://bugzilla.gnome.org/show_bug.cgi?id=781525
parent 6b703b32
......@@ -113,22 +113,18 @@ class CCompiler(object):
# An "internal" link is where the library to be introspected
# is being built in the current directory.
if not libtool:
# non-libtool case: prepare distutils use
if self.check_is_msvc():
for library in libraries + extra_libraries:
# MSVC Builds don't use libtool, so no .la libraries,
# so just add the library directly.
self.compiler.add_library(library)
for libpath in libpaths:
self.compiler.add_library_dir(libpath)
else:
# Search the current directory first
# (This flag is not supported nor needed for Visual C++)
self.compiler.add_library_dir('.')
if os.name != 'nt':
self.compiler.add_runtime_library_dir('.')
runtime_path_envvar = []
runtime_paths = []
if self.check_is_msvc():
runtime_path_envvar = ['LIB', 'PATH']
else:
runtime_path_envvar = ['LD_LIBRARY_PATH']
# Search the current directory first
# (This flag is not supported nor needed for Visual C++)
args.append('-L.')
if not libtool:
# https://bugzilla.gnome.org/show_bug.cgi?id=625195
args.append('-Wl,-rpath,.')
......@@ -137,37 +133,51 @@ class CCompiler(object):
if sys.platform != 'darwin':
args.append('-Wl,--no-as-needed')
for library in libraries + extra_libraries:
self.compiler.add_library(library)
if not self.check_is_msvc():
for library_path in libpaths:
args.append('-L' + library_path)
if os.path.isabs(library_path):
args.append('-Wl,-rpath,' + library_path)
else:
# libtool case: assemble linker command arguments, like we did before
args.append('-L.')
for library in libraries:
for library in libraries + extra_libraries:
if self.check_is_msvc():
# Note that Visual Studio builds do not use libtool!
if library != 'm':
args.append(library + '.lib')
else:
if library.endswith(".la"): # explicitly specified libtool library
args.append(library)
else:
args.append('-l' + library)
for library_path in libpaths:
for library_path in libpaths:
# The dumper program needs to look for dynamic libraries
# in the library paths first
if self.check_is_msvc():
library_path = library_path.replace('/', '\\')
args.append('-libpath:' + library_path)
else:
args.append('-L' + library_path)
if os.path.isabs(library_path):
args.append('-rpath')
args.append(library_path)
if libtool:
args.append('-rpath')
args.append(library_path)
else:
args.append('-Wl,-rpath=' + library_path)
runtime_paths.append(library_path)
for envvar in runtime_path_envvar:
if envvar in os.environ:
os.environ[envvar] = \
os.pathsep.join(runtime_paths + [os.environ[envvar]])
else:
os.environ[envvar] = os.pathsep.join(runtime_paths)
def get_external_link_flags(self, args, libtool, libraries):
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:
if not libtool:
self.compiler.add_library(library)
if self.check_is_msvc():
# Visual Studio: don't attempt to link to m.lib
if library != 'm':
args.append(library + ".lib")
else:
if library.endswith(".la"): # explicitly specified libtool library
args.append(library)
......@@ -240,22 +250,6 @@ class CCompiler(object):
extra_postargs=extra_postargs,
output_dir=os.path.abspath(os.sep))
def link(self, output, objects, lib_args):
# Note: This is used for non-libtool builds only!
extra_preargs = []
extra_postargs = []
library_dirs = []
libraries = []
for arg in lib_args:
extra_postargs.append(arg)
self.compiler.link(target_desc=self.compiler.EXECUTABLE,
objects=objects,
output_filename=output,
extra_preargs=extra_preargs,
extra_postargs=extra_postargs)
def resolve_windows_libs(self, libraries, options):
args = []
libsearch = []
......@@ -278,6 +272,10 @@ class CCompiler(object):
args.append('dumpbin.exe')
args.append('-symbols')
# Work around the attempt to resolve m.lib on Python 2.x
if sys.version_info.major < 3:
libraries[:] = [lib for lib in libraries if lib != 'm']
# When we are not using Visual C++ (i.e. we are using GCC)...
else:
libtool = utils.get_libtool_command(options)
......
......@@ -99,10 +99,10 @@ class DumpCompiler(object):
self._uninst_srcdir = os.environ.get('UNINSTALLED_INTROSPECTION_SRCDIR')
self._packages = ['gio-2.0 gmodule-2.0']
self._packages.extend(options.packages)
if hasattr(self._compiler.compiler, 'linker_exe'):
self._linker_cmd = self._compiler.compiler.linker_exe
if self._compiler.check_is_msvc():
self._linker_cmd = ['link.exe']
else:
self._linker_cmd = []
self._linker_cmd = shlex.split(os.environ.get('CC', 'cc'))
# Public API
......@@ -212,21 +212,25 @@ class DumpCompiler(object):
libtool = utils.get_libtool_command(self._options)
if libtool:
# Note: MSVC Builds do not use libtool!
# In the libtool case, put together the linker command, as we did before.
# We aren't using distutils to link in this case.
args.extend(libtool)
args.append('--mode=link')
args.append('--tag=CC')
if self._options.quiet:
args.append('--silent')
args.extend(self._linker_cmd)
args.extend(self._linker_cmd)
# We can use -o for the Microsoft compiler/linker,
# but it is considered deprecated usage
if self._compiler.check_is_msvc():
args.extend(['-out:' + output])
else:
args.extend(['-o', output])
if os.name == 'nt':
args.append('-Wl,--export-all-symbols')
else:
args.append('-export-dynamic')
if libtool:
if os.name == 'nt':
args.append('-Wl,--export-all-symbols')
else:
args.append('-export-dynamic')
if not self._compiler.check_is_msvc():
# These envvars are not used for MSVC Builds!
......@@ -246,8 +250,7 @@ class DumpCompiler(object):
raise CompilerError(
"Could not find object file: %s" % (source, ))
if libtool:
args.extend(sources)
args.extend(sources)
pkg_config_libs = self._run_pkgconfig('--libs')
......@@ -261,66 +264,36 @@ class DumpCompiler(object):
else:
args.extend(pkg_config_libs)
self._compiler.get_external_link_flags(args,
libtool,
self._options.libraries)
self._compiler.get_external_link_flags(args, self._options.libraries)
if not self._compiler.check_is_msvc():
for ldflag in shlex.split(os.environ.get('LDFLAGS', '')):
args.append(ldflag)
if not libtool:
# non-libtool: prepare distutils for linking the introspection
# dumper program...
try:
self._compiler.link(output,
sources,
args)
# Ignore failing to embed the manifest files, when the manifest
# file does not exist, especially for MSVC 2010 and later builds.
# If we are on Visual C++ 2005/2008, where
# this embedding is required, the build will fail anyway, as
# the dumper program will likely fail to run, and this means
# something went wrong with the build.
except LinkError as e:
if self._compiler.check_is_msvc():
msg = str(e)
if msg[msg.rfind('mt.exe'):] == 'mt.exe\' failed with exit status 31':
if sys.version_info < (3, 0):
sys.exc_clear()
pass
else:
raise LinkError(e)
else:
raise LinkError(e)
else:
# libtool: Run the assembled link command, we don't use distutils
# for linking here.
if not self._options.quiet:
print("g-ir-scanner: link: %s" % (
subprocess.list2cmdline(args), ))
sys.stdout.flush()
msys = os.environ.get('MSYSTEM', None)
if not self._options.quiet:
print("g-ir-scanner: link: %s" % (
subprocess.list2cmdline(args), ))
sys.stdout.flush()
msys = os.environ.get('MSYSTEM', None)
if msys:
shell = os.environ.get('SHELL', 'sh.exe')
# Create a temporary script file that
# runs the command we want
tf, tf_name = tempfile.mkstemp()
with os.fdopen(tf, 'wb') as f:
shellcontents = ' '.join([x.replace('\\', '/') for x in args])
fcontents = '#!/bin/sh\nunset PWD\n{}\n'.format(shellcontents)
f.write(fcontents)
shell = utils.which(shell)
args = [shell, tf_name.replace('\\', '/')]
try:
subprocess.check_call(args)
except subprocess.CalledProcessError as e:
raise LinkerError(e)
finally:
if msys:
shell = os.environ.get('SHELL', 'sh.exe')
# Create a temporary script file that
# runs the command we want
tf, tf_name = tempfile.mkstemp()
with os.fdopen(tf, 'wb') as f:
shellcontents = ' '.join([x.replace('\\', '/') for x in args])
fcontents = '#!/bin/sh\nunset PWD\n{}\n'.format(shellcontents)
f.write(fcontents)
shell = utils.which(shell)
args = [shell, tf_name.replace('\\', '/')]
try:
subprocess.check_call(args)
except subprocess.CalledProcessError as e:
raise LinkerError(e)
finally:
if msys:
os.remove(tf_name)
os.remove(tf_name)
def compile_introspection_binary(options, get_type_functions,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment