Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/markdown/snippets/subproject_lang_args.md
Original file line number Diff line number Diff line change
@@ -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.
7 changes: 5 additions & 2 deletions mesonbuild/backend/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -973,8 +973,11 @@ def generate_basic_compiler_args(self, target: build.BuildTarget, compiler: 'Com
commands += self.build.get_global_args(compiler, target.for_machine)
# 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')
Expand Down
4 changes: 2 additions & 2 deletions mesonbuild/backend/ninjabackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -642,8 +642,8 @@ def detect_vs_dep_prefix(self, tempfilename: str) -> T.TextIO:
# cpp_args in a native file) so that cl.exe can locate system headers
# even when the INCLUDE environment variable is not set — for example,
# when using a bundled MSVC toolchain outside a VS Developer Shell.
extra_args = self.environment.coredata.get_external_args(
MachineChoice.HOST, compiler.language)
extra_args = T.cast('T.List[str]', self.environment.coredata.optstore.get_value_for(
OptionKey(f'{compiler.language}_args', machine=MachineChoice.HOST)))
pc = subprocess.Popen(compiler.get_exelist() +
['/showIncludes', '/c', filebase] + extra_args,
cwd=self.environment.get_scratch_dir(),
Expand Down
4 changes: 3 additions & 1 deletion mesonbuild/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -1917,7 +1917,9 @@ def get_external_rpath_dirs(self) -> T.Set[str]:
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)
Expand Down
4 changes: 3 additions & 1 deletion mesonbuild/cargo/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
PerMachine, unique_list, SubProject,
)
from .. import coredata, mlog
from ..options import OptionKey
from ..wrap.wrap import PackageDefinition

if T.TYPE_CHECKING:
Expand Down Expand Up @@ -712,7 +713,8 @@ def _get_cfgs(self, machine: MachineChoice) -> T.Dict[str, str]:
machine = MachineChoice.HOST
rustc = T.cast('RustCompiler', self.environment.coredata.compilers[machine]['rust'])
cfgs = rustc.get_cfgs().copy()
rustflags = self.environment.coredata.get_external_args(machine, 'rust')
rustflags = T.cast('T.List[str]', self.environment.coredata.optstore.get_value_for(
OptionKey('rust_args', machine=machine)))
rustflags_i = iter(rustflags)
for i in rustflags_i:
if i == '--cfg':
Expand Down
19 changes: 14 additions & 5 deletions mesonbuild/compilers/compilers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1195,9 +1195,13 @@ def get_build_link_args(self, target: BuildTarget, build: build.Build) -> T.List
# 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, self.for_machine) \
+ 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
Expand Down Expand Up @@ -1440,8 +1444,11 @@ def _sanity_check_compile_args(self, sourcename: str, binname: str
:return: a tuple of arguments, the first is the executable and compiler
arguments, the second is linker arguments
"""
cargs = list(self.environment.coredata.get_external_args(self.for_machine, self.language))
largs = list(self.environment.coredata.get_external_link_args(self.for_machine, self.language))
optstore = self.environment.coredata.optstore
cargs = list(T.cast('T.List[str]', optstore.get_value_for(
OptionKey(f'{self.language}_args', machine=self.for_machine))))
largs = list(T.cast('T.List[str]', optstore.get_value_for(
OptionKey(f'{self.language}_link_args', machine=self.for_machine))))
return self.exelist_no_ccache + self.get_always_args() + self.get_output_args(binname) + [sourcename] + cargs, largs

@abc.abstractmethod
Expand Down Expand Up @@ -1587,10 +1594,12 @@ def build_wrapper_args(self,

if mode is CompileCheckMode.COMPILE:
# Add DFLAGS from the env
args += self.environment.coredata.get_external_args(self.for_machine, self.language)
args += T.cast('T.List[str]', self.environment.coredata.optstore.get_value_for(
OptionKey(f'{self.language}_args', machine=self.for_machine)))
elif mode is CompileCheckMode.LINK:
# Add LDFLAGS from the env
args += self.environment.coredata.get_external_link_args(self.for_machine, self.language)
args += T.cast('T.List[str]', self.environment.coredata.optstore.get_value_for(
OptionKey(f'{self.language}_link_args', machine=self.for_machine)))
# extra_args must override all other arguments, so we add them last
args += extra_args
return args
Expand Down
7 changes: 5 additions & 2 deletions mesonbuild/compilers/fortran.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,11 @@ def has_function(self, funcname: str, prefix: str, *,
'that example is to see if the compiler has Fortran 2008 Block element.')

def _get_basic_compiler_args(self, mode: CompileCheckMode) -> T.Tuple[T.List[str], T.List[str]]:
cargs = self.environment.coredata.get_external_args(self.for_machine, self.language)
largs = self.environment.coredata.get_external_link_args(self.for_machine, self.language)
optstore = self.environment.coredata.optstore
cargs = list(T.cast('T.List[str]', optstore.get_value_for(
options.OptionKey(f'{self.language}_args', machine=self.for_machine))))
largs = list(T.cast('T.List[str]', optstore.get_value_for(
options.OptionKey(f'{self.language}_link_args', machine=self.for_machine))))
return cargs, largs

def _sanity_check_source_code(self) -> str:
Expand Down
10 changes: 7 additions & 3 deletions mesonbuild/compilers/mixins/clike.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from ... import arglist
from ... import mesonlib
from ... import mlog
from ...options import OptionKey
from ...linkers.linkers import GnuLikeDynamicLinkerMixin, SolarisDynamicLinker, CompCertDynamicLinker
from ...mesonlib import LibType
from .. import compilers
Expand Down Expand Up @@ -339,7 +340,8 @@ def _get_basic_compiler_args(self, mode: CompileCheckMode) -> T.Tuple[T.List[str
pass

# Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS and CPPFLAGS from the env
sys_args = self.environment.coredata.get_external_args(self.for_machine, self.language)
sys_args = T.cast('T.List[str]', self.environment.coredata.optstore.get_value_for(
OptionKey(f'{self.language}_args', machine=self.for_machine)))
if isinstance(sys_args, str):
sys_args = [sys_args]
# Apparently it is a thing to inject linker flags both
Expand All @@ -355,7 +357,8 @@ def _get_basic_compiler_args(self, mode: CompileCheckMode) -> T.Tuple[T.List[str
cargs += self.use_linker_args(ld_value[0], self.version)

# Add LDFLAGS from the env
sys_ld_args = self.environment.coredata.get_external_link_args(self.for_machine, self.language)
sys_ld_args = T.cast('T.List[str]', self.environment.coredata.optstore.get_value_for(
OptionKey(f'{self.language}_link_args', machine=self.for_machine)))
# CFLAGS and CXXFLAGS go to both linking and compiling, but we want them
# to only appear on the command line once. Remove dupes.
largs += [x for x in sys_ld_args if x not in cleaned_sys_args]
Expand Down Expand Up @@ -1202,7 +1205,8 @@ def find_framework_paths(self) -> T.List[str]:
commands = self.get_exelist(ccache=False) + ['-v', '-E', '-']
commands += self.get_always_args()
# Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS from the env
commands += self.environment.coredata.get_external_args(self.for_machine, self.language)
commands += T.cast('T.List[str]', self.environment.coredata.optstore.get_value_for(
OptionKey(f'{self.language}_args', machine=self.for_machine)))
mlog.debug('Finding framework path by running: ', ' '.join(commands), '\n')
os_env = os.environ.copy()
os_env['LC_ALL'] = 'C'
Expand Down
3 changes: 2 additions & 1 deletion mesonbuild/compilers/swift.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,8 @@ def _sanity_check_compile_args(self, sourcename: str, binname: str
if self.is_cross:
args.extend(self.get_compile_only_args())
else:
largs.extend(self.environment.coredata.get_external_link_args(self.for_machine, self.language))
largs.extend(T.cast('T.List[str]', self.environment.coredata.optstore.get_value_for(
options.OptionKey(f'{self.language}_link_args', machine=self.for_machine))))
args.extend(self.get_output_args(binname))
args.append(sourcename)

Expand Down
9 changes: 6 additions & 3 deletions mesonbuild/compilers/vala.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,8 @@ def find_library(self, libname: str, extra_dirs: T.List[str], libtype: LibType =
if not extra_dirs:
code = 'class MesonFindLibrary : Object { }'
args: T.List[str] = []
args += self.environment.coredata.get_external_args(self.for_machine, self.language)
args += T.cast('T.List[str]', self.environment.coredata.optstore.get_value_for(
OptionKey(f'{self.language}_args', machine=self.for_machine)))
vapi_args = ['--pkg', libname]
args += vapi_args
with self.cached_compile(code, extra_args=args, mode=CompileCheckMode.COMPILE) as p:
Expand Down Expand Up @@ -212,10 +213,12 @@ def build_wrapper_args(self,

if mode is CompileCheckMode.COMPILE:
# Add DFLAGS from the env
args += self.environment.coredata.get_external_args(self.for_machine, self.language)
args += T.cast('T.List[str]', self.environment.coredata.optstore.get_value_for(
OptionKey(f'{self.language}_args', machine=self.for_machine)))
elif mode is CompileCheckMode.LINK:
# Add LDFLAGS from the env
args += self.environment.coredata.get_external_link_args(self.for_machine, self.language)
args += T.cast('T.List[str]', self.environment.coredata.optstore.get_value_for(
OptionKey(f'{self.language}_link_args', machine=self.for_machine)))
# extra_args must override all other arguments, so we add them last
args += extra_args
return args
Expand Down
12 changes: 0 additions & 12 deletions mesonbuild/coredata.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from . import mlog, options
import pickle, os, uuid
import sys
from functools import lru_cache
from collections import OrderedDict
import textwrap

Expand Down Expand Up @@ -401,17 +400,6 @@ def get_nondefault_buildtype_args(self) -> T.List[T.Union[T.Tuple[str, str, str]
result.append(('debug', actual_debug, debug))
return result

def get_external_args(self, for_machine: MachineChoice, lang: str) -> T.List[str]:
# mypy cannot analyze type of OptionKey
key = OptionKey(f'{lang}_args', machine=for_machine)
return T.cast('T.List[str]', self.optstore.get_value_for(key))

@lru_cache(maxsize=None)
def get_external_link_args(self, for_machine: MachineChoice, lang: str) -> T.List[str]:
# mypy cannot analyze type of OptionKey
linkkey = OptionKey(f'{lang}_link_args', machine=for_machine)
return T.cast('T.List[str]', self.optstore.get_value_for(linkkey))

def is_cross_build(self, when_building_for: MachineChoice = MachineChoice.HOST) -> bool:
if when_building_for == MachineChoice.BUILD:
return False
Expand Down
8 changes: 5 additions & 3 deletions mesonbuild/linkers/detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
EnvironmentException,
Popen_safe, Popen_safe_logged, join_args, search_version
)
from ..options import OptionKey

import re
import shlex
Expand Down Expand Up @@ -53,7 +54,8 @@ def guess_win_linker(env: 'Environment', compiler: T.List[str], comp_class: T.Ty
else:
check_args = comp_class.LINKER_OPTION_STYLE.wrap(['/logo', '--version'])

check_args += env.coredata.get_external_link_args(for_machine, comp_class.language)
check_args += T.cast('T.List[str]', env.coredata.optstore.get_value_for(
OptionKey(f'{comp_class.language}_link_args', machine=for_machine)))

override: T.List[str] = []
value = env.lookup_binary_entry(for_machine, comp_class.language + '_ld')
Expand Down Expand Up @@ -123,12 +125,12 @@ def guess_nix_linker(env: 'Environment', compiler: T.List[str], comp_class: T.Ty
:extra_args: Any additional arguments required (such as a source file)
"""
from . import linkers
from ..options import OptionKey
env.add_lang_args(comp_class.language, comp_class, for_machine)
extra_args = extra_args or []

system = env.machines[for_machine].system
ldflags = env.coredata.get_external_link_args(for_machine, comp_class.language)
ldflags = T.cast('T.List[str]', env.coredata.optstore.get_value_for(
OptionKey(f'{comp_class.language}_link_args', machine=for_machine)))
extra_args += comp_class._unix_args_to_native(ldflags, env.machines[for_machine])
check_args = comp_class.LINKER_OPTION_STYLE.wrap(['--version']) + extra_args

Expand Down
4 changes: 2 additions & 2 deletions mesonbuild/modules/external_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,13 @@ def _configure(self, state: 'ModuleState') -> None:
for lang, compiler in self.env.coredata.compilers[MachineChoice.HOST].items():
if any(lang not in i for i in (ENV_VAR_PROG_MAP, CFLAGS_MAPPING)):
continue
cargs = self.env.coredata.get_external_args(MachineChoice.HOST, lang)
cargs = self.env.coredata.optstore.get_value_for(OptionKey(f'{lang}_args', self.subproject, MachineChoice.HOST))
assert isinstance(cargs, list), 'for mypy'
self.run_env[ENV_VAR_PROG_MAP[lang][0]] = self._quote_and_join(compiler.get_exelist())
self.run_env[CFLAGS_MAPPING[lang]] = self._quote_and_join(cargs)
if not link_exelist:
link_exelist = compiler.get_linker_exelist()
_l = self.env.coredata.get_external_link_args(MachineChoice.HOST, lang)
_l = self.env.coredata.optstore.get_value_for(OptionKey(f'{lang}_link_args', self.subproject, MachineChoice.HOST))
assert isinstance(_l, list), 'for mypy'
link_args = _l
if link_exelist:
Expand Down
11 changes: 6 additions & 5 deletions mesonbuild/modules/gnome.py
Original file line number Diff line number Diff line change
Expand Up @@ -856,7 +856,7 @@ def _scan_langs(state: 'ModuleState', langs: T.Iterable[str]) -> T.List[str]:
ret: T.List[str] = []

for lang in langs:
link_args = state.environment.coredata.get_external_link_args(MachineChoice.HOST, lang)
link_args = T.cast('T.List[str]', state.get_option(f'{lang}_link_args', state.subproject))
for link_arg in link_args:
if link_arg.startswith('-L'):
ret.append(link_arg)
Expand Down Expand Up @@ -1113,7 +1113,7 @@ def _gather_typelib_includes_and_update_depends(
def _get_external_args_for_langs(state: 'ModuleState', langs: T.List[str]) -> T.List[str]:
ret: T.List[str] = []
for lang in langs:
ret += mesonlib.listify(state.environment.coredata.get_external_args(MachineChoice.HOST, lang))
ret += mesonlib.listify(state.get_option(f'{lang}_args', state.subproject))
return ret

@staticmethod
Expand Down Expand Up @@ -1204,7 +1204,8 @@ def generate_gir(self, state: 'ModuleState', args: T.Tuple[T.List[T.Union[Execut
scan_cflags += list(self._get_scanner_cflags(self._get_external_args_for_langs(state, [lc[0] for lc in langs_compilers])))
scan_internal_ldflags = []
scan_external_ldflags = []
scan_env_ldflags = state.environment.coredata.get_external_link_args(MachineChoice.HOST, 'c')
# Copy: the returned list is the stored option value and gets appended to below.
scan_env_ldflags = list(T.cast('T.List[str]', state.get_option('c_link_args', state.subproject)))
for cli_flags, env_flags in (self._get_scanner_ldflags(internal_ldflags), self._get_scanner_ldflags(dep_internal_ldflags)):
scan_internal_ldflags += cli_flags
scan_env_ldflags += env_flags
Expand Down Expand Up @@ -1618,8 +1619,8 @@ def _get_build_args(self, c_args: T.List[str], inc_dirs: T.List[T.Union[str, bui
ldflags.extend(internal_ldflags)
ldflags.extend(external_ldflags)

cflags.extend(state.environment.coredata.get_external_args(MachineChoice.HOST, 'c'))
ldflags.extend(state.environment.coredata.get_external_link_args(MachineChoice.HOST, 'c'))
cflags.extend(T.cast('T.List[str]', state.get_option('c_args', state.subproject)))
ldflags.extend(T.cast('T.List[str]', state.get_option('c_link_args', state.subproject)))
compiler = state.environment.coredata.compilers[MachineChoice.HOST]['c']

compiler_flags = self._get_langs_compilers_flags(state, [('c', compiler)])
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0fd8007dd44a1a5eb5c01af4c138f0993c6cb44da194b36db04484212eff591b
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
project('subsubsub')

meson.override_dependency('subsubsub', declare_dependency())
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[wrap-redirect]
filename = sub_implicit/subprojects/subsub/subprojects/subsubsub.wrap
6 changes: 6 additions & 0 deletions test cases/unit/139 subproject lang args/meson.build
Original file line number Diff line number Diff line change
@@ -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'])
7 changes: 7 additions & 0 deletions test cases/unit/139 subproject lang args/over.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef OVERRIDE_FLAG
#error "OVERRIDE_FLAG not set"
#endif

int over(void) {
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
project('sub', 'c')

static_library('sub', 'sub.c')
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef SUB_FLAG
#error "SUB_FLAG not set"
#endif

int sub(void) {
return 0;
}
7 changes: 7 additions & 0 deletions test cases/unit/139 subproject lang args/top.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef TOP_FLAG
#error "TOP_FLAG not set"
#endif

int top(void) {
return 0;
}
Loading
Loading