Skip to content

Commit

Permalink
Environment: Fix passing envrionment variables CPPFLAGS and CFLAGS
Browse files Browse the repository at this point in the history
Or other language flags that use CPPFLAGS (like CXXFLAGS). The problem
here is actually rather simple, `dict.setdefault()` doesn't work like I
thought it did, I thought it created a weak entry, but it actually is
equivalent to:
```python
if k not in dict:
    dict[k] = v
```
Instead we'll use an intermediate dictionary (a default dictionary
actually, since that makes things a little cleaner) and then add the
keys from that dict to self.options as applicable.

Test case written by Jussi, Fix by Dylan

Co-authored-by: Jussi Pakkanen
Fixes: #8361
Fixes: #8345
  • Loading branch information
dcbaker authored and jpakkane committed Feb 17, 2021
1 parent 7812cee commit 10d94a1
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 8 deletions.
19 changes: 12 additions & 7 deletions mesonbuild/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,8 @@ def _set_default_options_from_env(self) -> None:
]
)

env_opts: T.DefaultDict[OptionKey, T.List[str]] = collections.defaultdict(list)

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:
Expand All @@ -805,7 +807,7 @@ def _set_default_options_from_env(self) -> None:
p_list = list(mesonlib.OrderedSet(p_env.split(':')))
else:
p_list = split_args(p_env)
p_list = [e for e in p_list if e] # filter out any empty eelemnts
p_list = [e for e in p_list if e] # filter out any empty elements

# Take env vars only on first invocation, if the env changes when
# reconfiguring it gets ignored.
Expand All @@ -816,18 +818,21 @@ def _set_default_options_from_env(self) -> None:
key = OptionKey('link_args', machine=for_machine, lang='c') # needs a language to initialize properly
for lang in compilers.compilers.LANGUAGES_USING_LDFLAGS:
key = key.evolve(lang=lang)
v = mesonlib.listify(self.options.get(key, []))
self.options.setdefault(key, v + p_list)
env_opts[key].extend(p_list)
elif keyname == 'cppflags':
key = OptionKey('args', machine=for_machine, lang='c')
for lang in compilers.compilers.LANGUAGES_USING_CPPFLAGS:
key = key.evolve(lang=lang)
v = mesonlib.listify(self.options.get(key, []))
self.options.setdefault(key, v + p_list)
env_opts[key].extend(p_list)
else:
key = OptionKey.from_string(keyname).evolve(machine=for_machine)
v = mesonlib.listify(self.options.get(key, []))
self.options.setdefault(key, v + p_list)
env_opts[key].extend(p_list)

# Only store options that are not already in self.options,
# otherwise we'd override the machine files
for k, v in env_opts.items():
if k not in self.options:
self.options[k] = v

def _set_default_binaries_from_env(self) -> None:
"""Set default binaries from the environment.
Expand Down
1 change: 0 additions & 1 deletion mesonbuild/mesonlib/universal.py
Original file line number Diff line number Diff line change
Expand Up @@ -2023,7 +2023,6 @@ def from_string(cls, raw: str) -> 'OptionKey':
This takes strings like `mysubproject:build.myoption` and Creates an
OptionKey out of them.
"""

try:
subproject, raw2 = raw.split(':')
except ValueError:
Expand Down
8 changes: 8 additions & 0 deletions run_unittests.py
Original file line number Diff line number Diff line change
Expand Up @@ -5476,6 +5476,14 @@ def test_version_file(self):
projinfo = self.introspect('--projectinfo')
self.assertEqual(projinfo['version'], '1.0.0')

def test_cflags_cppflags(self):
envs = {'CPPFLAGS': '-DCPPFLAG',
'CFLAGS': '-DCFLAG',
'CXXFLAGS': '-DCXXFLAG'}
srcdir = os.path.join(self.unit_test_dir, '90 multiple envvars')
self.init(srcdir, override_envvars=envs)
self.build()


class FailureTests(BasePlatformTests):
'''
Expand Down
4 changes: 4 additions & 0 deletions test cases/unit/90 multiple envvars/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
project('multienv', 'c', 'cpp')

executable('cexe', 'prog.c')
executable('cppexe', 'prog.cpp')
18 changes: 18 additions & 0 deletions test cases/unit/90 multiple envvars/prog.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include<stdio.h>

#ifndef CPPFLAG
#error CPPFLAG not set
#endif

#ifndef CFLAG
#error CFLAGS not set
#endif

#ifdef CXXFLAG
#error CXXFLAG is set
#endif

int main(int argc, char **argv) {
printf("%d %s\n", argc, argv[0]);
return 0;
}
18 changes: 18 additions & 0 deletions test cases/unit/90 multiple envvars/prog.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include<cstdio>

#ifndef CPPFLAG
#error CPPFLAG not set
#endif

#ifdef CFLAG
#error CFLAG is set
#endif

#ifndef CXXFLAG
#error CXXFLAG not set
#endif

int main(int argc, char **argv) {
printf("%d %s\n", argc, argv[0]);
return 0;
}

0 comments on commit 10d94a1

Please sign in to comment.