aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/IDE-integration.md4
-rw-r--r--docs/markdown/snippets/intro_extra_files.md6
-rw-r--r--mesonbuild/ast/introspection.py68
-rw-r--r--mesonbuild/backend/backends.py2
-rw-r--r--mesonbuild/build.py5
-rw-r--r--mesonbuild/mintro.py24
-rwxr-xr-xrun_unittests.py49
-rw-r--r--test cases/unit/57 introspection/sharedlib/meson.build2
-rw-r--r--test cases/unit/57 introspection/staticlib/meson.build3
-rw-r--r--test cases/unit/57 introspection/staticlib/static.h10
10 files changed, 116 insertions, 57 deletions
diff --git a/docs/markdown/IDE-integration.md b/docs/markdown/IDE-integration.md
index 5188359..2f91e81 100644
--- a/docs/markdown/IDE-integration.md
+++ b/docs/markdown/IDE-integration.md
@@ -59,6 +59,7 @@ for one target is defined as follows:
"filename": ["list", "of", "generated", "files"],
"build_by_default": true / false,
"target_sources": [],
+ "extra_files": ["/path/to/file1.hpp", "/path/to/file2.hpp"],
"installed": true / false,
}
```
@@ -71,6 +72,9 @@ is set to `null`.
The `subproject` key specifies the name of the subproject this target was
defined in, or `null` if the target was defined in the top level project.
+*(New in 0.56.0)* The `extra_files` key lists all files specified via the
+`extra_files` kwarg of a build target. See [`executable()`](Reference-manual.md#executable).
+
A target usually generates only one file. However, it is possible for custom
targets to have multiple outputs.
diff --git a/docs/markdown/snippets/intro_extra_files.md b/docs/markdown/snippets/intro_extra_files.md
new file mode 100644
index 0000000..43475cd
--- /dev/null
+++ b/docs/markdown/snippets/intro_extra_files.md
@@ -0,0 +1,6 @@
+## New `extra_files` key in target introspection
+
+The target introspection (`meson introspect --targets`, `intro-targets.json`)
+now has the new `extra_files` key which lists all files specified via the
+`extra_files` kwarg of a build target (see `executable()`, etc.)
+
diff --git a/mesonbuild/ast/introspection.py b/mesonbuild/ast/introspection.py
index 9cfdded..334ff83 100644
--- a/mesonbuild/ast/introspection.py
+++ b/mesonbuild/ast/introspection.py
@@ -194,42 +194,51 @@ class IntrospectionInterpreter(AstInterpreter):
return None
name = args[0]
srcqueue = [node]
+ extra_queue = []
# Process the sources BEFORE flattening the kwargs, to preserve the original nodes
if 'sources' in kwargs_raw:
srcqueue += mesonlib.listify(kwargs_raw['sources'])
+ if 'extra_files' in kwargs_raw:
+ extra_queue += mesonlib.listify(kwargs_raw['extra_files'])
+
kwargs = self.flatten_kwargs(kwargs_raw, True)
- source_nodes = [] # type: T.List[BaseNode]
- while srcqueue:
- curr = srcqueue.pop(0)
- arg_node = None
- assert(isinstance(curr, BaseNode))
- if isinstance(curr, FunctionNode):
- arg_node = curr.args
- elif isinstance(curr, ArrayNode):
- arg_node = curr.args
- elif isinstance(curr, IdNode):
- # Try to resolve the ID and append the node to the queue
- assert isinstance(curr.value, str)
- var_name = curr.value
- if var_name in self.assignments:
- tmp_node = self.assignments[var_name]
- if isinstance(tmp_node, (ArrayNode, IdNode, FunctionNode)):
- srcqueue += [tmp_node]
- elif isinstance(curr, ArithmeticNode):
- srcqueue += [curr.left, curr.right]
- if arg_node is None:
- continue
- arg_nodes = arg_node.arguments.copy()
- # Pop the first element if the function is a build target function
- if isinstance(curr, FunctionNode) and curr.func_name in build_target_functions:
- arg_nodes.pop(0)
- elemetary_nodes = [x for x in arg_nodes if isinstance(x, (str, StringNode))]
- srcqueue += [x for x in arg_nodes if isinstance(x, (FunctionNode, ArrayNode, IdNode, ArithmeticNode))]
- if elemetary_nodes:
- source_nodes += [curr]
+ def traverse_nodes(inqueue: T.List[BaseNode]) -> T.List[BaseNode]:
+ res = [] # type: T.List[BaseNode]
+ while inqueue:
+ curr = inqueue.pop(0)
+ arg_node = None
+ assert(isinstance(curr, BaseNode))
+ if isinstance(curr, FunctionNode):
+ arg_node = curr.args
+ elif isinstance(curr, ArrayNode):
+ arg_node = curr.args
+ elif isinstance(curr, IdNode):
+ # Try to resolve the ID and append the node to the queue
+ assert isinstance(curr.value, str)
+ var_name = curr.value
+ if var_name in self.assignments:
+ tmp_node = self.assignments[var_name]
+ if isinstance(tmp_node, (ArrayNode, IdNode, FunctionNode)):
+ inqueue += [tmp_node]
+ elif isinstance(curr, ArithmeticNode):
+ inqueue += [curr.left, curr.right]
+ if arg_node is None:
+ continue
+ arg_nodes = arg_node.arguments.copy()
+ # Pop the first element if the function is a build target function
+ if isinstance(curr, FunctionNode) and curr.func_name in build_target_functions:
+ arg_nodes.pop(0)
+ elemetary_nodes = [x for x in arg_nodes if isinstance(x, (str, StringNode))]
+ inqueue += [x for x in arg_nodes if isinstance(x, (FunctionNode, ArrayNode, IdNode, ArithmeticNode))]
+ if elemetary_nodes:
+ res += [curr]
+ return res
+
+ source_nodes = traverse_nodes(srcqueue)
+ extraf_nodes = traverse_nodes(extra_queue)
# Make sure nothing can crash when creating the build class
kwargs_reduced = {k: v for k, v in kwargs.items() if k in targetclass.known_kwargs and k in ['install', 'build_by_default', 'build_always']}
@@ -251,6 +260,7 @@ class IntrospectionInterpreter(AstInterpreter):
'installed': target.should_install(),
'outputs': target.get_outputs(),
'sources': source_nodes,
+ 'extra_files': extraf_nodes,
'kwargs': kwargs,
'node': node,
}
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index 3e883e9..23734a8 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -1390,7 +1390,7 @@ class Backend:
This is a limited fallback / reference implementation. The backend should override this method.
'''
if isinstance(target, (build.CustomTarget, build.BuildTarget)):
- source_list_raw = target.sources + target.extra_files
+ source_list_raw = target.sources
source_list = []
for j in source_list_raw:
if isinstance(j, mesonlib.File):
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index bc1f54a..26b54ff 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -370,6 +370,7 @@ a hard error in the future.'''.format(name))
self.build_always_stale = False
self.option_overrides_base = {}
self.option_overrides_compiler = defaultdict(dict)
+ self.extra_files = [] # type: T.List[File]
if not hasattr(self, 'typename'):
raise RuntimeError('Target type is not set for target class "{}". This is a bug'.format(type(self).__name__))
@@ -518,7 +519,6 @@ class BuildTarget(Target):
self.pch = {}
self.extra_args = {}
self.generated = []
- self.extra_files = []
self.d_features = {}
self.pic = False
self.pie = False
@@ -1011,7 +1011,7 @@ This will become a hard error in a future Meson release.''')
if self.gnu_symbol_visibility not in permitted:
raise InvalidArguments('GNU symbol visibility arg {} not one of: {}'.format(self.symbol_visibility, ', '.join(permitted)))
- def validate_win_subsystem(self, value: str) -> str:
+ def validate_win_subsystem(self, value: str) -> str:
value = value.lower()
if re.fullmatch(r'(boot_application|console|efi_application|efi_boot_service_driver|efi_rom|efi_runtime_driver|native|posix|windows)(,\d+(\.\d+)?)?', value) is None:
raise InvalidArguments('Invalid value for win_subsystem: {}.'.format(value))
@@ -2058,7 +2058,6 @@ class CustomTarget(Target):
self.depend_files = [] # Files that this target depends on but are not on the command line.
self.depfile = None
self.process_kwargs(kwargs, backend)
- self.extra_files = []
# Whether to use absolute paths for all files on the commandline
self.absolute_paths = absolute_paths
unknowns = []
diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py
index 4c1e8ea..924a103 100644
--- a/mesonbuild/mintro.py
+++ b/mesonbuild/mintro.py
@@ -28,7 +28,7 @@ from . import mlog
from .backend import backends
from .mparser import BaseNode, FunctionNode, ArrayNode, ArgumentNode, StringNode
from .interpreter import Interpreter
-from ._pathlib import PurePath
+from ._pathlib import Path, PurePath
import typing as T
import os
import argparse
@@ -119,9 +119,10 @@ def list_installed(installdata: backends.InstallData) -> T.Dict[str, str]:
def list_targets_from_source(intr: IntrospectionInterpreter) -> T.List[T.Dict[str, T.Union[bool, str, T.List[T.Union[str, T.Dict[str, T.Union[str, T.List[str], bool]]]]]]]:
tlist = [] # type: T.List[T.Dict[str, T.Union[bool, str, T.List[T.Union[str, T.Dict[str, T.Union[str, T.List[str], bool]]]]]]]
- for i in intr.targets:
- sources = [] # type: T.List[str]
- for n in i['sources']:
+ root_dir = Path(intr.source_root)
+ def nodes_to_paths(node_list: T.List[BaseNode]) -> T.List[Path]:
+ res = [] # type: T.List[Path]
+ for n in node_list:
args = [] # type: T.List[BaseNode]
if isinstance(n, FunctionNode):
args = list(n.args.arguments)
@@ -134,9 +135,16 @@ def list_targets_from_source(intr: IntrospectionInterpreter) -> T.List[T.Dict[st
for j in args:
if isinstance(j, StringNode):
assert isinstance(j.value, str)
- sources += [j.value]
+ res += [Path(j.value)]
elif isinstance(j, str):
- sources += [j]
+ res += [Path(j)]
+ res = [root_dir / i['subdir'] / x for x in res]
+ res = [x.resolve() for x in res]
+ return res
+
+ for i in intr.targets:
+ sources = nodes_to_paths(i['sources'])
+ extra_f = nodes_to_paths(i['extra_files'])
tlist += [{
'name': i['name'],
@@ -149,9 +157,10 @@ def list_targets_from_source(intr: IntrospectionInterpreter) -> T.List[T.Dict[st
'language': 'unknown',
'compiler': [],
'parameters': [],
- 'sources': [os.path.normpath(os.path.join(os.path.abspath(intr.source_root), i['subdir'], x)) for x in sources],
+ 'sources': [str(x) for x in sources],
'generated_sources': []
}],
+ 'extra_files': [str(x) for x in extra_f],
'subproject': None, # Subprojects are not supported
'installed': i['installed']
}]
@@ -182,6 +191,7 @@ def list_targets(builddata: build.Build, installdata: backends.InstallData, back
'filename': [os.path.join(build_dir, target.subdir, x) for x in target.get_outputs()],
'build_by_default': target.build_by_default,
'target_sources': backend.get_introspection_data(idname, target),
+ 'extra_files': [os.path.normpath(os.path.join(src_dir, x.subdir, x.fname)) for x in target.extra_files],
'subproject': target.subproject or None
}
diff --git a/run_unittests.py b/run_unittests.py
index f6adcee..708dcb7 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -4308,10 +4308,22 @@ recommended as it is not supported on some platforms''')
infodir = os.path.join(self.builddir, 'meson-info')
self.assertPathExists(infodir)
- def assertKeyTypes(key_type_list, obj):
+ def assertKeyTypes(key_type_list, obj, strict: bool = True):
for i in key_type_list:
+ if isinstance(i[1], (list, tuple)) and None in i[1]:
+ i = (i[0], tuple([x for x in i[1] if x is not None]))
+ if i[0] not in obj or obj[i[0]] is None:
+ continue
self.assertIn(i[0], obj)
self.assertIsInstance(obj[i[0]], i[1])
+ if strict:
+ for k in obj.keys():
+ found = False
+ for i in key_type_list:
+ if k == i[0]:
+ found = True
+ break
+ self.assertTrue(found, 'Key "{}" not in expected list'.format(k))
root_keylist = [
('benchmarks', list),
@@ -4333,6 +4345,8 @@ recommended as it is not supported on some platforms''')
('is_parallel', bool),
('protocol', str),
('depends', list),
+ ('workdir', (str, None)),
+ ('priority', int),
]
buildoptions_keylist = [
@@ -4341,6 +4355,8 @@ recommended as it is not supported on some platforms''')
('type', str),
('description', str),
('machine', str),
+ ('choices', (list, None)),
+ ('value', (str, int, bool, list)),
]
buildoptions_typelist = [
@@ -4369,6 +4385,9 @@ recommended as it is not supported on some platforms''')
('filename', list),
('build_by_default', bool),
('target_sources', list),
+ ('extra_files', list),
+ ('subproject', (str, None)),
+ ('install_filename', (list, None)),
('installed', bool),
]
@@ -4422,7 +4441,7 @@ recommended as it is not supported on some platforms''')
for j in buildoptions_typelist:
if i['type'] == j[0]:
self.assertIsInstance(i['value'], j[1])
- assertKeyTypes(j[2], i)
+ assertKeyTypes(j[2], i, strict=False)
valid_type = True
break
@@ -9328,18 +9347,20 @@ def main():
'LinuxlikeTests', 'LinuxCrossArmTests', 'LinuxCrossMingwTests',
'WindowsTests', 'DarwinTests']
- # Don't use pytest-xdist when running single unit tests since it wastes
- # time spawning a lot of processes to distribute tests to in that case.
- if not running_single_tests(sys.argv, cases):
- try:
- import pytest # noqa: F401
- # Need pytest-xdist for `-n` arg
- import xdist # noqa: F401
- pytest_args = ['-n', 'auto', './run_unittests.py']
- pytest_args += convert_args(sys.argv[1:])
- return subprocess.run(python_command + ['-m', 'pytest'] + pytest_args).returncode
- except ImportError:
- print('pytest-xdist not found, using unittest instead')
+ try:
+ import pytest # noqa: F401
+ # Need pytest-xdist for `-n` arg
+ import xdist # noqa: F401
+ pytest_args = []
+ # Don't use pytest-xdist when running single unit tests since it wastes
+ # time spawning a lot of processes to distribute tests to in that case.
+ if not running_single_tests(sys.argv, cases):
+ pytest_args += ['-n', 'auto']
+ pytest_args += ['./run_unittests.py']
+ pytest_args += convert_args(sys.argv[1:])
+ return subprocess.run(python_command + ['-m', 'pytest'] + pytest_args).returncode
+ except ImportError:
+ print('pytest-xdist not found, using unittest instead')
# Fallback to plain unittest.
return unittest.main(defaultTest=cases, buffer=True)
diff --git a/test cases/unit/57 introspection/sharedlib/meson.build b/test cases/unit/57 introspection/sharedlib/meson.build
index 3de3493..7640bc7 100644
--- a/test cases/unit/57 introspection/sharedlib/meson.build
+++ b/test cases/unit/57 introspection/sharedlib/meson.build
@@ -1,2 +1,2 @@
SRC_shared = ['shared.cpp']
-sharedlib = shared_library('sharedTestLib', SRC_shared)
+sharedlib = shared_library('sharedTestLib', SRC_shared, extra_files: ['shared.hpp'])
diff --git a/test cases/unit/57 introspection/staticlib/meson.build b/test cases/unit/57 introspection/staticlib/meson.build
index b1b9afe..1cbb020 100644
--- a/test cases/unit/57 introspection/staticlib/meson.build
+++ b/test cases/unit/57 introspection/staticlib/meson.build
@@ -1,2 +1,3 @@
SRC_static = ['static.c']
-staticlib = static_library('staticTestLib', SRC_static)
+extra_static = files(['static.h'])
+staticlib = static_library('staticTestLib', SRC_static, extra_files: extra_static)
diff --git a/test cases/unit/57 introspection/staticlib/static.h b/test cases/unit/57 introspection/staticlib/static.h
index 506784e..06da508 100644
--- a/test cases/unit/57 introspection/staticlib/static.h
+++ b/test cases/unit/57 introspection/staticlib/static.h
@@ -1,3 +1,11 @@
#pragma once
-int add_numbers(int a, int b); \ No newline at end of file
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int add_numbers(int a, int b);
+
+#ifdef __cplusplus
+}
+#endif