Merge pull request #5263 from Ericson2314/per-machine-cli-args

Per machine 'build_' and '' options
pull/4421/merge
Jussi Pakkanen 6 years ago committed by GitHub
commit 09a722c4bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 55
      docs/markdown/Builtin-options.md
  2. 15
      docs/markdown/snippets/per-machine-options.md
  3. 195
      mesonbuild/coredata.py
  4. 17
      mesonbuild/dependencies/base.py
  5. 25
      mesonbuild/interpreter.py
  6. 13
      mesonbuild/mconf.py
  7. 12
      mesonbuild/mesonlib.py
  8. 14
      mesonbuild/mintro.py
  9. 7
      mesonbuild/rewriter.py
  10. 27
      run_unittests.py
  11. 2
      test cases/unit/50 std remains/meson.build
  12. 1
      test cases/unit/50 std remains/prog.c
  13. 7
      test cases/unit/55 pkg_config_path option/build_extra_path/totally_made_up_dep.pc
  14. 0
      test cases/unit/55 pkg_config_path option/host_extra_path/totally_made_up_dep.pc
  15. 11
      test cases/unit/55 pkg_config_path option/meson.build

@ -52,31 +52,36 @@ on Linux platforms.
### Core options ### Core options
Options that have a separate cross option will be prefixed with Options that are labled "per machine" in the table are set per machine.
cross\_, for example, "cross_pkg_config_path" controls the paths Prefixing the option with `build.` just affects the build machine configuration,
pkg-config will search for host dependencies in a cross compile. while unprefixed just affects the host machine configuration, respectively.
They have no effect when the host and build machines are the same. Using the option as-is with no prefix affects all machines. For example:
- `build.pkg_config_path` controls the paths pkg-config will search for just
| Option | Default value | Description | Has Separate cross | `native: true` dependencies (build machine).
| ------ | ------------- | ----------- | ------------------ |
| auto_features {enabled, disabled, auto} | auto | Override value of all 'auto' features | no | - `pkg_config_path` controls the paths pkg-config will search for just
| backend {ninja, vs,<br>vs2010, vs2015, vs2017, xcode} | ninja | Backend to use | no | `native: false` dependencies (host machine).
| buildtype {plain, debug,<br>debugoptimized, release, minsize, custom} | debug | Build type to use | no |
| debug | true | Debug | no | | Option | Default value | Description | Is per machine |
| default_library {shared, static, both} | shared | Default library type | no | | ------ | ------------- | ----------- | -------------- |
| errorlogs | true | Whether to print the logs from failing tests. | no | | auto_features {enabled, disabled, auto} | auto | Override value of all 'auto' features | no |
| install_umask {preserve, 0000-0777} | 022 | Default umask to apply on permissions of installed files | no | | backend {ninja, vs,<br>vs2010, vs2015, vs2017, xcode} | ninja | Backend to use | no |
| layout {mirror,flat} | mirror | Build directory layout | no | | buildtype {plain, debug,<br>debugoptimized, release, minsize, custom} | debug | Build type to use | no |
| optimization {0, g, 1, 2, 3, s} | 0 | Optimization level | no | | debug | true | Debug | no |
| pkg_config_path | [] | Additional paths for pkg-config to search before builtin paths | yes | | default_library {shared, static, both} | shared | Default library type | no |
| cmake_prefix_path | [] | Additional prefixes for cmake to search before builtin paths | yes | | errorlogs | true | Whether to print the logs from failing tests. | no |
| stdsplit | true | Split stdout and stderr in test logs | no | | install_umask {preserve, 0000-0777} | 022 | Default umask to apply on permissions of installed files | no |
| strip | false | Strip targets on install | no | | layout {mirror,flat} | mirror | Build directory layout | no |
| unity {on, off, subprojects} | off | Unity build | no | | optimization {0, g, 1, 2, 3, s} | 0 | Optimization level | no |
| warning_level {0, 1, 2, 3} | 1 | Set the warning level. From 0 = none to 3 = highest | no | | pkg_config_path {OS separated path} | '' | Additional paths for pkg-config to search before builtin paths | yes |
| werror | false | Treat warnings as errors | no | | cmake_prefix_path | [] | Additional prefixes for cmake to search before builtin paths | yes |
| wrap_mode {default, nofallback,<br>nodownload, forcefallback} | default | Wrap mode to use | no | | stdsplit | true | Split stdout and stderr in test logs | no |
| strip | false | Strip targets on install | no |
| unity {on, off, subprojects} | off | Unity build | no |
| warning_level {0, 1, 2, 3} | 1 | Set the warning level. From 0 = none to 3 = highest | no |
| werror | false | Treat warnings as errors | no |
| wrap_mode {default, nofallback,<br>nodownload, forcefallback} | default | Wrap mode to use | no |
## Base options ## Base options

@ -0,0 +1,15 @@
## Specifying options per mer machine
Previously, no cross builds were controllable from the command line.
Machine-specific options like the pkg-config path and compiler options only
affected native targets, that is to say all targets in native builds, and
`native: true` targets in cross builds. Now, prefix the option with `build.` to
affect build machine targets, and leave it unprefixed to affect host machine
targets.
For those trying to ensure native and cross builds to the same platform produced
the same result, the old way was frustrating because very different invocations
were needed to affect the same targets, if it was possible at all. Now, the same
command line arguments affect the same targets everwhere --- Meson is closer to
ignoring whether the "overall" build is native or cross, and just caring about
whether individual targets are for the build or host machines.

@ -26,7 +26,9 @@ from .wrap import WrapMode
import ast import ast
import argparse import argparse
import configparser import configparser
from typing import Optional, Any, TypeVar, Generic, Type, List, Union from typing import (
Any, Dict, Generic, Iterable, List, Optional, Type, TypeVar, Union
)
import typing import typing
import enum import enum
@ -275,20 +277,16 @@ class DependencyCache:
successfully lookup by providing a simple get/put interface. successfully lookup by providing a simple get/put interface.
""" """
def __init__(self, builtins: typing.Dict[str, UserOption[typing.Any]], cross: bool): def __init__(self, builtins_per_machine: PerMachine[typing.Dict[str, UserOption[typing.Any]]], for_machine: MachineChoice):
self.__cache = OrderedDict() # type: typing.MutableMapping[CacheKeyType, DependencySubCache] self.__cache = OrderedDict() # type: typing.MutableMapping[CacheKeyType, DependencySubCache]
self.__builtins = builtins self.__builtins_per_machine = builtins_per_machine
self.__is_cross = cross self.__for_machine = for_machine
def __calculate_subkey(self, type_: DependencyCacheType) -> typing.Tuple[typing.Any, ...]: def __calculate_subkey(self, type_: DependencyCacheType) -> typing.Tuple[typing.Any, ...]:
if type_ is DependencyCacheType.PKG_CONFIG: if type_ is DependencyCacheType.PKG_CONFIG:
if self.__is_cross: return tuple(self.__builtins_per_machine[self.__for_machine]['pkg_config_path'].value)
return tuple(self.__builtins['cross_pkg_config_path'].value)
return tuple(self.__builtins['pkg_config_path'].value)
elif type_ is DependencyCacheType.CMAKE: elif type_ is DependencyCacheType.CMAKE:
if self.__is_cross: return tuple(self.__builtins_per_machine[self.__for_machine]['cmake_prefix_path'].value)
return tuple(self.__builtins['cross_cmake_prefix_path'].value)
return tuple(self.__builtins['cmake_prefix_path'].value)
assert type_ is DependencyCacheType.OTHER, 'Someone forgot to update subkey calculations for a new type' assert type_ is DependencyCacheType.OTHER, 'Someone forgot to update subkey calculations for a new type'
return tuple() return tuple()
@ -339,6 +337,9 @@ class DependencyCache:
def clear(self) -> None: def clear(self) -> None:
self.__cache.clear() self.__cache.clear()
# Can't bind this near the class method it seems, sadly.
_V = TypeVar('_V')
# This class contains all data that must persist over multiple # This class contains all data that must persist over multiple
# invocations of Meson. It is roughly the same thing as # invocations of Meson. It is roughly the same thing as
# cmakecache. # cmakecache.
@ -359,19 +360,16 @@ class CoreData:
self.target_guids = {} self.target_guids = {}
self.version = version self.version = version
self.init_builtins() self.init_builtins()
self.backend_options = {} self.backend_options = {} # : Dict[str, UserOption]
self.user_options = {} self.user_options = {} # : Dict[str, UserOption]
self.compiler_options = PerMachine({}, {}) self.compiler_options = PerMachine({}, {})
self.base_options = {} self.base_options = {} # : Dict[str, UserOption]
self.cross_files = self.__load_config_files(options.cross_file, 'cross') self.cross_files = self.__load_config_files(options.cross_file, 'cross')
self.compilers = OrderedDict() self.compilers = OrderedDict()
self.cross_compilers = OrderedDict() self.cross_compilers = OrderedDict()
build_cache = DependencyCache(self.builtins, False) build_cache = DependencyCache(self.builtins_per_machine, MachineChoice.BUILD)
if self.cross_files: host_cache = DependencyCache(self.builtins_per_machine, MachineChoice.BUILD)
host_cache = DependencyCache(self.builtins, True)
else:
host_cache = build_cache
self.deps = PerMachine(build_cache, host_cache) # type: PerMachine[DependencyCache] self.deps = PerMachine(build_cache, host_cache) # type: PerMachine[DependencyCache]
self.compiler_check_cache = OrderedDict() self.compiler_check_cache = OrderedDict()
@ -462,8 +460,10 @@ class CoreData:
self.builtins = {} self.builtins = {}
for key, opt in builtin_options.items(): for key, opt in builtin_options.items():
self.builtins[key] = opt.init_option() self.builtins[key] = opt.init_option()
if opt.separate_cross: self.builtins_per_machine = PerMachine({}, {})
self.builtins['cross_' + key] = opt.init_option() for for_machine in iter(MachineChoice):
for key, opt in builtin_options_per_machine.items():
self.builtins_per_machine[for_machine][key] = opt.init_option()
def init_backend_options(self, backend_name): def init_backend_options(self, backend_name):
if backend_name == 'ninja': if backend_name == 'ninja':
@ -479,28 +479,40 @@ class CoreData:
'') '')
def get_builtin_option(self, optname): def get_builtin_option(self, optname):
if optname in self.builtins: for opts in self._get_all_builtin_options():
v = self.builtins[optname] v = opts.get(optname)
if v is None:
continue
if optname == 'wrap_mode': if optname == 'wrap_mode':
return WrapMode.from_string(v.value) return WrapMode.from_string(v.value)
return v.value return v.value
raise RuntimeError('Tried to get unknown builtin option %s.' % optname) raise RuntimeError('Tried to get unknown builtin option %s.' % optname)
def set_builtin_option(self, optname, value): def _try_set_builtin_option(self, optname, value):
if optname == 'prefix': for opts in self._get_all_builtin_options():
value = self.sanitize_prefix(value) opt = opts.get(optname)
elif optname in self.builtins: if opt is None:
prefix = self.builtins['prefix'].value continue
value = self.sanitize_dir_option_value(prefix, optname, value) if optname == 'prefix':
value = self.sanitize_prefix(value)
else:
prefix = self.builtins['prefix'].value
value = self.sanitize_dir_option_value(prefix, optname, value)
break
else: else:
raise RuntimeError('Tried to set unknown builtin option %s.' % optname) return False
self.builtins[optname].set_value(value) opt.set_value(value)
# Make sure that buildtype matches other settings. # Make sure that buildtype matches other settings.
if optname == 'buildtype': if optname == 'buildtype':
self.set_others_from_buildtype(value) self.set_others_from_buildtype(value)
else: else:
self.set_buildtype_from_others() self.set_buildtype_from_others()
return True
def set_builtin_option(self, optname, value):
res = self._try_set_builtin_option(optname, value)
if not res:
raise RuntimeError('Tried to set unknown builtin option %s.' % optname)
def set_others_from_buildtype(self, value): def set_others_from_buildtype(self, value):
if value == 'plain': if value == 'plain':
@ -541,29 +553,42 @@ class CoreData:
mode = 'custom' mode = 'custom'
self.builtins['buildtype'].set_value(mode) self.builtins['buildtype'].set_value(mode)
def get_all_compiler_options(self): @staticmethod
# TODO think about cross and command-line interface. (Only .build is mentioned here.) def get_prefixed_options_per_machine(
yield self.compiler_options.build options_per_machine # : PerMachine[Dict[str, _V]]]
) -> Iterable[Dict[str, _V]]:
def _get_all_nonbuiltin_options(self): for for_machine in iter(MachineChoice):
prefix = for_machine.get_prefix()
yield {
prefix + k: v
for k, v in options_per_machine[for_machine].items()
}
def _get_all_nonbuiltin_options(self) -> Iterable[Dict[str, UserOption]]:
yield self.backend_options yield self.backend_options
yield self.user_options yield self.user_options
yield from self.get_all_compiler_options() yield from self.get_prefixed_options_per_machine(self.compiler_options)
yield self.base_options yield self.base_options
def get_all_options(self): def _get_all_builtin_options(self) -> Dict[str, UserOption]:
return chain([self.builtins], self._get_all_nonbuiltin_options()) yield from self.get_prefixed_options_per_machine(self.builtins_per_machine)
yield self.builtins
def get_all_options(self) -> Dict[str, UserOption]:
yield from self._get_all_nonbuiltin_options()
yield from self._get_all_builtin_options()
def validate_option_value(self, option_name, override_value): def validate_option_value(self, option_name, override_value):
for opts in self.get_all_options(): for opts in self.get_all_options():
if option_name in opts: opt = opts.get(option_name)
opt = opts[option_name] if opt is not None:
try: try:
return opt.validate_value(override_value) return opt.validate_value(override_value)
except MesonException as e: except MesonException as e:
raise type(e)(('Validation failed for option %s: ' % option_name) + str(e)) \ raise type(e)(('Validation failed for option %s: ' % option_name) + str(e)) \
.with_traceback(sys.exc_into()[2]) .with_traceback(sys.exc_into()[2])
raise MesonException('Tried to validate unknown option %s.' % option_name) else:
raise MesonException('Tried to validate unknown option %s.' % option_name)
def get_external_args(self, for_machine: MachineChoice, lang): def get_external_args(self, for_machine: MachineChoice, lang):
return self.compiler_options[for_machine][lang + '_args'].value return self.compiler_options[for_machine][lang + '_args'].value
@ -593,17 +618,17 @@ class CoreData:
unknown_options = [] unknown_options = []
for k, v in options.items(): for k, v in options.items():
if k == 'prefix': if k == 'prefix':
pass continue
elif k in self.builtins: if self._try_set_builtin_option(k, v):
self.set_builtin_option(k, v) continue
for opts in self._get_all_nonbuiltin_options():
tgt = opts.get(k)
if tgt is None:
continue
tgt.set_value(v)
break
else: else:
for opts in self._get_all_nonbuiltin_options(): unknown_options.append(k)
if k in opts:
tgt = opts[k]
tgt.set_value(v)
break
else:
unknown_options.append(k)
if unknown_options and warn_unknown: if unknown_options and warn_unknown:
unknown_options = ', '.join(sorted(unknown_options)) unknown_options = ', '.join(sorted(unknown_options))
sub = 'In subproject {}: '.format(subproject) if subproject else '' sub = 'In subproject {}: '.format(subproject) if subproject else ''
@ -645,7 +670,9 @@ class CoreData:
if subproject: if subproject:
if not k.startswith(subproject + ':'): if not k.startswith(subproject + ':'):
continue continue
elif k not in builtin_options: elif k not in builtin_options.keys() \
and 'build.' + k not in builtin_options_per_machine.keys() \
and k not in builtin_options_per_machine.keys():
if ':' in k: if ':' in k:
continue continue
if optinterpreter.is_invalid_name(k, log=False): if optinterpreter.is_invalid_name(k, log=False):
@ -666,7 +693,7 @@ class CoreData:
if cross_comp is not None: if cross_comp is not None:
new_options_for_host = cross_comp.get_and_default_options(env.properties.host) new_options_for_host = cross_comp.get_and_default_options(env.properties.host)
else: else:
new_options_for_host = new_options_for_build new_options_for_host = comp.get_and_default_options(env.properties.host)
opts_machines_list = [ opts_machines_list = [
(new_options_for_build, MachineChoice.BUILD), (new_options_for_build, MachineChoice.BUILD),
@ -678,10 +705,10 @@ class CoreData:
for k, o in new_options.items(): for k, o in new_options.items():
if not k.startswith(optprefix): if not k.startswith(optprefix):
raise MesonException('Internal error, %s has incorrect prefix.' % k) raise MesonException('Internal error, %s has incorrect prefix.' % k)
if (env.machines.matches_build_machine(for_machine) and # prefixed compiler options affect just this machine
k in env.cmd_line_options): opt_prefix = for_machine.get_prefix()
# TODO think about cross and command-line interface. if opt_prefix + k in env.cmd_line_options:
o.set_value(env.cmd_line_options[k]) o.set_value(env.cmd_line_options[opt_prefix + k])
self.compiler_options[for_machine].setdefault(k, o) self.compiler_options[for_machine].setdefault(k, o)
enabled_opts = [] enabled_opts = []
@ -794,7 +821,10 @@ def save(obj, build_dir):
def register_builtin_arguments(parser): def register_builtin_arguments(parser):
for n, b in builtin_options.items(): for n, b in builtin_options.items():
b.add_to_argparse(n, parser) b.add_to_argparse(n, parser, '', '')
for n, b in builtin_options_per_machine.items():
b.add_to_argparse(n, parser, '', ' (just for host machine)')
b.add_to_argparse(n, parser, 'build.', ' (just for build machine)')
parser.add_argument('-D', action='append', dest='projectoptions', default=[], metavar="option", parser.add_argument('-D', action='append', dest='projectoptions', default=[], metavar="option",
help='Set the value of an option, can be used several times to set multiple options.') help='Set the value of an option, can be used several times to set multiple options.')
@ -812,19 +842,19 @@ def parse_cmd_line_options(args):
args.cmd_line_options = create_options_dict(args.projectoptions) args.cmd_line_options = create_options_dict(args.projectoptions)
# Merge builtin options set with --option into the dict. # Merge builtin options set with --option into the dict.
for name, builtin in builtin_options.items(): for name in chain(
names = [name] builtin_options.keys(),
if builtin.separate_cross: ('build.' + k for k in builtin_options_per_machine.keys()),
names.append('cross_' + name) builtin_options_per_machine.keys(),
for name in names: ):
value = getattr(args, name, None) value = getattr(args, name, None)
if value is not None: if value is not None:
if name in args.cmd_line_options: if name in args.cmd_line_options:
cmdline_name = BuiltinOption.argparse_name_to_arg(name) cmdline_name = BuiltinOption.argparse_name_to_arg(name)
raise MesonException( raise MesonException(
'Got argument {0} as both -D{0} and {1}. Pick one.'.format(name, cmdline_name)) 'Got argument {0} as both -D{0} and {1}. Pick one.'.format(name, cmdline_name))
args.cmd_line_options[name] = value args.cmd_line_options[name] = value
delattr(args, name) delattr(args, name)
_U = TypeVar('_U', bound=UserOption[_T]) _U = TypeVar('_U', bound=UserOption[_T])
@ -837,13 +867,12 @@ class BuiltinOption(Generic[_T, _U]):
""" """
def __init__(self, opt_type: Type[_U], description: str, default: Any, yielding: Optional[bool] = None, *, def __init__(self, opt_type: Type[_U], description: str, default: Any, yielding: Optional[bool] = None, *,
choices: Any = None, separate_cross: bool = False): choices: Any = None):
self.opt_type = opt_type self.opt_type = opt_type
self.description = description self.description = description
self.default = default self.default = default
self.choices = choices self.choices = choices
self.yielding = yielding self.yielding = yielding
self.separate_cross = separate_cross
def init_option(self) -> _U: def init_option(self) -> _U:
"""Create an instance of opt_type and return it.""" """Create an instance of opt_type and return it."""
@ -882,7 +911,7 @@ class BuiltinOption(Generic[_T, _U]):
pass pass
return self.default return self.default
def add_to_argparse(self, name: str, parser: argparse.ArgumentParser) -> None: def add_to_argparse(self, name: str, parser: argparse.ArgumentParser, prefix: str, help_suffix: str) -> None:
kwargs = {} kwargs = {}
c = self._argparse_choices() c = self._argparse_choices()
@ -895,13 +924,10 @@ class BuiltinOption(Generic[_T, _U]):
if c and not b: if c and not b:
kwargs['choices'] = c kwargs['choices'] = c
kwargs['default'] = argparse.SUPPRESS kwargs['default'] = argparse.SUPPRESS
kwargs['dest'] = name kwargs['dest'] = prefix + name
cmdline_name = self.argparse_name_to_arg(name) cmdline_name = self.argparse_name_to_arg(prefix + name)
parser.add_argument(cmdline_name, help=h, **kwargs) parser.add_argument(cmdline_name, help=h + help_suffix, **kwargs)
if self.separate_cross:
kwargs['dest'] = 'cross_' + name
parser.add_argument(self.argparse_name_to_arg('cross_' + name), help=h + ' (for host in cross compiles)', **kwargs)
# Update `docs/markdown/Builtin-options.md` after changing the options below # Update `docs/markdown/Builtin-options.md` after changing the options below
builtin_options = OrderedDict([ builtin_options = OrderedDict([
@ -929,8 +955,6 @@ builtin_options = OrderedDict([
('errorlogs', BuiltinOption(UserBooleanOption, "Whether to print the logs from failing tests", True)), ('errorlogs', BuiltinOption(UserBooleanOption, "Whether to print the logs from failing tests", True)),
('install_umask', BuiltinOption(UserUmaskOption, 'Default umask to apply on permissions of installed files', '022')), ('install_umask', BuiltinOption(UserUmaskOption, 'Default umask to apply on permissions of installed files', '022')),
('layout', BuiltinOption(UserComboOption, 'Build directory layout', 'mirror', choices=['mirror', 'flat'])), ('layout', BuiltinOption(UserComboOption, 'Build directory layout', 'mirror', choices=['mirror', 'flat'])),
('pkg_config_path', BuiltinOption(UserArrayOption, 'List of additional paths for pkg-config to search', [], separate_cross=True)),
('cmake_prefix_path', BuiltinOption(UserArrayOption, 'List of additional prefixes for cmake to search', [], separate_cross=True)),
('optimization', BuiltinOption(UserComboOption, 'Optimization level', '0', choices=['0', 'g', '1', '2', '3', 's'])), ('optimization', BuiltinOption(UserComboOption, 'Optimization level', '0', choices=['0', 'g', '1', '2', '3', 's'])),
('stdsplit', BuiltinOption(UserBooleanOption, 'Split stdout and stderr in test logs', True)), ('stdsplit', BuiltinOption(UserBooleanOption, 'Split stdout and stderr in test logs', True)),
('strip', BuiltinOption(UserBooleanOption, 'Strip targets on install', False)), ('strip', BuiltinOption(UserBooleanOption, 'Strip targets on install', False)),
@ -940,6 +964,11 @@ builtin_options = OrderedDict([
('wrap_mode', BuiltinOption(UserComboOption, 'Wrap mode', 'default', choices=['default', 'nofallback', 'nodownload', 'forcefallback'])), ('wrap_mode', BuiltinOption(UserComboOption, 'Wrap mode', 'default', choices=['default', 'nofallback', 'nodownload', 'forcefallback'])),
]) ])
builtin_options_per_machine = OrderedDict([
('pkg_config_path', BuiltinOption(UserArrayOption, 'List of additional paths for pkg-config to search', [])),
('cmake_prefix_path', BuiltinOption(UserArrayOption, 'List of additional prefixes for cmake to search', [])),
])
# Special prefix-dependent defaults for installation directories that reside in # Special prefix-dependent defaults for installation directories that reside in
# a path outside of the prefix in FHS and common usage. # a path outside of the prefix in FHS and common usage.
builtin_dir_noprefix_options = { builtin_dir_noprefix_options = {

@ -665,11 +665,15 @@ class PkgConfigDependency(ExternalDependency):
else: else:
env = env.copy() env = env.copy()
if self.want_cross: if not self.want_cross and self.env.is_cross_build():
extra_paths = self.env.coredata.get_builtin_option('cross_pkg_config_path') for_machine = MachineChoice.BUILD
else: else:
extra_paths = self.env.coredata.get_builtin_option('pkg_config_path') for_machine = MachineChoice.HOST
env['PKG_CONFIG_PATH'] = ':'.join([p for p in extra_paths])
extra_paths = self.env.coredata.builtins_per_machine[for_machine]['pkg_config_path'].value
new_pkg_config_path = ':'.join([p for p in extra_paths])
mlog.debug('PKG_CONFIG_PATH: ' + new_pkg_config_path)
env['PKG_CONFIG_PATH'] = new_pkg_config_path
fenv = frozenset(env.items()) fenv = frozenset(env.items())
targs = tuple(args) targs = tuple(args)
cache = PkgConfigDependency.pkgbin_cache cache = PkgConfigDependency.pkgbin_cache
@ -1134,10 +1138,7 @@ class CMakeDependency(ExternalDependency):
if cm_path: if cm_path:
cm_args.append('-DCMAKE_MODULE_PATH=' + ';'.join(cm_path)) cm_args.append('-DCMAKE_MODULE_PATH=' + ';'.join(cm_path))
if environment.is_cross_build() and self.want_cross: pref_path = self.env.coredata.builtins_per_machine[for_machine]['cmake_prefix_path'].value
pref_path = self.env.coredata.builtins['cross_cmake_prefix_path'].value
else:
pref_path = self.env.coredata.builtins['cmake_prefix_path'].value
if pref_path: if pref_path:
cm_args.append('-DCMAKE_PREFIX_PATH={}'.format(';'.join(pref_path))) cm_args.append('-DCMAKE_PREFIX_PATH={}'.format(';'.join(pref_path)))

@ -2097,12 +2097,12 @@ class Interpreter(InterpreterBase):
def get_non_matching_default_options(self): def get_non_matching_default_options(self):
env = self.environment env = self.environment
for def_opt_name, def_opt_value in self.project_default_options.items(): for def_opt_name, def_opt_value in self.project_default_options.items():
for option_type in env.coredata.get_all_options(): for opts in env.coredata.get_all_options():
for cur_opt_name, cur_opt_value in option_type.items(): cur_opt_value = opts.get(def_opt_name)
if def_opt_name == cur_opt_name: if cur_opt_value is not None:
def_opt_value = env.coredata.validate_option_value(def_opt_name, def_opt_value) def_opt_value = env.coredata.validate_option_value(def_opt_name, def_opt_value)
if def_opt_value != cur_opt_value.value: if def_opt_value != cur_opt_value.value:
yield (def_opt_name, def_opt_value, cur_opt_value) yield (def_opt_name, def_opt_value, cur_opt_value)
def build_func_dict(self): def build_func_dict(self):
self.funcs.update({'add_global_arguments': self.func_add_global_arguments, self.funcs.update({'add_global_arguments': self.func_add_global_arguments,
@ -2519,13 +2519,14 @@ external dependencies (including libraries) must go to "dependencies".''')
return self.subprojects[dirname] return self.subprojects[dirname]
def get_option_internal(self, optname): def get_option_internal(self, optname):
for d in chain( for opts in chain(
[self.coredata.base_options, compilers.base_options, self.coredata.builtins], [self.coredata.base_options, compilers.base_options, self.coredata.builtins],
self.coredata.get_all_compiler_options()): self.coredata.get_prefixed_options_per_machine(self.coredata.builtins_per_machine),
try: self.coredata.get_prefixed_options_per_machine(self.coredata.compiler_options),
return d[optname] ):
except KeyError: v = opts.get(optname)
pass if v is not None:
return v
raw_optname = optname raw_optname = optname
if self.is_subproject(): if self.is_subproject():

@ -181,10 +181,16 @@ class Conf:
core_options = {k: o for k, o in self.coredata.builtins.items() if k in core_option_names} core_options = {k: o for k, o in self.coredata.builtins.items() if k in core_option_names}
self.print_options('Core options', core_options) self.print_options('Core options', core_options)
self.print_options('Core options (for host machine)', self.coredata.builtins_per_machine.host)
self.print_options(
'Core options (for build machine)',
{'build.' + k: o for k, o in self.coredata.builtins_per_machine.build.items()})
self.print_options('Backend options', self.coredata.backend_options) self.print_options('Backend options', self.coredata.backend_options)
self.print_options('Base options', self.coredata.base_options) self.print_options('Base options', self.coredata.base_options)
# TODO others self.print_options('Compiler options (for host machine)', self.coredata.compiler_options.host)
self.print_options('Compiler options', self.coredata.compiler_options.build) self.print_options(
'Compiler options (for build machine)',
{'build.' + k: o for k, o in self.coredata.compiler_options.build.items()})
self.print_options('Directories', dir_options) self.print_options('Directories', dir_options)
self.print_options('Project options', self.coredata.user_options) self.print_options('Project options', self.coredata.user_options)
self.print_options('Testing options', test_options) self.print_options('Testing options', test_options)
@ -207,9 +213,6 @@ def run(options):
save = False save = False
if len(options.cmd_line_options) > 0: if len(options.cmd_line_options) > 0:
c.set_options(options.cmd_line_options) c.set_options(options.cmd_line_options)
if not c.build.environment.is_cross_build():
# TODO think about cross and command-line interface.
c.coredata.compiler_options.host = c.coredata.compiler_options.build
coredata.update_cmd_line_file(builddir, options) coredata.update_cmd_line_file(builddir, options)
save = True save = True
elif options.clearcache: elif options.clearcache:

@ -323,6 +323,12 @@ class MachineChoice(OrderedEnum):
BUILD = 0 BUILD = 0
HOST = 1 HOST = 1
def get_lower_case_name(self):
return PerMachine('build', 'host')[self]
def get_prefix(self):
return PerMachine('build.', '')[self]
class PerMachine(typing.Generic[_T]): class PerMachine(typing.Generic[_T]):
def __init__(self, build: _T, host: _T): def __init__(self, build: _T, host: _T):
@ -336,11 +342,7 @@ class PerMachine(typing.Generic[_T]):
}[machine] }[machine]
def __setitem__(self, machine: MachineChoice, val: _T) -> None: def __setitem__(self, machine: MachineChoice, val: _T) -> None:
key = { setattr(self, machine.get_lower_case_name(), val)
MachineChoice.BUILD: 'build',
MachineChoice.HOST: 'host',
}[machine]
setattr(self, key, val)
def miss_defaulting(self) -> "PerMachineDefaultable[typing.Optional[_T]]": def miss_defaulting(self) -> "PerMachineDefaultable[typing.Optional[_T]]":
"""Unset definition duplicated from their previous to None """Unset definition duplicated from their previous to None

@ -227,10 +227,20 @@ def list_buildoptions(coredata: cdata.CoreData) -> List[dict]:
core_options = {k: o for k, o in coredata.builtins.items() if k in core_option_names} core_options = {k: o for k, o in coredata.builtins.items() if k in core_option_names}
add_keys(optlist, core_options, 'core') add_keys(optlist, core_options, 'core')
add_keys(optlist, coredata.builtins_per_machine.host, 'core (for host machine)')
add_keys(
optlist,
{'build.' + k: o for k, o in coredata.builtins_per_machine.build.items()},
'core (for build machine)',
)
add_keys(optlist, coredata.backend_options, 'backend') add_keys(optlist, coredata.backend_options, 'backend')
add_keys(optlist, coredata.base_options, 'base') add_keys(optlist, coredata.base_options, 'base')
# TODO others add_keys(optlist, coredata.compiler_options.host, 'compiler (for host machine)')
add_keys(optlist, coredata.compiler_options.build, 'compiler') add_keys(
optlist,
{'build.' + k: o for k, o in coredata.compiler_options.build.items()},
'compiler (for build machine)',
)
add_keys(optlist, dir_options, 'directory') add_keys(optlist, dir_options, 'directory')
add_keys(optlist, coredata.user_options, 'user') add_keys(optlist, coredata.user_options, 'user')
add_keys(optlist, test_options, 'test') add_keys(optlist, test_options, 'test')

@ -465,10 +465,13 @@ class Rewriter:
cdata = self.interpreter.coredata cdata = self.interpreter.coredata
options = { options = {
**cdata.builtins, **cdata.builtins,
**cdata.builtins_per_machine.host,
**{'build.' + k: o for k, o in cdata.builtins_per_machine.build.items()},
**cdata.backend_options, **cdata.backend_options,
**cdata.base_options, **cdata.base_options,
**cdata.compiler_options.build, **cdata.compiler_options.host,
**cdata.user_options **{'build.' + k: o for k, o in cdata.compiler_options.build.items()},
**cdata.user_options,
} }
for key, val in sorted(cmd['options'].items()): for key, val in sorted(cmd['options'].items()):

@ -1088,7 +1088,10 @@ class DataTests(unittest.TestCase):
found_entries |= arches found_entries |= arches
break break
self.assertEqual(found_entries, set(mesonbuild.coredata.builtin_options.keys())) self.assertEqual(found_entries, set([
*mesonbuild.coredata.builtin_options.keys(),
*mesonbuild.coredata.builtin_options_per_machine.keys()
]))
def test_cpu_families_documented(self): def test_cpu_families_documented(self):
with open("docs/markdown/Reference-tables.md") as f: with open("docs/markdown/Reference-tables.md") as f:
@ -5193,8 +5196,15 @@ endian = 'little'
@skipIfNoPkgconfig @skipIfNoPkgconfig
def test_pkg_config_option(self): def test_pkg_config_option(self):
testdir = os.path.join(self.unit_test_dir, '55 pkg_config_path option') testdir = os.path.join(self.unit_test_dir, '55 pkg_config_path option')
self.init(testdir, extra_args=['-Dpkg_config_path=' + os.path.join(testdir, 'extra_path')]) self.init(testdir, extra_args=['-Dpkg_config_path=' + os.path.join(testdir, 'host_extra_path')])
def test_std_remains(self):
# C_std defined in project options must be in effect also when native compiling.
testdir = os.path.join(self.unit_test_dir, '50 std remains')
self.init(testdir)
compdb = self.get_compdb()
self.assertRegex(compdb[0]['command'], '-std=c99')
self.build()
def should_run_cross_arm_tests(): def should_run_cross_arm_tests():
return shutil.which('arm-linux-gnueabihf-gcc') and not platform.machine().lower().startswith('arm') return shutil.which('arm-linux-gnueabihf-gcc') and not platform.machine().lower().startswith('arm')
@ -5247,6 +5257,14 @@ class LinuxCrossArmTests(BasePlatformTests):
return return
self.assertTrue(False, 'Option libdir not in introspect data.') self.assertTrue(False, 'Option libdir not in introspect data.')
def test_std_remains(self):
# C_std defined in project options must be in effect also when cross compiling.
testdir = os.path.join(self.unit_test_dir, '50 std remains')
self.init(testdir)
compdb = self.get_compdb()
self.assertRegex(compdb[0]['command'], '-std=c99')
self.build()
def should_run_cross_mingw_tests(): def should_run_cross_mingw_tests():
return shutil.which('x86_64-w64-mingw32-gcc') and not (is_windows() or is_cygwin()) return shutil.which('x86_64-w64-mingw32-gcc') and not (is_windows() or is_cygwin())
@ -5294,7 +5312,10 @@ class LinuxCrossMingwTests(BasePlatformTests):
@skipIfNoPkgconfig @skipIfNoPkgconfig
def test_cross_pkg_config_option(self): def test_cross_pkg_config_option(self):
testdir = os.path.join(self.unit_test_dir, '55 pkg_config_path option') testdir = os.path.join(self.unit_test_dir, '55 pkg_config_path option')
self.init(testdir, extra_args=['-Dcross_pkg_config_path=' + os.path.join(testdir, 'extra_path')]) self.init(testdir, extra_args=[
'-Dbuild.pkg_config_path=' + os.path.join(testdir, 'build_extra_path'),
'-Dpkg_config_path=' + os.path.join(testdir, 'host_extra_path'),
])
class PythonTests(BasePlatformTests): class PythonTests(BasePlatformTests):

@ -0,0 +1,2 @@
project('std_remains', 'c', default_options: ['c_std=c99'])
executable('prog', 'prog.c')

@ -0,0 +1 @@
int main(int argc, char **argv) { return 0; }

@ -0,0 +1,7 @@
prefix=/
libdir=${prefix}/lib
includedir=${prefix}/include
Name: totally_made_up_dep
Description: completely and totally made up for a test case
Version: 4.5.6

@ -1,3 +1,12 @@
project('pkg_config_path option') project('pkg_config_path option')
dependency('totally_made_up_dep', method : 'pkg-config') build = dependency('totally_made_up_dep', native: true, method : 'pkg-config')
host = dependency('totally_made_up_dep', native: false, method : 'pkg-config')
# TODO always test we can do this separately
if meson.is_cross_build()
assert(build.version() == '4.5.6', 'wrong version for build machine dependency')
else
assert(host.version() == '1.2.3', 'wrong version for host machine dependency')
endif
assert(host.version() == '1.2.3', 'wrong version for host machine dependency')

Loading…
Cancel
Save