Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start adding native : 'both' #12022

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
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
10 changes: 10 additions & 0 deletions docs/markdown/snippets/add_native_both.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
## Add a `native : 'both'`` value

This has been added to the `add_language()` function. This allows explicitly
setting the default behavior of getting a language for both the host and build
machines. The default has been changed to `'both'`, and Meson will no longer
warn about getting no value for `native` in this function as a result.

This as also been added to `add_global_args()`, `add_global_link_args()`,
`add_project_args()`, and `add_project_link_args()`. The default for these
remains the same, but `'both'` is now allowed
14 changes: 7 additions & 7 deletions docs/yaml/functions/add_global_arguments.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ kwargs:
it in per-target flags.

native:
type: bool
type: bool | str
default: false
since: 0.48.0
description: |
A boolean specifying whether the arguments should be
applied to the native or cross compilation. If `true` the arguments
will only be used for native compilations. If `false` the arguments
will only be used in cross compilations. If omitted, the flags are
added to native compilations if compiling natively and cross
compilations (only) when cross compiling.
A boolean or `'both'` specifying whether the arguments should be
applied to targets for the host machine, the build machine, or both. If
`true` the arguments will only be used for build targets. If `false`
the arguments will only be used for host targets. *(since 1.4.0)* If
`'both'` then arguments will be used for both host and build targets.
When host == build, all options are equivalent.
7 changes: 5 additions & 2 deletions docs/yaml/functions/add_languages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,12 @@ kwargs:
specified are not found. *(since 0.47.0)* The value of a
[`feature`](Build-options.md#features) option can also be passed.
native:
type: bool
type: bool | str
since: 0.54.0
default: 'both'
description: |
If set to `true`, the language will be used to compile for the build
machine, if `false`, for the host machine.
machine, if `false`, for the host machine. *(since 1.4.0)* can be set to
`'both'` (the only valid string value), which is the default. When
performing a host == build compilation all of these options are equivalent.

67 changes: 42 additions & 25 deletions mesonbuild/interpreter/interpreter.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2012-2021 The Meson development team
# Copyright © 2023 Intel Corporation

from __future__ import annotations

Expand All @@ -14,9 +15,11 @@
from .. import envconfig
from ..wrap import wrap, WrapMode
from .. import mesonlib
from ..mesonlib import (EnvironmentVariables, ExecutableSerialisation, MesonBugException, MesonException, HoldableObject,
FileMode, MachineChoice, OptionKey, listify,
extract_as_list, has_path_sep, path_is_in_root, PerMachine)
from ..mesonlib import (EnvironmentVariables, ExecutableSerialisation,
MesonBugException, MesonException, HoldableObject,
InterpreterMachineChoice, FileMode, MachineChoice,
OptionKey, listify, extract_as_list, has_path_sep,
path_is_in_root, PerMachine)
from ..programs import ExternalProgram, NonExistingExternalProgram
from ..dependencies import Dependency
from ..depfile import DepFile
Expand Down Expand Up @@ -76,6 +79,7 @@
INSTALL_TAG_KW,
LANGUAGE_KW,
NATIVE_KW,
NATIVE_BOTH_KW,
PRESERVE_PATH_KW,
REQUIRED_KW,
SHARED_LIB_KWS,
Expand Down Expand Up @@ -1303,7 +1307,7 @@ def func_project(self, node: mparser.FunctionNode, args: T.Tuple[str, T.List[str
if not self.is_subproject():
self.check_stdlibs()

@typed_kwargs('add_languages', KwargInfo('native', (bool, NoneType), since='0.54.0'), REQUIRED_KW)
@typed_kwargs('add_languages', NATIVE_BOTH_KW.evolve(default='both', since='0.54.0'), REQUIRED_KW)
@typed_pos_args('add_languages', varargs=str)
def func_add_languages(self, node: mparser.FunctionNode, args: T.Tuple[T.List[str]], kwargs: 'kwtypes.FuncAddLanguages') -> bool:
langs = args[0]
Expand All @@ -1314,18 +1318,11 @@ def func_add_languages(self, node: mparser.FunctionNode, args: T.Tuple[T.List[st
for lang in sorted(langs, key=compilers.sort_clink):
mlog.log('Compiler for language', mlog.bold(lang), 'skipped: feature', mlog.bold(feature), 'disabled')
return False
if native is not None:
return self.add_languages(langs, required, self.machine_from_native_kwarg(kwargs))
else:
# absent 'native' means 'both' for backwards compatibility
tv = FeatureNew.get_target_version(self.subproject)
if FeatureNew.check_version(tv, '0.54.0'):
mlog.warning('add_languages is missing native:, assuming languages are wanted for both host and build.',
location=node)

success = self.add_languages(langs, False, MachineChoice.BUILD)
success &= self.add_languages(langs, required, MachineChoice.HOST)
return success
if native is not InterpreterMachineChoice.BOTH:
return self.add_languages(langs, required, native.as_machinechoice())
success = self.add_languages(langs, False, MachineChoice.BUILD)
success &= self.add_languages(langs, required, MachineChoice.HOST)
return success

def _stringify_user_arguments(self, args: T.List[TYPE_var], func_name: str) -> T.List[str]:
try:
Expand Down Expand Up @@ -2862,29 +2859,49 @@ def func_add_test_setup(self, node: mparser.BaseNode, args: T.Tuple[str], kwargs
kwargs['exclude_suites'])

@typed_pos_args('add_global_arguments', varargs=str)
@typed_kwargs('add_global_arguments', NATIVE_KW, LANGUAGE_KW)
@typed_kwargs('add_global_arguments', NATIVE_BOTH_KW, LANGUAGE_KW)
def func_add_global_arguments(self, node: mparser.FunctionNode, args: T.Tuple[T.List[str]], kwargs: 'kwtypes.FuncAddProjectArgs') -> None:
self._add_global_arguments(node, self.build.global_args[kwargs['native']], args[0], kwargs)
native = kwargs['native']
if native is InterpreterMachineChoice.BOTH:
self._add_global_arguments(node, self.build.global_args[MachineChoice.HOST], args[0], kwargs)
self._add_global_arguments(node, self.build.global_args[MachineChoice.BUILD], args[0], kwargs)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if this would duplicate all args when doing a native build, because in that case HOST and BUILD machines are the same, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that at first too, and added a bunch of code, only to discover that no, it doesn't. I've added a test in the lastest version to ensure that.

else:
self._add_global_arguments(node, self.build.global_args[native.as_machinechoice()], args[0], kwargs)

@typed_pos_args('add_global_link_arguments', varargs=str)
@typed_kwargs('add_global_arguments', NATIVE_KW, LANGUAGE_KW)
@typed_kwargs('add_global_arguments', NATIVE_BOTH_KW, LANGUAGE_KW)
def func_add_global_link_arguments(self, node: mparser.FunctionNode, args: T.Tuple[T.List[str]], kwargs: 'kwtypes.FuncAddProjectArgs') -> None:
self._add_global_arguments(node, self.build.global_link_args[kwargs['native']], args[0], kwargs)
native = kwargs['native']
if native is InterpreterMachineChoice.BOTH:
self._add_global_arguments(node, self.build.global_link_args[MachineChoice.HOST], args[0], kwargs)
self._add_global_arguments(node, self.build.global_link_args[MachineChoice.BUILD], args[0], kwargs)
else:
self._add_global_arguments(node, self.build.global_link_args[native.as_machinechoice()], args[0], kwargs)

@typed_pos_args('add_project_arguments', varargs=str)
@typed_kwargs('add_project_arguments', NATIVE_KW, LANGUAGE_KW)
@typed_kwargs('add_project_arguments', NATIVE_BOTH_KW, LANGUAGE_KW)
def func_add_project_arguments(self, node: mparser.FunctionNode, args: T.Tuple[T.List[str]], kwargs: 'kwtypes.FuncAddProjectArgs') -> None:
self._add_project_arguments(node, self.build.projects_args[kwargs['native']], args[0], kwargs)
native = kwargs['native']
if native is InterpreterMachineChoice.BOTH:
self._add_project_arguments(node, self.build.projects_args[MachineChoice.BUILD], args[0], kwargs)
self._add_project_arguments(node, self.build.projects_args[MachineChoice.HOST], args[0], kwargs)
else:
self._add_project_arguments(node, self.build.projects_args[native.as_machinechoice()], args[0], kwargs)

@typed_pos_args('add_project_link_arguments', varargs=str)
@typed_kwargs('add_global_arguments', NATIVE_KW, LANGUAGE_KW)
@typed_kwargs('add_global_arguments', NATIVE_BOTH_KW, LANGUAGE_KW)
def func_add_project_link_arguments(self, node: mparser.FunctionNode, args: T.Tuple[T.List[str]], kwargs: 'kwtypes.FuncAddProjectArgs') -> None:
self._add_project_arguments(node, self.build.projects_link_args[kwargs['native']], args[0], kwargs)
native = kwargs['native']
if native is InterpreterMachineChoice.BOTH:
self._add_project_arguments(node, self.build.projects_link_args[MachineChoice.BUILD], args[0], kwargs)
self._add_project_arguments(node, self.build.projects_link_args[MachineChoice.HOST], args[0], kwargs)
else:
self._add_project_arguments(node, self.build.projects_link_args[native.as_machinechoice()], args[0], kwargs)

@FeatureNew('add_project_dependencies', '0.63.0')
@typed_pos_args('add_project_dependencies', varargs=dependencies.Dependency)
@typed_kwargs('add_project_dependencies', NATIVE_KW, LANGUAGE_KW)
def func_add_project_dependencies(self, node: mparser.FunctionNode, args: T.Tuple[T.List[dependencies.Dependency]], kwargs: 'kwtypes.FuncAddProjectArgs') -> None:
def func_add_project_dependencies(self, node: mparser.FunctionNode, args: T.Tuple[T.List[dependencies.Dependency]], kwargs: kwtypes.FuncAddProjectDeps) -> None:
for_machine = kwargs['native']
for lang in kwargs['language']:
if lang not in self.compilers[for_machine]:
Expand Down
16 changes: 11 additions & 5 deletions mesonbuild/interpreter/kwargs.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright © 2021 The Meson Developers
# Copyright © 2021 Intel Corporation
# Copyright 2021 The Meson Developers
# Copyright © 2021-2023 Intel Corporation
from __future__ import annotations

"""Keyword Argument type annotations."""
Expand All @@ -9,11 +9,11 @@

from typing_extensions import TypedDict, Literal, Protocol, NotRequired

from .. import build
import build
from .. import coredata
from ..compilers import Compiler
from ..dependencies.base import Dependency
from ..mesonlib import EnvironmentVariables, MachineChoice, File, FileMode, FileOrString, OptionKey
from ..mesonlib import EnvironmentVariables, MachineChoice, File, FileMode, FileOrString, OptionKey, InterpreterMachineChoice
from ..modules.cmake import CMakeSubprojectOptions
from ..programs import ExternalProgram
from .type_checking import PkgConfigDefineType, SourcesVarargsType
Expand All @@ -29,6 +29,12 @@ class FuncAddProjectArgs(TypedDict):
a MachineChoice instance already.
"""

native: InterpreterMachineChoice
language: T.List[str]


class FuncAddProjectDeps(TypedDict):

native: MachineChoice
language: T.List[str]

Expand Down Expand Up @@ -163,7 +169,7 @@ class FuncIncludeDirectories(TypedDict):

class FuncAddLanguages(ExtractRequired):

native: T.Optional[bool]
native: InterpreterMachineChoice

class RunTarget(TypedDict):

Expand Down
21 changes: 19 additions & 2 deletions mesonbuild/interpreter/type_checking.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright © 2021 Intel Corporation
# Copyright © 2021-2023 Intel Corporation

"""Helpers for strict type checking."""

Expand All @@ -14,7 +14,7 @@
from ..coredata import UserFeatureOption
from ..dependencies import Dependency, InternalDependency
from ..interpreterbase.decorators import KwargInfo, ContainerTypeInfo
from ..mesonlib import (File, FileMode, MachineChoice, listify, has_path_sep,
from ..mesonlib import (File, FileMode, MachineChoice, InterpreterMachineChoice, listify, has_path_sep,
OptionKey, EnvironmentVariables)
from ..programs import ExternalProgram

Expand Down Expand Up @@ -168,6 +168,23 @@ def variables_convertor(contents: T.Union[str, T.List[str], T.Dict[str, str]]) -
default=False,
convertor=lambda n: MachineChoice.BUILD if n else MachineChoice.HOST)

_NATIVE_BOTH: T.Mapping[T.Union[bool, Literal['both']], InterpreterMachineChoice] = {
True: InterpreterMachineChoice.BUILD,
False: InterpreterMachineChoice.HOST,
'both': InterpreterMachineChoice.BOTH,
}

# We can't annotate the type below as Literal, but the validator will do that for us
# So, we need the type ignore, otherwise mypy complains about the `str`
NATIVE_BOTH_KW: KwargInfo[T.Union[bool, Literal['both']]] = KwargInfo(
'native',
(bool, str), # type: ignore[arg-type]
default=False,
validator=lambda x: 'must be either a boolean or the literal "both"' if isinstance(x, str) and x != 'both' else None,
convertor=lambda x: _NATIVE_BOTH[x],
since_values={str: '1.4.0'},
)

LANGUAGE_KW = KwargInfo(
'language', ContainerTypeInfo(list, str, allow_empty=False),
listify=True,
Expand Down
32 changes: 30 additions & 2 deletions mesonbuild/utils/universal.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2012-2020 The Meson development team

# Copyright © 2023 Intel Corporation

"""A library of random helper functionality."""

Expand All @@ -24,7 +24,7 @@
import json

from mesonbuild import mlog
from .core import MesonException, HoldableObject
from .core import MesonBugException, MesonException, HoldableObject

if T.TYPE_CHECKING:
from typing_extensions import Literal, Protocol
Expand Down Expand Up @@ -61,6 +61,7 @@ class _VerPickleLoadable(Protocol):
'File',
'FileMode',
'GitException',
'InterpreterMachineChoice',
'LibType',
'MachineChoice',
'EnvironmentException',
Expand Down Expand Up @@ -486,6 +487,33 @@ def get_prefix(self) -> str:
return PerMachine('build.', '')[self]


class InterpreterMachineChoice(enum.Enum):

"""Machine Choices for the interpreter.

This includes the option of having a "both" value, which the interpreter
will turn into two calls, one for the build and one for the host machine (in
a cross build situation)
"""

BUILD = enum.auto()
HOST = enum.auto()
BOTH = enum.auto()

def as_machinechoice(self) -> MachineChoice:
"""Convert to a normal MachineChoice

a Both value cannot be converted, it is expected that the interpreter
will handle any logic duplication required to handle both cases.

:raises MesonBugException: if a value of BOTH is converted
:return: A MachineChoiceValue
"""
if self.value == self.BOTH.value:
raise MesonBugException('Tried to get a MachineChoice for "both"')
return MachineChoice.HOST if self.value == self.HOST.value else MachineChoice.BUILD


class PerMachine(T.Generic[_T]):
def __init__(self, build: _T, host: _T) -> None:
self.build = build
Expand Down
46 changes: 38 additions & 8 deletions test cases/common/115 subproject project arguments/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,46 @@ project('project options tester', 'c', 'cpp',
version : '2.3.4',
license : 'mylicense')

add_global_arguments('-DGLOBAL_ARGUMENT', language: 'c')
add_project_arguments('-DPROJECT_OPTION', language: 'c')
add_project_arguments('-DPROJECT_OPTION_CPP', language: 'cpp')
add_project_arguments('-DPROJECT_OPTION_C_CPP', language: ['c', 'cpp'])
machine = get_option('machine')
assert(machine in ['host', 'build', 'both'])
if machine == 'host'
native = false
elif machine == 'build'
native = true
else
native = 'both'
endif

sub = subproject('subexe', version : '1.0.0')
if not add_languages('c', 'cpp', native : native, required : false)
error(f'MESON_SKIP_TEST this test requires compilers for @machine@ machine(s)')
endif

add_project_arguments('-DPROJECT_OPTION_1', language: 'c')
add_global_arguments('-DGLOBAL_ARGUMENT', language: 'c', native : native)
add_project_arguments('-DPROJECT_OPTION', language: 'c', native : native)
add_project_arguments('-DPROJECT_OPTION_CPP', language: 'cpp', native : native)
add_project_arguments('-DPROJECT_OPTION_C_CPP', language: ['c', 'cpp'], native : native)

e = executable('exe', 'exe.c')
e = executable('execpp', 'exe.cpp')
# XXX: when subprojects allow host/build
if machine != 'build'
sub = subproject('subexe', version : '1.0.0')
endif

add_project_arguments('-DPROJECT_OPTION_1', language: 'c', native : native)

if machine == 'both'
native = false
endif

e = executable('exe', 'exe.c', native : native)
e = executable('execpp', 'exe.cpp', native : native)
test('exetest', e)
test('execpptest', e)

if machine == 'both'
e = executable('exe_build', 'exe.c', native : true)
e = executable('execpp_build', 'exe.cpp', native : true)
if meson.can_run_host_binaries()
test('exetest_build', e)
test('execpptest_build', e)
endif
endif
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
option('machine', type : 'string', value : 'host')
11 changes: 11 additions & 0 deletions test cases/common/115 subproject project arguments/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"matrix": {
"options": {
"machine": [
{ "val": "host" },
{ "val": "build" },
{ "val": "both" }
]
}
}
}
8 changes: 8 additions & 0 deletions test cases/common/82 add language/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,11 @@ assert(not add_languages('klingon', required : false), 'Add_languages returned t
test('C++', executable('cppprog', 'prog.cc'))

add_languages('c', native: false)

cpp = meson.get_compiler('cpp', native : false)

# We have at least one CI setup that has only cross compilers, so both will fail
if add_languages('cpp', native : true, required : false)
assert(add_languages('cpp', native : 'both'), 'Add_languages returned false on success')
cpp_build = meson.get_compiler('cpp', native : true)
endif
3 changes: 0 additions & 3 deletions test cases/warning/2 languages missing native/meson.build

This file was deleted.

Loading
Loading