backends: apply per-subproject language args to targets

Compile and link args were collected via CoreData.get_external_args()
and get_external_link_args(), which build an OptionKey without a
subproject. Per-subproject values such as -Dsub:c_args=-DFOO or c_args
in the default_options of a subproject() call were stored as augments
in the option store but never consulted, so they silently never reached
the compile or link command.

Resolve the value per target with the existing augment- and
override-aware CoreData.get_option_for_target() at the three
target-context call sites. As a side effect, <lang>_args and
<lang>_link_args entries in a target's override_options now take
effect as well.

Fixes #13260.
This commit is contained in:
Maxandre Ogeret authored and Paolo Bonzini committed 2026-08-14 12:25:21 +02:00
1 parent da57db736b
commit 67d7ddb36c
13 files changed
+81 -4

No files matched your search

@@ -0,0 +1,15 @@
## Per-subproject language arguments are now applied
Compiler and linker arguments set for a specific subproject, for example
`-Dsub:c_args=-DFOO` on the command line or `c_args` in the
`default_options` of a `subproject()` call, are now added to the compile
and link commands of that subproject's targets. Previously such values
were accepted and stored but silently ignored.
Similarly, `<lang>_args` and `<lang>_link_args` entries in a target's
`override_options` now take effect.
In all cases the per-subproject or per-target value replaces the global
value (including flags coming from environment variables such as
`CFLAGS`), it is not appended to it. This matches what
`get_option('c_args')` already returned inside a subproject.
+5 -2
View File
@@ -1027,8 +1027,11 @@ class Backend:
commands += self.build.get_global_args(compiler, target)
# Compile args added from the env: CFLAGS/CXXFLAGS, etc, or the cross
# file. We want these to override all the defaults, but not the
# per-target compile args.
commands += self.environment.coredata.get_external_args(target.for_machine, compiler.get_language())
# per-target compile args. Resolved per target so that per-subproject
# values (-Dsub:c_args=...) are honoured.
ext_args = self.environment.coredata.get_option_for_target(target, f'{compiler.get_language()}_args')
assert isinstance(ext_args, list), 'for mypy'
commands += ext_args
# Using both /Z7 or /ZI and /Zi at the same times produces a compiler warning.
# We do not add /Z7 or /ZI by default. If it is being used it is because the user has explicitly enabled it.
# /Zi needs to be removed in that case to avoid cl's warning to that effect (D9025 : overriding '/Zi' with '/ZI')
+3 -1
View File
@@ -1939,7 +1939,9 @@ class BuildTarget(Target):
args: T.List[str] = []
for lang in LANGUAGES_USING_LDFLAGS:
try:
args += self.environment.coredata.get_external_link_args(self.for_machine, lang)
largs = self.environment.coredata.get_option_for_target(self, f'{lang}_link_args')
assert isinstance(largs, list), 'for mypy'
args += largs
except KeyError:
pass
return self.get_rpath_dirs_from_link_args(args)
+5 -1
View File
@@ -1195,9 +1195,13 @@ class Compiler(HoldableObject, metaclass=SimpleABC):
# Link args added using add_global_link_arguments() override
# per-project link arguments. Link args added from the env (LDFLAGS)
# override all the defaults but not the per-target link args.
# Resolved per target so that per-subproject values
# (-Dsub:c_link_args=...) are honoured.
ext_link_args = self.environment.coredata.get_option_for_target(target, f'{self.get_language()}_link_args')
assert isinstance(ext_link_args, list), 'for mypy'
return build.get_project_link_args(self, target) \
+ build.get_global_link_args(self, target) \
+ self.environment.coredata.get_external_link_args(self.for_machine, self.get_language())
+ ext_link_args
def get_target_link_args(self, target: 'BuildTarget') -> T.List[str]:
return target.link_args
@@ -0,0 +1 @@
0fd8007dd44a1a5eb5c01af4c138f0993c6cb44da194b36db04484212eff591b
@@ -0,0 +1,3 @@
project('subsubsub')
meson.override_dependency('subsubsub', declare_dependency())
@@ -0,0 +1,2 @@
[wrap-redirect]
filename = sub_implicit/subprojects/subsub/subprojects/subsubsub.wrap
@@ -0,0 +1,6 @@
project('top', 'c')
subproject('sub')
static_library('top', 'top.c')
static_library('over', 'over.c', override_options: ['c_args=-DOVERRIDE_FLAG'])
@@ -0,0 +1,7 @@
#ifndef OVERRIDE_FLAG
#error "OVERRIDE_FLAG not set"
#endif
int over(void) {
return 0;
}
@@ -0,0 +1,3 @@
project('sub', 'c')
static_library('sub', 'sub.c')
@@ -0,0 +1,7 @@
#ifndef SUB_FLAG
#error "SUB_FLAG not set"
#endif
int sub(void) {
return 0;
}
@@ -0,0 +1,7 @@
#ifndef TOP_FLAG
#error "TOP_FLAG not set"
#endif
int top(void) {
return 0;
}
+17
View File
@@ -3462,6 +3462,23 @@ class AllPlatformTests(BasePlatformTests):
self.build()
self.run_tests()
def test_subproject_lang_args(self):
testdir = os.path.join(self.unit_test_dir, '139 subproject lang args')
self.init(testdir, extra_args=['-Dc_args=-DTOP_FLAG', '-Dsub:c_args=-DSUB_FLAG'])
# The source files #error out if their expected flag is missing.
self.build()
# A per-subproject or per-target value replaces the global one.
for cmd in self.get_compdb():
if cmd['file'].endswith('top.c'):
self.assertIn('-DTOP_FLAG', cmd['command'])
self.assertNotIn('-DSUB_FLAG', cmd['command'])
elif cmd['file'].endswith('sub.c'):
self.assertIn('-DSUB_FLAG', cmd['command'])
self.assertNotIn('-DTOP_FLAG', cmd['command'])
elif cmd['file'].endswith('over.c'):
self.assertIn('-DOVERRIDE_FLAG', cmd['command'])
self.assertNotIn('-DTOP_FLAG', cmd['command'])
def test_wipe_from_builddir(self):
testdir = os.path.join(self.common_test_dir, '157 custom target subdir depend files')
self.init(testdir)