Repository: mesonbuild/meson

Issue:
Function check regression
There is a regression since meson 0.50.0, meson incorrectly detects not available functions as available since 0.50.0.

It seems this is caused by meson not passing some of the crossfile cflags that were passed before, it clearly lacks `c_args`:

### Meson 0.50.0
```
Running compile:
Working directory:  /var/folders/rw/l97gj1cd6vd_wrf_zjcbycjc0000gn/T/tmpw3x_eba0
Command line:  clang -L/Users/epirat/Projects/VideoLAN/VLC/build-test/contrib/arm64-apple-iOS_9.0/lib /var/folders/rw/l97gj1cd6vd_wrf_zjcbycjc0000gn/T/tmpw3x_eba0/testfile.c -pipe -o /var/folders/rw/l97gj1cd6vd_wrf_zjcbycjc0000gn/T/tmpw3x_eba0/output.exe -Wl,-ios_version_min,9.0 -arch arm64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk -O0 -D_POSIX_C_SOURCE=200112L -Wl,-no_weak_imports 

Code:
 #include <time.h>
#include <limits.h>

        #if defined __stub_clock_gettime || defined __stub___clock_gettime
        fail fail fail this function is not going to work
        #endif
        
int main() {
            void *a = (void*) &clock_gettime;
            long b = (long) a;
            return (int) b;
        }
Compiler stdout:
 
Compiler stderr:
``` 

### Meson 0.49.2
```
Running compile:
Working directory:  /var/folders/rw/l97gj1cd6vd_wrf_zjcbycjc0000gn/T/tmpsqqg32j7
Command line:  clang -I/Users/epirat/Projects/VideoLAN/VLC/build-test/contrib/arm64-apple-iOS_9.0/include -L/Users/epirat/Projects/VideoLAN/VLC/build-test/contrib/arm64-apple-iOS_9.0/lib /var/folders/rw/l97gj1cd6vd_wrf_zjcbycjc0000gn/T/tmpsqqg32j7/testfile.c -pipe -o /var/folders/rw/l97gj1cd6vd_wrf_zjcbycjc0000gn/T/tmpsqqg32j7/output.exe -mios-version-min=9.0 -arch arm64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk -mios-version-min=9.0 -arch arm64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk -g -O2 -Wl,-ios_version_min,9.0 -arch arm64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk -O0 -std=c99 -D_POSIX_C_SOURCE=200112L -Wl,-no_weak_imports 

Code:
 #include <time.h>
#include <limits.h>

        #if defined __stub_clock_gettime || defined __stub___clock_gettime
        fail fail fail this function is not going to work
        #endif
        
int main() {
            void *a = (void*) &clock_gettime;
            long b = (long) a;
            return (int) b;
        }
Compiler stdout:
 
Compiler stderr:
 ld: weak import of symbol '_clock_gettime' not supported because of option: -no_weak_imports for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
```

My crossfile:

```
# Automatically generated by contrib makefile

[binaries]
c = 'clang'
cpp = 'clang++'
ar = 'ar'
strip = 'strip'
pkgconfig = 'pkg-config'
windres = 'aarch64-apple-darwin18.6.0-windres'

[properties]
needs_exe_wrapper = true
c_args = ['-mios-version-min=9.0', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk', '-mios-version-min=9.0', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk', '-I/Users/epirat/Projects/VideoLAN/VLC/build-test/contrib/arm64-apple-iOS_9.0/include', '-g', '-O2', ]
c_link_args = ['-Wl,-ios_version_min,9.0', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk', '-L/Users/epirat/Projects/VideoLAN/VLC/build-test/contrib/arm64-apple-iOS_9.0/lib', ]
cpp_args = ['-mios-version-min=9.0', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk', '-mios-version-min=9.0', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk', '-mios-version-min=9.0', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk', '-I/Users/epirat/Projects/VideoLAN/VLC/build-test/contrib/arm64-apple-iOS_9.0/include', '-g', '-I/Users/epirat/Projects/VideoLAN/VLC/build-test/contrib/arm64-apple-iOS_9.0/include', '-g', '-O2', ]
cpp_link_args = ['-Wl,-ios_version_min,9.0', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk', '-L/Users/epirat/Projects/VideoLAN/VLC/build-test/contrib/arm64-apple-iOS_9.0/lib', ]

[host_machine]
system = 'darwin'
cpu_family = 'aarch64'
cpu = 'aarch64'
endian = 'little'
```


Discussion:
Bisect result:

```
d451a4bd97f827bb492fd0c0e357cb20b6056ed9 is the first bad commit
commit d451a4bd97f827bb492fd0c0e357cb20b6056ed9
Author: John Ericson <John.Ericson@Obsidian.Systems>
Date:   Tue Jan 8 21:59:50 2019 -0500

    Remove get_cross_extra_flags

    This is no longer needed, we just remove conditionals around it.

:040000 040000 d1c154516c0e4b368b726a117f63756537711628 e18e6eb2e2c41b16bfbc9361ea0797081e9d0aa8 M	mesonbuild
```

cc @Ericson2314 
@ePirat this sounds like issues I fixed in `0.50.1` and also `master`. Can you try there?
Same issue on master:

```
Running compile:
Working directory:  /var/folders/rw/l97gj1cd6vd_wrf_zjcbycjc0000gn/T/tmpisko7k95
Command line:  clang -L/Users/epirat/Projects/VideoLAN/VLC/build-test/contrib/arm64-apple-iOS_9.0/lib /var/folders/rw/l97gj1cd6vd_wrf_zjcbycjc0000gn/T/tmpisko7k95/testfile.c -pipe -o /var/folders/rw/l97gj1cd6vd_wrf_zjcbycjc0000gn/T/tmpisko7k95/output.exe -Wl,-ios_version_min,9.0 -arch arm64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk -O0 -std=c99 -D_POSIX_C_SOURCE=200112L -Wl,-no_weak_imports 

Code:
 #include <time.h>
#include <limits.h>

        #if defined __stub_clock_gettime || defined __stub___clock_gettime
        fail fail fail this function is not going to work
        #endif
        
int main() {
            void *a = (void*) &clock_gettime;
            long b = (long) a;
            return (int) b;
        }
Compiler stdout:
 
Compiler stderr:
 
Checking for function "clock_gettime" : YES 
```

Resolving patch:
diff --git a/mesonbuild/compilers/clike.py b/mesonbuild/compilers/clike.py
--- a/mesonbuild/compilers/clike.py
+++ b/mesonbuild/compilers/clike.py
@@ -384,18 +384,22 @@ def _get_basic_compiler_args(self, env, mode):
         # Select a CRT if needed since we're linking
         if mode == 'link':
             args += self.get_linker_debug_crt_args()
-        if mode in {'compile', 'preprocess'}:
-            # Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS and CPPFLAGS from the env
-            sys_args = env.coredata.get_external_args(self.for_machine, self.language)
-            # Apparently it is a thing to inject linker flags both
-            # via CFLAGS _and_ LDFLAGS, even though the former are
-            # also used during linking. These flags can break
-            # argument checks. Thanks, Autotools.
-            cleaned_sys_args = self.remove_linkerlike_args(sys_args)
-            args += cleaned_sys_args
-        elif mode == 'link':
+
+        # Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS and CPPFLAGS from the env
+        sys_args = env.coredata.get_external_args(self.for_machine, self.language)
+        # Apparently it is a thing to inject linker flags both
+        # via CFLAGS _and_ LDFLAGS, even though the former are
+        # also used during linking. These flags can break
+        # argument checks. Thanks, Autotools.
+        cleaned_sys_args = self.remove_linkerlike_args(sys_args)
+        args += cleaned_sys_args
+
+        if mode == 'link':
             # Add LDFLAGS from the env
-            args += env.coredata.get_external_link_args(self.for_machine, self.language)
+            sys_ld_args = env.coredata.get_external_link_args(self.for_machine, self.language)
+            # CFLAGS and CXXFLAGS go to both linking and compiling, but we want them
+            # to only appear on the command line once. Remove dupes.
+            args += [x for x in sys_ld_args if x not in sys_args]
 
         args += self.get_compiler_args_for_mode(mode)
         return args
@@ -431,11 +435,11 @@ def compiles(self, code, env, *, extra_args=None, dependencies=None, mode='compi
         with self._build_wrapper(code, env, extra_args, dependencies, mode, disable_cache=disable_cache) as p:
             return p.returncode == 0, p.cached
 
-    def _build_wrapper(self, code, env, extra_args, dependencies=None, mode='compile', want_output=False, disable_cache=False):
+    def _build_wrapper(self, code, env, extra_args, dependencies=None, mode='compile', want_output=False, disable_cache=False, temp_dir=None):
         args = self._get_compiler_check_args(env, extra_args, dependencies, mode)
         if disable_cache or want_output:
-            return self.compile(code, extra_args=args, mode=mode, want_output=want_output, temp_dir=env.scratch_dir)
-        return self.cached_compile(code, env.coredata, extra_args=args, mode=mode, temp_dir=env.scratch_dir)
+            return self.compile(code, extra_args=args, mode=mode, want_output=want_output, temp_dir=temp_dir)
+        return self.cached_compile(code, env.coredata, extra_args=args, mode=mode, temp_dir=temp_dir)
 
     def links(self, code, env, *, extra_args=None, dependencies=None, disable_cache=False):
         return self.compiles(code, env, extra_args=extra_args,
@@ -861,7 +865,7 @@ def symbols_have_underscore_prefix(self, env):
         '''
         args = self.get_compiler_check_args()
         n = 'symbols_have_underscore_prefix'
-        with self.compile(code, extra_args=args, mode='compile', want_output=True, temp_dir=env.scratch_dir) as p:
+        with self._build_wrapper(code, env, extra_args=args, mode='compile', want_output=True, temp_dir=env.scratch_dir) as p:
             if p.returncode != 0:
                 m = 'BUG: Unable to compile {!r} check: {}'
                 raise RuntimeError(m.format(n, p.stdo))
diff --git a/run_unittests.py b/run_unittests.py
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -3055,9 +3055,10 @@ def test_command_line(self):
         self.wipe()
 
         # c_args value should be parsed with shlex
-        self.init(testdir, extra_args=['-Dc_args=foo bar "one two"'])
+        self.init(testdir, extra_args=['-Dc_args=-Dfoo -Dbar "-Dthird=one two"'])
         obj = mesonbuild.coredata.load(self.builddir)
-        self.assertEqual(obj.compiler_options.host['c_args'].value, ['foo', 'bar', 'one two'])
+        self.assertEqual(obj.compiler_options.host['c_args'].value, ['-Dfoo', '-Dbar', '-Dthird=one two'])
+
         self.setconf('-Dc_args="foo bar" one two')
         obj = mesonbuild.coredata.load(self.builddir)
         self.assertEqual(obj.compiler_options.host['c_args'].value, ['foo bar', 'one', 'two'])
@@ -3068,21 +3069,21 @@ def test_command_line(self):
             self.init(testdir, extra_args=['--bindir=foo', '--bindir=bar',
                                            '-Dbuildtype=plain', '-Dbuildtype=release',
                                            '-Db_sanitize=address', '-Db_sanitize=thread',
-                                           '-Dc_args=foo', '-Dc_args=bar'])
+                                           '-Dc_args=-Dfoo', '-Dc_args=-Dbar'])
             obj = mesonbuild.coredata.load(self.builddir)
             self.assertEqual(obj.builtins['bindir'].value, 'bar')
             self.assertEqual(obj.builtins['buildtype'].value, 'release')
             self.assertEqual(obj.base_options['b_sanitize'].value, 'thread')
-            self.assertEqual(obj.compiler_options.host['c_args'].value, ['bar'])
+            self.assertEqual(obj.compiler_options.host['c_args'].value, ['-Dbar'])
             self.setconf(['--bindir=bar', '--bindir=foo',
                           '-Dbuildtype=release', '-Dbuildtype=plain',
                           '-Db_sanitize=thread', '-Db_sanitize=address',
-                          '-Dc_args=bar', '-Dc_args=foo'])
+                          '-Dc_args=-Dbar', '-Dc_args=-Dfoo'])
             obj = mesonbuild.coredata.load(self.builddir)
             self.assertEqual(obj.builtins['bindir'].value, 'foo')
             self.assertEqual(obj.builtins['buildtype'].value, 'plain')
             self.assertEqual(obj.base_options['b_sanitize'].value, 'address')
-            self.assertEqual(obj.compiler_options.host['c_args'].value, ['foo'])
+            self.assertEqual(obj.compiler_options.host['c_args'].value, ['-Dfoo'])
             self.wipe()
         except KeyError:
             # Ignore KeyError, it happens on CI for compilers that does not


Test patch: