diff options
-rw-r--r-- | mesonbuild/cmake/generator.py | 61 | ||||
-rw-r--r-- | mesonbuild/cmake/interpreter.py | 4 | ||||
-rw-r--r-- | mesonbuild/cmake/toolchain.py | 2 | ||||
-rw-r--r-- | mesonbuild/cmake/traceparser.py | 40 | ||||
-rw-r--r-- | mesonbuild/dependencies/cmake.py | 4 | ||||
-rw-r--r-- | test cases/cmake/12 generator expressions/subprojects/cmMod/CMakeLists.txt | 10 | ||||
-rw-r--r-- | test cases/cmake/12 generator expressions/subprojects/cmMod/include/cmMod.hpp | 32 | ||||
-rw-r--r-- | test cases/cmake/12 generator expressions/test.json | 5 |
8 files changed, 149 insertions, 9 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]: diff --git a/mesonbuild/dependencies/cmake.py b/mesonbuild/dependencies/cmake.py index 09f7f14..cff0e58 100644 --- a/mesonbuild/dependencies/cmake.py +++ b/mesonbuild/dependencies/cmake.py @@ -127,7 +127,7 @@ class CMakeDependency(ExternalDependency): return # Setup the trace parser - self.traceparser = CMakeTraceParser(self.cmakebin.version(), self._get_build_dir()) + self.traceparser = CMakeTraceParser(self.cmakebin.version(), self._get_build_dir(), self.env) cm_args = stringlistify(extract_as_list(kwargs, 'cmake_args')) cm_args = check_cmake_args(cm_args) @@ -166,7 +166,7 @@ class CMakeDependency(ExternalDependency): gen_list += [CMakeDependency.class_working_generator] gen_list += CMakeDependency.class_cmake_generators - temp_parser = CMakeTraceParser(self.cmakebin.version(), self._get_build_dir()) + temp_parser = CMakeTraceParser(self.cmakebin.version(), self._get_build_dir(), self.env) toolchain = CMakeToolchain(self.cmakebin, self.env, self.for_machine, CMakeExecScope.DEPENDENCY, self._get_build_dir()) toolchain.write() diff --git a/test cases/cmake/12 generator expressions/subprojects/cmMod/CMakeLists.txt b/test cases/cmake/12 generator expressions/subprojects/cmMod/CMakeLists.txt index dc4f9e4..27b3721 100644 --- a/test cases/cmake/12 generator expressions/subprojects/cmMod/CMakeLists.txt +++ b/test cases/cmake/12 generator expressions/subprojects/cmMod/CMakeLists.txt @@ -12,6 +12,10 @@ target_compile_options(cmModLib INTERFACE "-DCMAKE_FLAG_REQUIRED_A" INTERFACE $<$<AND:1,$<STREQUAL:asd,$<LOWER_CASE:AsD>>,$<NOT:$<EQUAL:4,2>>>:-DCMAKE_FLAG_REQUIRED_B> INTERFACE $<$<VERSION_LESS:1.2.3,2.1.0>:-DCMAKE_FLAG_REQUIRED_C> + INTERFACE $<IF:$<NOT:$<BOOL:OFF>>,-DCMAKE_TRUE_FLAG,-DCMAKE_FALSE_FLAG> + INTERFACE $<IF:$<TARGET_EXISTS:cmModLib>,-DCMAKE_TGT_EXISTS,-DCMAKE_TGT_NEXISTS> + INTERFACE $<IF:$<TARGET_PROPERTY:IMPORTED_NO_SONAME>,-DCMAKE_PROP1_OK,-DCMAKE_PROP1_ERROR> + INTERFACE $<IF:$<TARGET_PROPERTY:cmModLib,IMPORT_SUFFIX>,-DCMAKE_PROP2_ERROR,-DCMAKE_PROP2_OK> ) target_include_directories(cmModLib INTERFACE @@ -19,4 +23,10 @@ target_include_directories(cmModLib INTERFACE $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> ) +set_target_properties(cmModLib + PROPERTIES + IMPORTED_NO_SONAME 1 + IMPORT_SUFFIX 0 +) + target_compile_definitions(cmModLib INTERFACE -DCMAKE_COMPILER_DEFINE_STR="compDef") diff --git a/test cases/cmake/12 generator expressions/subprojects/cmMod/include/cmMod.hpp b/test cases/cmake/12 generator expressions/subprojects/cmMod/include/cmMod.hpp index 1f00107..416e5bb 100644 --- a/test cases/cmake/12 generator expressions/subprojects/cmMod/include/cmMod.hpp +++ b/test cases/cmake/12 generator expressions/subprojects/cmMod/include/cmMod.hpp @@ -18,6 +18,38 @@ #error "The flag CMAKE_FLAG_ERROR_A was set" #endif +#ifndef CMAKE_TRUE_FLAG +#error "The flag CMAKE_TRUE_FLAG was not set" +#endif + +#ifdef CMAKE_FALSE_FLAG +#error "The flag CMAKE_FALSE_FLAG was set" +#endif + +#ifndef CMAKE_TGT_EXISTS +#error "The flag CMAKE_TGT_EXISTS was not set" +#endif + +#ifdef CMAKE_TGT_NEXISTS +#error "The flag CMAKE_TGT_NEXISTS was set" +#endif + +#ifndef CMAKE_PROP1_OK +#error "The flag CMAKE_PROP1_OK was not set" +#endif + +#ifdef CMAKE_PROP1_ERROR +#error "The flag CMAKE_PROP1_ERROR was set" +#endif + +#ifndef CMAKE_PROP2_OK +#error "The flag CMAKE_PROP2_OK was not set" +#endif + +#ifdef CMAKE_PROP2_ERROR +#error "The flag CMAKE_PROP2_ERROR was set" +#endif + class cmModClass { private: std::string str; diff --git a/test cases/cmake/12 generator expressions/test.json b/test cases/cmake/12 generator expressions/test.json new file mode 100644 index 0000000..faf1ff8 --- /dev/null +++ b/test cases/cmake/12 generator expressions/test.json @@ -0,0 +1,5 @@ +{ + "tools": { + "cmake": ">=3.19" + } +} |