Repository: mesonbuild/meson

Issue:
gnome.generate_gir(): need ability to set environment variables when calling g-ir-scanner
I need to set some environment variables so that when g-ir-scanner calls gst_init() no GStreamer plugins from the install prefix (or anywhere really) get loaded, amongst other things.



Discussion:
Unfortunately there is no reliable cross tool way of setting environment variables. This needs to be implemented somehow by having a wrapper script that sets the environment transparently (many Meson features do the same behind the scenes).

The question then is whether we should make it possible to add a custom wrapper to this command or a create a syntax for setting envvars and then do that transparently. The latter can be said to be more user friendly but the former gives more freedom for people to do other crazy customisation as well and we might need to provide it at some point anyway.

I guess the answer is both then? :)

I would always prioritise user-friendliness. It's one of the main selling points of meson IMHO. (But then I would say that, wouldn't I)

I don't think this is something that only GStreamer will want/or need btw.

https://github.com/mesonbuild/meson/pull/494 sets up the infrastructure that will be required to implement this.

Given run_target and custom_target both support envs now (new in meson 0.57), and generate_gir internally creates a build.CustomTarget, this seems quite doable. Anyone want to implement it?

Resolving patch:
diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py
--- a/mesonbuild/modules/gnome.py
+++ b/mesonbuild/modules/gnome.py
@@ -32,12 +32,12 @@
 from .. import mlog
 from ..build import CustomTarget, CustomTargetIndex, Executable, GeneratedList, InvalidArguments
 from ..dependencies import Dependency, PkgConfigDependency, InternalDependency
-from ..interpreter.type_checking import DEPENDS_KW, DEPEND_FILES_KW, INSTALL_DIR_KW, INSTALL_KW, NoneType, SOURCES_KW, in_set_validator
+from ..interpreter.type_checking import DEPENDS_KW, DEPEND_FILES_KW, ENV_KW, INSTALL_DIR_KW, INSTALL_KW, NoneType, SOURCES_KW, in_set_validator
 from ..interpreterbase import noPosargs, noKwargs, FeatureNew, FeatureDeprecated
 from ..interpreterbase import typed_kwargs, KwargInfo, ContainerTypeInfo
 from ..interpreterbase.decorators import typed_pos_args
 from ..mesonlib import (
-    MachineChoice, MesonException, OrderedSet, Popen_safe, join_args,
+    MachineChoice, MesonException, OrderedSet, Popen_safe, join_args, quote_arg
 )
 from ..programs import OverrideProgram
 from ..scripts.gettext import read_linguas
@@ -979,6 +979,10 @@ def _make_gir_target(
         # settings user could have set in machine file, like PKG_CONFIG_LIBDIR,
         # SYSROOT, etc.
         run_env = PkgConfigDependency.get_env(state.environment, MachineChoice.HOST, uninstalled=True)
+        # g-ir-scanner uses Python's distutils to find the compiler, which uses 'CC'
+        cc_exelist = state.environment.coredata.compilers.host['c'].get_exelist()
+        run_env.set('CC', [quote_arg(x) for x in cc_exelist], ' ')
+        run_env.merge(kwargs['env'])
 
         return GirTarget(
             girfile,
@@ -1023,6 +1027,7 @@ def _make_typelib_target(state: 'ModuleState', typelib_output: str,
             install_dir=[install_dir],
             install_tag=['typelib'],
             build_by_default=kwargs['build_by_default'],
+            env=kwargs['env'],
         )
 
     @staticmethod
@@ -1095,6 +1100,7 @@ def _get_scanner_ldflags(ldflags: T.Iterable[str]) -> T.Iterable[str]:
         INSTALL_KW,
         _BUILD_BY_DEFAULT.evolve(since='0.40.0'),
         _EXTRA_ARGS_KW,
+        ENV_KW.evolve(since='1.2.0'),
         KwargInfo('dependencies', ContainerTypeInfo(list, Dependency), default=[], listify=True),
         KwargInfo('export_packages', ContainerTypeInfo(list, str), default=[], listify=True),
         KwargInfo('fatal_warnings', bool, default=False, since='0.55.0'),
diff --git a/mesonbuild/utils/core.py b/mesonbuild/utils/core.py
--- a/mesonbuild/utils/core.py
+++ b/mesonbuild/utils/core.py
@@ -99,6 +99,11 @@ def has_name(self, name: str) -> bool:
     def get_names(self) -> T.Set[str]:
         return self.varnames
 
+    def merge(self, other: EnvironmentVariables) -> None:
+        for method, name, values, separator in other.envvars:
+            self.varnames.add(name)
+            self.envvars.append((method, name, values, separator))
+
     def set(self, name: str, values: T.List[str], separator: str = os.pathsep) -> None:
         self.varnames.add(name)
         self.envvars.append((self._set, name, values, separator))


Test patch:
diff --git a/test cases/frameworks/7 gnome/gir/dep1/dep1.h b/test cases/frameworks/7 gnome/gir/dep1/dep1.h
--- a/test cases/frameworks/7 gnome/gir/dep1/dep1.h	
+++ b/test cases/frameworks/7 gnome/gir/dep1/dep1.h	
@@ -1,8 +1,8 @@
 #ifndef MESON_DEP1_H
 #define MESON_DEP1_H
 
-#if !defined (MESON_TEST)
-#error "MESON_TEST not defined."
+#if !defined (MESON_TEST_1)
+#error "MESON_TEST_1 not defined."
 #endif
 
 #include <glib-object.h>
diff --git a/test cases/frameworks/7 gnome/gir/dep1/dep2/dep2.h b/test cases/frameworks/7 gnome/gir/dep1/dep2/dep2.h
--- a/test cases/frameworks/7 gnome/gir/dep1/dep2/dep2.h	
+++ b/test cases/frameworks/7 gnome/gir/dep1/dep2/dep2.h	
@@ -1,8 +1,8 @@
 #ifndef MESON_DEP2_H
 #define MESON_DEP2_H
 
-#if !defined (MESON_TEST)
-#error "MESON_TEST not defined."
+#if !defined (MESON_TEST_1)
+#error "MESON_TEST_1 not defined."
 #endif
 
 #include <glib-object.h>
diff --git a/test cases/frameworks/7 gnome/gir/dep1/dep3/dep3.h b/test cases/frameworks/7 gnome/gir/dep1/dep3/dep3.h
--- a/test cases/frameworks/7 gnome/gir/dep1/dep3/dep3.h	
+++ b/test cases/frameworks/7 gnome/gir/dep1/dep3/dep3.h	
@@ -1,8 +1,8 @@
 #ifndef MESON_DEP3_H
 #define MESON_DEP3_H
 
-#if !defined (MESON_TEST)
-#error "MESON_TEST not defined."
+#if !defined (MESON_TEST_1)
+#error "MESON_TEST_1 not defined."
 #endif
 
 #include <glib-object.h>
diff --git a/test cases/frameworks/7 gnome/gir/meson-sample.h b/test cases/frameworks/7 gnome/gir/meson-sample.h
--- a/test cases/frameworks/7 gnome/gir/meson-sample.h	
+++ b/test cases/frameworks/7 gnome/gir/meson-sample.h	
@@ -1,8 +1,12 @@
 #ifndef MESON_SAMPLE_H
 #define MESON_SAMPLE_H
 
-#if !defined (MESON_TEST)
-#error "MESON_TEST not defined."
+#if !defined (MESON_TEST_1)
+#error "MESON_TEST_1 not defined."
+#endif
+
+#if !defined (MESON_TEST_2)
+#error "MESON_TEST_2 not defined."
 #endif
 
 #include <glib-object.h>
diff --git a/test cases/frameworks/7 gnome/gir/meson-sample2.h b/test cases/frameworks/7 gnome/gir/meson-sample2.h
--- a/test cases/frameworks/7 gnome/gir/meson-sample2.h	
+++ b/test cases/frameworks/7 gnome/gir/meson-sample2.h	
@@ -1,8 +1,8 @@
 #ifndef MESON_SAMPLE2_H
 #define MESON_SAMPLE2_H
 
-#if !defined (MESON_TEST)
-#error "MESON_TEST not defined."
+#if !defined (MESON_TEST_1)
+#error "MESON_TEST_1 not defined."
 #endif
 
 #include <glib-object.h>
diff --git a/test cases/frameworks/7 gnome/gir/meson.build b/test cases/frameworks/7 gnome/gir/meson.build
--- a/test cases/frameworks/7 gnome/gir/meson.build	
+++ b/test cases/frameworks/7 gnome/gir/meson.build	
@@ -14,6 +14,7 @@ gen_source = custom_target(
 girlib = shared_library(
   'gir_lib',
   sources : libsources,
+  c_args: '-DMESON_TEST_2',
   dependencies : [gobj, dep1_dep],
   install : true
 )
@@ -28,6 +29,7 @@ girlib2 = shared_library(
 girexe = executable(
   'girprog',
   sources : 'prog.c',
+  c_args: '-DMESON_TEST_2',
   dependencies : [glib, gobj, gir, dep1_dep],
   link_with : girlib
 )
@@ -37,6 +39,7 @@ fake_dep = dependency('no-way-this-exists', required: false)
 gnome.generate_gir(
   girlib, girlib2,
   sources : [libsources, lib2sources, gen_source],
+  env : {'CPPFLAGS': '-DMESON_TEST_2'},
   nsversion : '1.0',
   namespace : 'Meson',
   symbol_prefix : 'meson',
diff --git a/test cases/frameworks/7 gnome/meson.build b/test cases/frameworks/7 gnome/meson.build
--- a/test cases/frameworks/7 gnome/meson.build	
+++ b/test cases/frameworks/7 gnome/meson.build	
@@ -23,7 +23,7 @@ endif
 
 cc = meson.get_compiler('c')
 
-add_global_arguments('-DMESON_TEST', language : 'c')
+add_global_arguments('-DMESON_TEST_1', language : 'c')
 if cc.get_id() == 'intel'
   # Ignore invalid GCC pragma warnings from glib
   # https://bugzilla.gnome.org/show_bug.cgi?id=776562