Repository: mesonbuild/meson

Issue:
LLVM dependency injects system libs
`llvm-config --libs --ldflags`, as used for dependency('llvm'), contains system library paths at least on Fedora. Since it's not using pkg-config, and we don't have the special 'drop system include/library paths which are there anyway' magic, this places the system libraries higher in the link search path than they otherwise should be, which can break builds.

Assuming upstream are going to continue to not be helpful wrt llvm-config, we might perhaps have to strip it ourselves. An incredibly dumb filter to remove, e.g., '-L/usr/lib64' and '-L/usr/lib' should be enough for most uses, I'd imagine.


Discussion:
(+ @dcbaker)
I noticed this too yesterday, the problem is that `--system-libs` is only needed for static linking, and I put it in but didn't enable static linking. I'll send a patch.
@dcbaker I don't think eliding `--system-libs` actually helps; you have to filter `--ldflags`:
```
strictly:~% llvm-config --libs
-lLLVM-4.0
strictly:~% llvm-config --ldflags
-L/usr/lib64 
strictly:~% llvm-config --system-libs

strictly:~% 
```
What's wrong with -L/usr/lib64? if LLVM was in a non-standard location say, /opt you'd need the -L flag, right?
Correct you are.

The problem is that by default, the compiler/linker will search the provided -L paths for a library first, followed by all the system library paths (e.g. `/usr/lib64` or `/usr/lib/arm-linux-gnueabihf` or whatever). If you put a system path in explicitly, that will be resolved for dependencies.

Specifically, I have new symbols in the version of xcb-dri3 I'm working on. LLVM adding `-L/usr/lib64` to the search path makes it find the system version of xcb-dri3, even though the prefix I've installed it into has an explicit -L line. Link failure results.

This is the reason pkg-config specifically removes system library/include paths, e.g. this for xcb-dri3 which I have installed to a local prefix, and x11 which is provided by the system:
```
strictly:~% pkg-config --libs xcb-dri3
-L/home/daniels/prefix/xorg/lib -lxcb-dri3 
strictly:~% pkg-config --libs x11     
-lX11
```
Okay, that makes sense (I'm still a bit of a noob with C/C++ to be honest).

It's an interesting problem. pkg-config knows which directories to strip from configuration flags that the distro sets.

Also, I checked the `--system-libs`, it definitely breaks debian

Resolving patch:
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -640,3 +640,14 @@ def find_external_dependency(name, env, kwargs):
         raise pkg_exc
     mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO'))
     return pkgdep
+
+
+def strip_system_libdirs(environment, link_args):
+    """Remove -L<system path> arguments.
+
+    leaving these in will break builds where a user has a version of a library
+    in the system path, and a different version not in the system path if they
+    want to link against the non-system path version.
+    """
+    exclude = {'-L{}'.format(p) for p in environment.get_compiler_system_dirs()}
+    return [l for l in link_args if l not in exclude]
diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py
--- a/mesonbuild/dependencies/dev.py
+++ b/mesonbuild/dependencies/dev.py
@@ -23,6 +23,7 @@
 from .. import mesonlib
 from ..mesonlib import version_compare, Popen_safe, stringlistify, extract_as_list
 from .base import DependencyException, ExternalDependency, PkgConfigDependency
+from .base import strip_system_libdirs
 
 class GTestDependency(ExternalDependency):
     def __init__(self, environment, kwargs):
@@ -172,8 +173,7 @@ def __init__(self, environment, kwargs):
             [self.llvmconfig, '--libs', '--ldflags'])[:2]
         if p.returncode != 0:
             raise DependencyException('Could not generate libs for LLVM.')
-        self.link_args = shlex.split(out)
-
+        self.link_args = strip_system_libdirs(environment, shlex.split(out))
         p, out = Popen_safe([self.llvmconfig, '--cppflags'])[:2]
         if p.returncode != 0:
             raise DependencyException('Could not generate includedir for LLVM.')
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -887,6 +887,24 @@ def get_mandir(self):
     def get_datadir(self):
         return self.coredata.get_builtin_option('datadir')
 
+    def get_compiler_system_dirs(self):
+        for comp in self.coredata.compilers.values():
+            if isinstance(comp, compilers.ClangCompiler):
+                index = 1
+                break
+            elif isinstance(comp, compilers.GnuCompiler):
+                index = 2
+                break
+        else:
+            # This option is only supported by gcc and clang. If we don't get a
+            # GCC or Clang compiler return and empty list.
+            return []
+
+        p, out, _ = Popen_safe(comp.get_exelist() + ['-print-search-dirs'])
+        if p.returncode != 0:
+            raise mesonlib.MesonException('Could not calculate system search dirs')
+        out = out.split('\n')[index].lstrip('libraries: =').split(':')
+        return [os.path.normpath(p) for p in out]
 
 def get_args_from_envvars(compiler):
     """


Test patch: