aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/cmake
diff options
context:
space:
mode:
authorJussi Pakkanen <jpakkane@gmail.com>2022-03-07 16:12:19 +0200
committerGitHub <noreply@github.com>2022-03-07 16:12:19 +0200
commit219f40c1e4689060f3c299edd463fc5f5a625608 (patch)
tree0f3d2565382221b62368569cc049be2f0389f670 /mesonbuild/cmake
parent0f2f87a003477bd79487a47d5f60f67751e2f44e (diff)
parent7ab2ceb2733442a2c3ca1284f545f28abcd5a14a (diff)
downloadmeson-219f40c1e4689060f3c299edd463fc5f5a625608.zip
meson-219f40c1e4689060f3c299edd463fc5f5a625608.tar.gz
meson-219f40c1e4689060f3c299edd463fc5f5a625608.tar.bz2
Merge pull request #9743 from mensinda/cmakeGeneratorFixed
cmake: Add TARGET_ generator expression support (fixes #9305)
Diffstat (limited to 'mesonbuild/cmake')
-rw-r--r--mesonbuild/cmake/generator.py61
-rw-r--r--mesonbuild/cmake/interpreter.py4
-rw-r--r--mesonbuild/cmake/toolchain.py2
-rw-r--r--mesonbuild/cmake/traceparser.py40
4 files changed, 100 insertions, 7 deletions
diff --git a/mesonbuild/cmake/generator.py b/mesonbuild/cmake/generator.py
index 848fdf9..b68778d 100644
--- a/mesonbuild/cmake/generator.py
+++ b/mesonbuild/cmake/generator.py
@@ -13,9 +13,18 @@
# limitations under the License.
from .. import mesonlib
+from .common import cmake_is_debug
import typing as T
-def parse_generator_expressions(raw: str) -> str:
+if T.TYPE_CHECKING:
+ from .traceparser import CMakeTraceParser, CMakeTarget
+
+def parse_generator_expressions(
+ raw: str,
+ trace: 'CMakeTraceParser',
+ *,
+ context_tgt: T.Optional['CMakeTarget'] = None,
+ ) -> str:
'''Parse CMake generator expressions
Most generator expressions are simply ignored for
@@ -44,6 +53,48 @@ def parse_generator_expressions(raw: str) -> str:
else:
return '1' if mesonlib.version_compare(arg[:col_pos], '{}{}'.format(op, arg[col_pos + 1:])) else '0'
+ def target_property(arg: str) -> str:
+ # We can't really support this since we don't have any context
+ if ',' not in arg:
+ if context_tgt is None:
+ return ''
+ return ';'.join(context_tgt.properties.get(arg, []))
+
+ args = arg.split(',')
+ props = trace.targets[args[0]].properties.get(args[1], []) if args[0] in trace.targets else []
+ return ';'.join(props)
+
+ def target_file(arg: str) -> str:
+ if arg not in trace.targets:
+ return ''
+ tgt = trace.targets[arg]
+
+ cfgs = []
+ cfg = ''
+
+ if 'IMPORTED_CONFIGURATIONS' in tgt.properties:
+ cfgs = [x for x in tgt.properties['IMPORTED_CONFIGURATIONS'] if x]
+ cfg = cfgs[0]
+
+ if cmake_is_debug(trace.env):
+ if 'DEBUG' in cfgs:
+ cfg = 'DEBUG'
+ elif 'RELEASE' in cfgs:
+ cfg = 'RELEASE'
+ else:
+ if 'RELEASE' in cfgs:
+ cfg = 'RELEASE'
+
+ if f'IMPORTED_IMPLIB_{cfg}' in tgt.properties:
+ return ';'.join([x for x in tgt.properties[f'IMPORTED_IMPLIB_{cfg}'] if x])
+ elif 'IMPORTED_IMPLIB' in tgt.properties:
+ return ';'.join([x for x in tgt.properties['IMPORTED_IMPLIB'] if x])
+ elif f'IMPORTED_LOCATION_{cfg}' in tgt.properties:
+ return ';'.join([x for x in tgt.properties[f'IMPORTED_LOCATION_{cfg}'] if x])
+ elif 'IMPORTED_LOCATION' in tgt.properties:
+ return ';'.join([x for x in tgt.properties['IMPORTED_LOCATION'] if x])
+ return ''
+
supported = {
# Boolean functions
'BOOL': lambda x: '0' if x.upper() in ['0', 'FALSE', 'OFF', 'N', 'NO', 'IGNORE', 'NOTFOUND'] or x.endswith('-NOTFOUND') else '1',
@@ -51,6 +102,8 @@ def parse_generator_expressions(raw: str) -> str:
'OR': lambda x: '1' if any([y == '1' for y in x.split(',')]) else '0',
'NOT': lambda x: '0' if x == '1' else '1',
+ 'IF': lambda x: x.split(',')[1] if x.split(',')[0] == '1' else x.split(',')[2],
+
'0': lambda x: '',
'1': lambda x: x,
@@ -78,6 +131,12 @@ def parse_generator_expressions(raw: str) -> str:
'ANGLE-R': lambda x: '>',
'COMMA': lambda x: ',',
'SEMICOLON': lambda x: ';',
+
+ # Target related expressions
+ 'TARGET_EXISTS': lambda x: '1' if x in trace.targets else '0',
+ 'TARGET_NAME_IF_EXISTS': lambda x: x if x in trace.targets else '',
+ 'TARGET_PROPERTY': target_property,
+ 'TARGET_FILE': target_file,
} # type: T.Dict[str, T.Callable[[str], str]]
# Recursively evaluate generator expressions
diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py
index 44b7e57..a619d1a 100644
--- a/mesonbuild/cmake/interpreter.py
+++ b/mesonbuild/cmake/interpreter.py
@@ -784,7 +784,7 @@ class CMakeInterpreter:
self.languages = [] # type: T.List[str]
self.targets = [] # type: T.List[ConverterTarget]
self.custom_targets = [] # type: T.List[ConverterCustomTarget]
- self.trace = CMakeTraceParser('', Path('.')) # Will be replaced in analyse
+ self.trace = CMakeTraceParser('', Path('.'), self.env) # Will be replaced in analyse
self.output_target_map = OutputTargetMap(self.build_dir)
# Generated meson data
@@ -805,7 +805,7 @@ class CMakeInterpreter:
cmake_exe = CMakeExecutor(self.env, '>=3.14', MachineChoice.BUILD)
if not cmake_exe.found():
raise CMakeException('Unable to find CMake')
- self.trace = CMakeTraceParser(cmake_exe.version(), self.build_dir, permissive=True)
+ self.trace = CMakeTraceParser(cmake_exe.version(), self.build_dir, self.env, permissive=True)
preload_file = DataFile('cmake/data/preload.cmake').write_to_private(self.env)
toolchain = CMakeToolchain(cmake_exe, self.env, self.for_machine, CMakeExecScope.SUBPROJECT, self.build_dir, preload_file)
diff --git a/mesonbuild/cmake/toolchain.py b/mesonbuild/cmake/toolchain.py
index 316f57c..e30f642 100644
--- a/mesonbuild/cmake/toolchain.py
+++ b/mesonbuild/cmake/toolchain.py
@@ -232,7 +232,7 @@ class CMakeToolchain:
temp_toolchain_file.write_text(CMakeToolchain._print_vars(self.variables), encoding='utf-8')
# Configure
- trace = CMakeTraceParser(self.cmakebin.version(), build_dir)
+ trace = CMakeTraceParser(self.cmakebin.version(), build_dir, self.env)
self.cmakebin.set_exec_mode(print_cmout=False, always_capture_stderr=trace.requires_stderr())
cmake_args = []
cmake_args += trace.trace_args()
diff --git a/mesonbuild/cmake/traceparser.py b/mesonbuild/cmake/traceparser.py
index 7909e13..7336d15 100644
--- a/mesonbuild/cmake/traceparser.py
+++ b/mesonbuild/cmake/traceparser.py
@@ -27,6 +27,9 @@ import re
import json
import textwrap
+if T.TYPE_CHECKING:
+ from ..environment import Environment
+
class CMakeTraceLine:
def __init__(self, file_str: str, line: int, func: str, args: T.List[str]) -> None:
self.file = CMakeTraceLine._to_path(file_str)
@@ -90,7 +93,7 @@ class CMakeGeneratorTarget(CMakeTarget):
self.working_dir = None # type: T.Optional[Path]
class CMakeTraceParser:
- def __init__(self, cmake_version: str, build_dir: Path, permissive: bool = True) -> None:
+ def __init__(self, cmake_version: str, build_dir: Path, env: 'Environment', permissive: bool = True) -> None:
self.vars: T.Dict[str, T.List[str]] = {}
self.vars_by_file: T.Dict[Path, T.Dict[str, T.List[str]]] = {}
self.targets: T.Dict[str, CMakeTarget] = {}
@@ -101,6 +104,7 @@ class CMakeTraceParser:
# T.List of targes that were added with add_custom_command to generate files
self.custom_targets = [] # type: T.List[CMakeGeneratorTarget]
+ self.env = env
self.permissive = permissive # type: bool
self.cmake_version = cmake_version # type: str
self.trace_file = 'cmake_trace.txt'
@@ -194,6 +198,38 @@ class CMakeTraceParser:
if fn:
fn(l)
+ # Evaluate generator expressions
+ strlist_gen: T.Callable[[T.List[str]], T.List[str]] = lambda strlist: [parse_generator_expressions(x, self) for x in strlist]
+ pathlist_gen: T.Callable[[T.List[Path]], T.List[Path]] = lambda plist: [Path(parse_generator_expressions(str(x), self)) for x in plist]
+
+ self.vars = {k: strlist_gen(v) for k, v in self.vars.items()}
+ self.vars_by_file = {
+ p: {k: strlist_gen(v) for k, v in d.items()}
+ for p, d in self.vars_by_file.items()
+ }
+ self.explicit_headers = set(Path(parse_generator_expressions(str(x), self)) for x in self.explicit_headers)
+ self.cache = {
+ k: CMakeCacheEntry(
+ strlist_gen(v.value),
+ v.type
+ )
+ for k, v in self.cache.items()
+ }
+
+ for tgt in self.targets.values():
+ tgtlist_gen: T.Callable[[T.List[str], CMakeTarget], T.List[str]] = lambda strlist, t: [parse_generator_expressions(x, self, context_tgt=t) for x in strlist]
+ tgt.name = parse_generator_expressions(tgt.name, self, context_tgt=tgt)
+ tgt.type = parse_generator_expressions(tgt.type, self, context_tgt=tgt)
+ tgt.properties = {
+ k: tgtlist_gen(v, tgt) for k, v in tgt.properties.items()
+ } if tgt.properties is not None else None
+ tgt.depends = tgtlist_gen(tgt.depends, tgt)
+
+ for ctgt in self.custom_targets:
+ ctgt.outputs = pathlist_gen(ctgt.outputs)
+ ctgt.command = [strlist_gen(x) for x in ctgt.command]
+ ctgt.working_dir = Path(parse_generator_expressions(str(ctgt.working_dir), self)) if ctgt.working_dir is not None else None
+
# Postprocess
for tgt in self.targets.values():
tgt.strip_properties()
@@ -688,7 +724,6 @@ class CMakeTraceParser:
line = mo_file_line.group(3)
func = mo_file_line.group(4)
args = mo_file_line.group(5)
- args = parse_generator_expressions(args)
argl = args.split(' ')
argl = list(map(lambda x: x.strip(), argl))
@@ -706,7 +741,6 @@ class CMakeTraceParser:
args = data['args']
for j in args:
assert isinstance(j, str)
- args = [parse_generator_expressions(x) for x in args]
yield CMakeTraceLine(data['file'], data['line'], data['cmd'], args)
def _flatten_args(self, args: T.List[str]) -> T.List[str]: