Repository: mesonbuild/meson

Issue:
Confusion about the meaning of the -L parameter with D compilers
Hi!
The dmd and ldc D compilers define the `-L` flag as "pass the next command to the linker", while gdc/gcc define it as "set linker search path".

So I thought I was smart when translating a passed-in `-L` to a ldc/dmd compiler to `-L-L`, since this will make it work expected from a gcc compiler (= `-L` always sets the linker search path).
Unfortunately it now turns out that many people use the `-L` flag as "pass to linker" and even use it in existing pkg-config files, which makes it really hard to change

So, I wonder whether I should do some black magic to detect this in the DCompiler classes, or whether we could somehow utilize `get_linker_search_args()` to set linker search paths in a way all compilers understand, and make the to_native argument translation simply not-deal with an already existing `-L` flag (= have the compiler interpret it as it sees fit).

Possible uses for `-L` for setting the linker search path is to search for local, precompiled shared or static libraries, e.g. `-Lpath/to/libraries -lfoo` (to find a `libfoo.a` or `libfoo.so` file which doesn't exist system-wide). For using `-L` directly, people use it to e.g. pass linker arguments to a compiler if they expect the compiler to be LDC/DMD. E.g. `-L-lfoo` to link against libfoo.

I would prefer to just leave the `-L` flag alone in meson and utilize the `get_linker_search_args` command somehow to allow for a compiler-agnostic way to set linker search paths.



Discussion:
Do people use pkg-config files for D currently? Do they actually work? It would seem that you can only make it work on GDC or LDC...

Yes and yes. But they can work with both systems easily, if people would just use one kind of flag... (the one without `-L` prefix).
But ideally, I would like to get rid of this special-casing alltogether..

Okay so what are the current sources for -L arguments?
- pkg-config?
- link_args : ['-Lfoofoo']?
- something we ourselves generate (what)?
- others?

AFAIK only the first two, pkg-config and manual, explicitly set arguments.


Resolving patch:
diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py
--- a/mesonbuild/compilers.py
+++ b/mesonbuild/compilers.py
@@ -1542,7 +1542,7 @@ def translate_args_to_nongnu(self, args):
                 for la in linkargs:
                     dcargs.append('-L' + la.strip())
                 continue
-            elif arg.startswith(('-l', '-L')):
+            elif arg.startswith('-l'):
                 # translate library link flag
                 dcargs.append('-L' + arg)
                 continue
@@ -1557,6 +1557,12 @@ def __init__(self, exelist, version, is_cross):
         self.warn_args = {'1': ['-Wall', '-Wdeprecated'],
                           '2': ['-Wall', '-Wextra', '-Wdeprecated'],
                           '3': ['-Wall', '-Wextra', '-Wdeprecated', '-Wpedantic']}
+        self.base_options = ['b_colorout', 'b_sanitize']
+
+    def get_colorout_args(self, colortype):
+        if mesonlib.version_compare(self.version, '>=4.9.0'):
+            return gnu_color_args[colortype][:]
+        return []
 
     def get_dependency_gen_args(self, outtarget, outfile):
         # FIXME: Passing -fmake-deps results in a file-not-found message.
@@ -1581,6 +1587,9 @@ def get_warn_args(self, level):
     def get_werror_args(self):
         return ['-Werror']
 
+    def get_linker_search_args(self, dirname):
+        return ['-L'+dirname]
+
     def get_buildtype_args(self, buildtype):
         return d_gdc_buildtype_args[buildtype]
 
@@ -1594,6 +1603,12 @@ class LLVMDCompiler(DCompiler):
     def __init__(self, exelist, version, is_cross):
         DCompiler.__init__(self, exelist, version, is_cross)
         self.id = 'llvm'
+        self.base_options = ['b_coverage', 'b_colorout']
+
+    def get_colorout_args(self, colortype):
+        if colortype == 'always':
+            return ['-enable-color']
+        return []
 
     def get_dependency_gen_args(self, outtarget, outfile):
         # LDC using the -deps flag returns a non-Makefile dependency-info file, which
@@ -1627,6 +1642,12 @@ def get_buildtype_args(self, buildtype):
     def get_pic_args(self):
         return ['-relocation-model=pic']
 
+    def get_linker_search_args(self, dirname):
+        # -L is recognized as "add this to the search path" by the linker,
+        # while the compiler recognizes it as "pass to linker". So, the first
+        # -L is for the compiler, telling it to pass the second -L to the linker.
+        return ['-L-L'+dirname]
+
     def unix_link_flags_to_native(self, args):
         return self.translate_args_to_nongnu(args)
 
@@ -1637,6 +1658,12 @@ class DmdDCompiler(DCompiler):
     def __init__(self, exelist, version, is_cross):
         DCompiler.__init__(self, exelist, version, is_cross)
         self.id = 'dmd'
+        self.base_options = ['b_coverage', 'b_colorout']
+
+    def get_colorout_args(self, colortype):
+        if colortype == 'always':
+            return ['-color=on']
+        return []
 
     def get_dependency_gen_args(self, outtarget, outfile):
         # LDC using the -deps flag returns a non-Makefile dependency-info file, which
@@ -1664,6 +1691,12 @@ def get_warn_args(self, level):
     def get_coverage_args(self):
         return ['-cov']
 
+    def get_linker_search_args(self, dirname):
+        # -L is recognized as "add this to the search path" by the linker,
+        # while the compiler recognizes it as "pass to linker". So, the first
+        # -L is for the compiler, telling it to pass the second -L to the linker.
+        return ['-L-L'+dirname]
+
     def get_buildtype_args(self, buildtype):
         return d_dmd_buildtype_args[buildtype]
 


Test patch: