Repository: mesonbuild/meson

Issue:
_FOR_BUILD environment variables are broken
Using the _FOR_BUILD environment variables in a cross compilation has stopped working.

this should work:
```console
PKG_CONFIG_PATH=/foo PKG_CONFIG_PATH_FOR_BUILD=/bar meson build --cross-file cross
```
and should be equivalent to
```console
meson build --cross-file cross -Dpkg_config_path=/foo -Dbuild.pkg_config_path=/bar
```
This has stopped working on master, and is due to #8603


Discussion:

Resolving patch:
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -1236,19 +1236,26 @@ def get_global_options(lang: str,
     largkey = argkey.evolve('link_args')
     envkey = argkey.evolve('env_args')
 
+    comp_key = argkey if argkey in env.options else envkey
+
+    comp_options = env.options.get(comp_key, [])
+    link_options = env.options.get(largkey, [])
+
     cargs = coredata.UserArrayOption(
         description + ' compiler',
-        env.options.get(argkey, []), split_args=True, user_input=True, allow_dups=True)
-    # the compiler args always gets the environemtn variable arguments
-    cargs.extend_value(env.options.get(envkey, []))
+        comp_options, split_args=True, user_input=True, allow_dups=True)
 
     largs = coredata.UserArrayOption(
         description + ' linker',
-        env.options.get(largkey, []), split_args=True, user_input=True, allow_dups=True)
-    # The linker gets the compiler environment variable only if the comiler
-    # acts as the linker
-    if comp.INVOKES_LINKER:
-        largs.extend_value(env.options.get(envkey, []))
+        link_options, split_args=True, user_input=True, allow_dups=True)
+
+    if comp.INVOKES_LINKER and comp_key == envkey:
+        # If the compiler acts as a linker driver, and we're using the
+        # environment variable flags for both the compiler and linker
+        # arguments, then put the compiler flags in the linker flags as well.
+        # This is how autotools works, and the env vars freature is for
+        # autotools compatibility.
+        largs.extend_value(comp_options)
 
     opts: 'KeyedOptionDictType' = {argkey: cargs, largkey: largs}
 
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -798,11 +798,7 @@ def _set_default_options_from_env(self) -> None:
 
         env_opts: T.DefaultDict[OptionKey, T.List[str]] = collections.defaultdict(list)
 
-        if self.is_cross_build():
-            for_machine = MachineChoice.BUILD
-        else:
-            for_machine = MachineChoice.HOST
-        for evar, keyname in opts:
+        for (evar, keyname), for_machine in itertools.product(opts, MachineChoice):
             p_env = _get_env_var(for_machine, self.is_cross_build(), evar)
             if p_env is not None:
                 # these may contain duplicates, which must be removed, else
@@ -832,7 +828,7 @@ def _set_default_options_from_env(self) -> None:
                             key = key.evolve(lang=lang)
                             env_opts[key].extend(p_list)
                     elif keyname == 'cppflags':
-                        key = OptionKey('args', machine=for_machine, lang='c')
+                        key = OptionKey('env_args', machine=for_machine, lang='c')
                         for lang in compilers.compilers.LANGUAGES_USING_CPPFLAGS:
                             key = key.evolve(lang=lang)
                             env_opts[key].extend(p_list)
diff --git a/run_unittests.py b/run_unittests.py
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -9325,13 +9325,15 @@ def test_builtin_options_per_machine(self):
 
     def test_builtin_options_conf_overrides_env(self):
         testcase = os.path.join(self.common_test_dir, '2 cpp')
-        config = self.helper_create_cross_file({'built-in options': {'pkg_config_path': '/native'}})
-        cross = self.helper_create_cross_file({'built-in options': {'pkg_config_path': '/cross'}})
+        config = self.helper_create_cross_file({'built-in options': {'pkg_config_path': '/native', 'cpp_args': '-DFILE'}})
+        cross = self.helper_create_cross_file({'built-in options': {'pkg_config_path': '/cross', 'cpp_args': '-DFILE'}})
 
         self.init(testcase, extra_args=['--native-file', config, '--cross-file', cross],
-                  override_envvars={'PKG_CONFIG_PATH': '/bar', 'PKG_CONFIG_PATH_FOR_BUILD': '/dir'})
+                  override_envvars={'PKG_CONFIG_PATH': '/bar', 'PKG_CONFIG_PATH_FOR_BUILD': '/dir',
+                                    'CXXFLAGS': '-DENV', 'CXXFLAGS_FOR_BUILD': '-DENV'})
         configuration = self.introspect('--buildoptions')
         found = 0
+        expected = 4
         for each in configuration:
             if each['name'] == 'pkg_config_path':
                 self.assertEqual(each['value'], ['/cross'])
@@ -9339,6 +9341,29 @@ def test_builtin_options_conf_overrides_env(self):
             elif each['name'] == 'build.pkg_config_path':
                 self.assertEqual(each['value'], ['/native'])
                 found += 1
+            elif each['name'].endswith('cpp_args'):
+                self.assertEqual(each['value'], ['-DFILE'])
+                found += 1
+            if found == expected:
+                break
+        self.assertEqual(found, expected, 'Did not find all sections.')
+
+    def test_for_build_env_vars(self) -> None:
+        testcase = os.path.join(self.common_test_dir, '2 cpp')
+        config = self.helper_create_cross_file({'built-in options': {}})
+        cross = self.helper_create_cross_file({'built-in options': {}})
+
+        self.init(testcase, extra_args=['--native-file', config, '--cross-file', cross],
+                  override_envvars={'PKG_CONFIG_PATH': '/bar', 'PKG_CONFIG_PATH_FOR_BUILD': '/dir'})
+        configuration = self.introspect('--buildoptions')
+        found = 0
+        for each in configuration:
+            if each['name'] == 'pkg_config_path':
+                self.assertEqual(each['value'], ['/bar'])
+                found += 1
+            elif each['name'] == 'build.pkg_config_path':
+                self.assertEqual(each['value'], ['/dir'])
+                found += 1
             if found == 2:
                 break
         self.assertEqual(found, 2, 'Did not find all sections.')


Test patch: