Skip to content

Commit

Permalink
Add -Wl,-rpath-link for secondary dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
SoapGentoo committed Aug 11, 2019
1 parent 8764e4f commit 5432015
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 4 deletions.
1 change: 1 addition & 0 deletions mesonbuild/compilers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
clink_langs,
c_suffixes,
cpp_suffixes,
get_compiler_is_linuxlike,
get_base_compile_args,
get_base_link_args,
is_header,
Expand Down
49 changes: 45 additions & 4 deletions mesonbuild/dependencies/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

from .. import mlog
from .. import mesonlib
from ..compilers import clib_langs
from ..compilers import clib_langs, get_compiler_is_linuxlike
from ..environment import BinaryTable, Environment, MachineInfo
from ..cmake import CMakeExecutor, CMakeTraceParser, CMakeException
from ..mesonlib import MachineChoice, MesonException, OrderedSet, PerMachine
Expand Down Expand Up @@ -710,16 +710,18 @@ def _set_cargs(self):
(self.name, out))
self.compile_args = self._convert_mingw_paths(shlex.split(out))

def _search_libs(self, out, out_raw):
def _search_libs(self, out, out_raw, out_all):
'''
@out: PKG_CONFIG_ALLOW_SYSTEM_LIBS=1 pkg-config --libs
@out_raw: pkg-config --libs
@out_all: pkg-config --libs --static
We always look for the file ourselves instead of depending on the
compiler to find it with -lfoo or foo.lib (if possible) because:
1. We want to be able to select static or shared
2. We need the full path of the library to calculate RPATH values
3. De-dup of libraries is easier when we have absolute paths
4. We need to find the directories in which secondary dependencies reside
Libraries that are provided by the toolchain or are not found by
find_library() will be added with -L -l pairs.
Expand Down Expand Up @@ -753,15 +755,31 @@ def _search_libs(self, out, out_raw):
continue
if arg.startswith('-L') and arg[2:] not in prefix_libpaths:
system_libpaths.add(arg[2:])
# collect all secondary library paths
secondary_libpaths = OrderedSet()
all_args = self._convert_mingw_paths(shlex.split(out_all))
for arg in all_args:
if arg.startswith('-L') and not arg.startswith(('-L-l', '-L-L')):
path = arg[2:]
if not os.path.isabs(path):
# Resolve the path as a compiler in the build directory would
path = os.path.join(self.env.get_build_dir(), path)
if path not in prefix_libpaths and path not in system_libpaths:
secondary_libpaths.add(path)

# Use this re-ordered path list for library resolution
libpaths = list(prefix_libpaths) + list(system_libpaths)
# Track -lfoo libraries to avoid duplicate work
libs_found = OrderedSet()
# Track not-found libraries to know whether to add library paths
libs_notfound = []
libtype = LibType.STATIC if self.static else LibType.PREFER_SHARED
# Generate link arguments for this library
# Generate link arguments for this library, by
# first appending secondary link arguments for ld
link_args = []
if self.clib_compiler and get_compiler_is_linuxlike(self.clib_compiler):
link_args = ['-Wl,-rpath-link,' + p for p in secondary_libpaths]

for lib in full_args:
if lib.startswith(('-L-l', '-L-L')):
# These are D language arguments, add them as-is
Expand Down Expand Up @@ -831,6 +849,26 @@ def _set_libs(self):
libcmd = [self.name, '--libs']
if self.static:
libcmd.append('--static')
# We need to find *all* secondary dependencies of a library
#
# Say we have libA.so, located in /non/standard/dir1/, and
# libB.so, located in /non/standard/dir2/, which links to
# libA.so. Now when linking exeC to libB.so, the linker will
# walk the complete symbol tree to determine that all undefined
# symbols can be resolved. Because libA.so lives in a directory
# not known to the linker by default, you will get errors like
#
# ld: warning: libA.so, needed by /non/standard/dir2/libB.so,
# not found (try using -rpath or -rpath-link)
# ld: /non/standard/dir2/libB.so: undefined reference to `foo()'
#
# To solve this, we load the -L paths of *all* dependencies, by
# relying on --static to provide us with a complete picture. All
# -L paths that are found via a --static lookup but that are not
# contained in the normal lookup have to originate from secondary
# dependencies. See also:
# http://www.kaizou.org/2015/01/linux-libraries/
libcmd_all = [self.name, '--libs', '--static']
# Force pkg-config to output -L fields even if they are system
# paths so we can do manual searching with cc.find_library() later.
env = os.environ.copy()
Expand All @@ -846,7 +884,10 @@ def _set_libs(self):
if ret != 0:
raise DependencyException('Could not generate libs for %s:\n\n%s' %
(self.name, out_raw))
self.link_args, self.raw_link_args = self._search_libs(out, out_raw)
ret, out_all = self._call_pkgbin(libcmd_all)
if ret != 0:
mlog.warning('Could not determine complete list of dependencies for %s' % self.name)
self.link_args, self.raw_link_args = self._search_libs(out, out_raw, out_all)

def get_pkgconfig_variable(self, variable_name, kwargs):
options = ['--variable=' + variable_name, self.name]
Expand Down

0 comments on commit 5432015

Please sign in to comment.