aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/dependencies/base.py
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild/dependencies/base.py')
-rw-r--r--mesonbuild/dependencies/base.py48
1 files changed, 45 insertions, 3 deletions
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index b0f24c8..e32f983 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -33,6 +33,7 @@ from .. import mesonlib
from ..compilers import clib_langs
from ..environment import BinaryTable, Environment, MachineInfo
from ..cmake import CMakeExecutor, CMakeTraceParser, CMakeException
+from ..linkers import GnuLikeDynamicLinkerMixin
from ..mesonlib import MachineChoice, MesonException, OrderedSet, PerMachine
from ..mesonlib import Popen_safe, version_compare_many, version_compare, listify, stringlistify, extract_as_list, split_args
from ..mesonlib import Version, LibType
@@ -712,16 +713,18 @@ class PkgConfigDependency(ExternalDependency):
(self.name, out))
self.compile_args = self._convert_mingw_paths(self._split_args(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.
@@ -755,6 +758,18 @@ class PkgConfigDependency(ExternalDependency):
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
@@ -762,8 +777,12 @@ class PkgConfigDependency(ExternalDependency):
# 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 self.clib_compiler.linker and isinstance(self.clib_compiler.linker, GnuLikeDynamicLinkerMixin):
+ 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
@@ -833,6 +852,26 @@ class PkgConfigDependency(ExternalDependency):
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()
@@ -848,7 +887,10 @@ class PkgConfigDependency(ExternalDependency):
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]