Skip to content

Commit

Permalink
Add required kwarg to compiler.{compiles,links,run}
Browse files Browse the repository at this point in the history
This is a similar commit to the one that added required to all the
compiler.has* functions.
  • Loading branch information
tristan957 committed May 1, 2024
1 parent f38a826 commit 2c1e5ba
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 8 deletions.
21 changes: 21 additions & 0 deletions docs/markdown/snippets/requires_kwarg_on_more_compiler_methods.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
## Required kwarg on more `compiler` methods

The following `compiler` methods now support the `required` keyword argument:

- `compiler.compiles()`
- `compiler.links()`
- `compiler.runs()`

```meson
cc.compiles(valid, name: 'valid', required : true)
cc.links(valid, name: 'valid', required : true)
cc.run(valid, name: 'valid', required : true)
assert(not cc.compiles(valid, name: 'valid', required : opt))
assert(not cc.links(valid, name: 'valid', required : opt))
res = cc.run(valid, name: 'valid', required : opt)
assert(res.compiled())
assert(res.returncode() == 0)
assert(res.stdout() == '')
assert(res.stderr() == '')
```
10 changes: 10 additions & 0 deletions docs/yaml/objects/compiler.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,16 @@ methods:
- name: _compiles
returns: void
description: You have found a bug if you can see this!
kwargs:
required:
type: bool | feature
default: false
since: 1.5.0
description:
When set to `true`, Meson will halt if the check fails.

When set to a [`feature`](Build-options.md#features) option, the feature
will control if it is searched and whether to fail if not found.
kwargs_inherit:
- compiler._args
- compiler._include_directories
Expand Down
47 changes: 39 additions & 8 deletions mesonbuild/interpreter/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from .. import dependencies
from .. import mesonlib
from .. import mlog
from ..compilers import SUFFIX_TO_LANG
from ..compilers import SUFFIX_TO_LANG, RunResult
from ..compilers.compilers import CompileCheckMode
from ..interpreterbase import (ObjectHolder, noPosargs, noKwargs,
FeatureNew, FeatureNewKwargs, disablerIfNotFound,
Expand All @@ -27,7 +27,7 @@

if T.TYPE_CHECKING:
from ..interpreter import Interpreter
from ..compilers import Compiler, RunResult
from ..compilers import Compiler
from ..interpreterbase import TYPE_var, TYPE_kwargs
from .kwargs import ExtractRequired, ExtractSearchDirs
from .interpreter import SourceOutputs
Expand All @@ -50,7 +50,7 @@ class BaseCompileKW(TypedDict):
include_directories: T.List[build.IncludeDirs]
args: T.List[str]

class CompileKW(BaseCompileKW):
class CompileKW(BaseCompileKW, ExtractRequired):

name: str
dependencies: T.List[dependencies.Dependency]
Expand Down Expand Up @@ -178,7 +178,8 @@ def stderr_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:

# Common methods of compiles, links, runs, and similar
_COMPILES_KWS: T.List[KwargInfo] = [_NAME_KW, _ARGS_KW, _DEPENDENCIES_KW, _INCLUDE_DIRS_KW, _NO_BUILTIN_ARGS_KW,
_WERROR_KW]
_WERROR_KW,
REQUIRED_KW.evolve(since='1.5.0', default=False)]

_HEADER_KWS: T.List[KwargInfo] = [REQUIRED_KW.evolve(since='0.50.0', default=False), *_COMMON_KWS]
_HAS_REQUIRED_KW = REQUIRED_KW.evolve(since='1.3.0', default=False)
Expand Down Expand Up @@ -306,15 +307,25 @@ def run_method(self, args: T.Tuple['mesonlib.FileOrString'], kwargs: 'CompileKW'
FeatureNew.single_use(f'compiler.run for {self.compiler.get_display_language()} language',
'1.5.0', self.subproject, location=self.current_node)
code = args[0]
testname = kwargs['name']

disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False)
if disabled:
if testname:
mlog.log('Checking if', mlog.bold(testname, True), 'runs:', 'skipped: feature', mlog.bold(feature), 'disabled')
return RunResult(compiled=True, returncode=0, stdout='', stderr='', cached=False)

if isinstance(code, mesonlib.File):
self.interpreter.add_build_def_file(code)
code = mesonlib.File.from_absolute_file(
code.rel_to_builddir(self.environment.source_dir))
testname = kwargs['name']
extra_args = functools.partial(self._determine_args, kwargs)
deps, msg = self._determine_dependencies(kwargs['dependencies'], compile_only=False, endl=None)
result = self.compiler.run(code, self.environment, extra_args=extra_args,
dependencies=deps)
if required and result.returncode != 0:
raise InterpreterException(f'Could not run {testname if testname else "code"}')

if testname:
if not result.compiled:
h = mlog.red('DID NOT COMPILE')
Expand Down Expand Up @@ -510,19 +521,29 @@ def has_define_method(self, args: T.Tuple[str], kwargs: 'CommonKW') -> bool:
@typed_kwargs('compiler.compiles', *_COMPILES_KWS)
def compiles_method(self, args: T.Tuple['mesonlib.FileOrString'], kwargs: 'CompileKW') -> bool:
code = args[0]
testname = kwargs['name']

disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False)
if disabled:
if testname:
mlog.log('Checking if', mlog.bold(testname, True), 'compiles:', 'skipped: feature', mlog.bold(feature), 'disabled')
return False

if isinstance(code, mesonlib.File):
if code.is_built:
FeatureNew.single_use('compiler.compiles with file created at setup time', '1.2.0', self.subproject,
'It was broken and either errored or returned false.', self.current_node)
self.interpreter.add_build_def_file(code)
code = mesonlib.File.from_absolute_file(
code.absolute_path(self.environment.source_dir, self.environment.build_dir))
testname = kwargs['name']
extra_args = functools.partial(self._determine_args, kwargs)
deps, msg = self._determine_dependencies(kwargs['dependencies'], endl=None)
result, cached = self.compiler.compiles(code, self.environment,
extra_args=extra_args,
dependencies=deps)
if required and not result:
raise InterpreterException(f'Could not compile {testname}')

if testname:
if result:
h = mlog.green('YES')
Expand All @@ -536,6 +557,14 @@ def compiles_method(self, args: T.Tuple['mesonlib.FileOrString'], kwargs: 'Compi
@typed_kwargs('compiler.links', *_COMPILES_KWS)
def links_method(self, args: T.Tuple['mesonlib.FileOrString'], kwargs: 'CompileKW') -> bool:
code = args[0]
testname = kwargs['name']

disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False)
if disabled:
if testname:
mlog.log('Checking if', mlog.bold(testname, True), 'links:', 'skipped: feature', mlog.bold(feature), 'disabled')
return False

compiler = None
if isinstance(code, mesonlib.File):
if code.is_built:
Expand All @@ -556,19 +585,21 @@ def links_method(self, args: T.Tuple['mesonlib.FileOrString'], kwargs: 'CompileK
else:
compiler = clist[SUFFIX_TO_LANG[suffix]]

testname = kwargs['name']
extra_args = functools.partial(self._determine_args, kwargs)
deps, msg = self._determine_dependencies(kwargs['dependencies'], compile_only=False)
result, cached = self.compiler.links(code, self.environment,
compiler=compiler,
extra_args=extra_args,
dependencies=deps)
cached_msg = mlog.blue('(cached)') if cached else ''
if required and not result:
raise InterpreterException(f'Could not link {testname if testname else "code"}')

if testname:
if result:
h = mlog.green('YES')
else:
h = mlog.red('NO')
cached_msg = mlog.blue('(cached)') if cached else ''
mlog.log('Checking if', mlog.bold(testname, True), msg, 'links:', h, cached_msg)
return result

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// The error in this file is an homage to the xz incident :)
//
int
main(void)
{
. return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
project('required keyword in compiles functions', 'c')

cc = meson.get_compiler('c')
opt = get_option('opt')

valid = files('valid.c')
invalid = files('invalid.c')

cc.compiles(valid, name: 'valid', required : true)
cc.links(valid, name: 'valid', required : true)
if meson.can_run_host_binaries()
cc.run(valid, name: 'valid', required : true)
endif

assert(not cc.compiles(valid, name: 'valid', required : opt))
assert(not cc.links(valid, name: 'valid', required : opt))
if meson.can_run_host_binaries()
res = cc.run(valid, name: 'valid', required : opt)
assert(res.compiled())
assert(res.returncode() == 0)
assert(res.stdout() == '')
assert(res.stderr() == '')
endif

testcase expect_error('''compiler.compiles keyword argument 'required' was of type str but should have been one of: bool, UserFeatureOption''')
cc.compiles(valid, name: 'valid', required : 'not a bool')
endtestcase

testcase expect_error('''Could not compile invalid''')
cc.compiles(invalid, name: 'invalid', required : true)
endtestcase

testcase expect_error('''Could not link invalid''')
cc.links(invalid, name: 'invalid', required : true)
endtestcase

if meson.can_run_host_binaries()
testcase expect_error('''Could not run invalid''')
cc.run(invalid, name: 'invalid', required : true)
endtestcase
endif
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
option('opt', type: 'feature', value: 'disabled')
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
int
main(void)
{
return 0;
}

0 comments on commit 2c1e5ba

Please sign in to comment.