aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/cmake
diff options
context:
space:
mode:
authorDaniel Mensinger <daniel@mensinger-ka.de>2021-11-27 19:58:04 +0100
committerJussi Pakkanen <jpakkane@gmail.com>2021-12-01 21:03:36 +0200
commit45c5300496486ff9f1f3d47a01cdf19b8fa7e877 (patch)
tree97f3c7c077df90cc60e83ee4e0bf85e5379f9a4e /mesonbuild/cmake
parent4f882ff8ec81cbc42b097d3aee8ca4a8013f538b (diff)
downloadmeson-45c5300496486ff9f1f3d47a01cdf19b8fa7e877.zip
meson-45c5300496486ff9f1f3d47a01cdf19b8fa7e877.tar.gz
meson-45c5300496486ff9f1f3d47a01cdf19b8fa7e877.tar.bz2
cmake: Fix old style dependency lookup with imported targets
This also includes some refactoring, since the alternaticve would have been to duplicate the huge traceparser target code block again. fixes #9581
Diffstat (limited to 'mesonbuild/cmake')
-rw-r--r--mesonbuild/cmake/__init__.py6
-rw-r--r--mesonbuild/cmake/common.py12
-rw-r--r--mesonbuild/cmake/interpreter.py83
-rw-r--r--mesonbuild/cmake/tracetargets.py117
4 files changed, 140 insertions, 78 deletions
diff --git a/mesonbuild/cmake/__init__.py b/mesonbuild/cmake/__init__.py
index d39bf24..32b8b6c 100644
--- a/mesonbuild/cmake/__init__.py
+++ b/mesonbuild/cmake/__init__.py
@@ -34,9 +34,12 @@ __all__ = [
'cmake_get_generator_args',
'cmake_defines_to_args',
'check_cmake_args',
+ 'cmake_is_debug',
+ 'resolve_cmake_trace_targets',
+ 'ResolvedTarget',
]
-from .common import CMakeException, SingleTargetOptions, TargetOptions, cmake_defines_to_args, language_map, backend_generator_map, cmake_get_generator_args, check_cmake_args
+from .common import CMakeException, SingleTargetOptions, TargetOptions, cmake_defines_to_args, language_map, backend_generator_map, cmake_get_generator_args, check_cmake_args, cmake_is_debug
from .client import CMakeClient
from .executor import CMakeExecutor
from .fileapi import CMakeFileAPI
@@ -44,3 +47,4 @@ from .generator import parse_generator_expressions
from .interpreter import CMakeInterpreter
from .toolchain import CMakeToolchain, CMakeExecScope
from .traceparser import CMakeTarget, CMakeTraceLine, CMakeTraceParser
+from .tracetargets import resolve_cmake_trace_targets, ResolvedTarget
diff --git a/mesonbuild/cmake/common.py b/mesonbuild/cmake/common.py
index f6ba5ec..7130248 100644
--- a/mesonbuild/cmake/common.py
+++ b/mesonbuild/cmake/common.py
@@ -61,6 +61,18 @@ blacklist_cmake_defs = [
'MESON_CMAKE_ROOT',
]
+def cmake_is_debug(env: 'Environment') -> bool:
+ if OptionKey('b_vscrt') in env.coredata.options:
+ is_debug = env.coredata.get_option(OptionKey('buildtype')) == 'debug'
+ if env.coredata.options[OptionKey('b_vscrt')].value in {'mdd', 'mtd'}:
+ is_debug = True
+ return is_debug
+ else:
+ # Don't directly assign to is_debug to make mypy happy
+ debug_opt = env.coredata.get_option(OptionKey('debug'))
+ assert isinstance(debug_opt, bool)
+ return debug_opt
+
class CMakeException(MesonException):
pass
diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py
index 47459a2..a8ed67c 100644
--- a/mesonbuild/cmake/interpreter.py
+++ b/mesonbuild/cmake/interpreter.py
@@ -21,6 +21,7 @@ from .fileapi import CMakeFileAPI
from .executor import CMakeExecutor
from .toolchain import CMakeToolchain, CMakeExecScope
from .traceparser import CMakeTraceParser, CMakeGeneratorTarget
+from .tracetargets import resolve_cmake_trace_targets
from .. import mlog, mesonlib
from ..mesonlib import MachineChoice, OrderedSet, version_compare, path_is_in_root, relative_to_if_possible, OptionKey
from ..mesondata import mesondata
@@ -342,84 +343,12 @@ class ConverterTarget:
if tgt:
self.depends_raw = trace.targets[self.cmake_name].depends
- # TODO refactor this copy paste from CMakeDependency for future releases
- reg_is_lib = re.compile(r'^(-l[a-zA-Z0-9_]+|-l?pthread)$')
- to_process = [self.cmake_name]
- processed = []
- while len(to_process) > 0:
- curr = to_process.pop(0)
+ rtgt = resolve_cmake_trace_targets(self.cmake_name, trace, self.env)
+ self.includes += [Path(x) for x in rtgt.include_directories]
+ self.link_flags += rtgt.link_flags
+ self.public_compile_opts += rtgt.public_compile_opts
+ self.link_libraries += rtgt.libraries
- if curr in processed or curr not in trace.targets:
- continue
-
- tgt = trace.targets[curr]
- cfgs = []
- cfg = ''
- otherDeps = []
- libraries = []
- mlog.debug(str(tgt))
-
- if 'INTERFACE_INCLUDE_DIRECTORIES' in tgt.properties:
- self.includes += [Path(x) for x in tgt.properties['INTERFACE_INCLUDE_DIRECTORIES'] if x]
-
- if 'INTERFACE_LINK_OPTIONS' in tgt.properties:
- self.link_flags += [x for x in tgt.properties['INTERFACE_LINK_OPTIONS'] if x]
-
- if 'INTERFACE_COMPILE_DEFINITIONS' in tgt.properties:
- self.public_compile_opts += ['-D' + re.sub('^-D', '', x) for x in tgt.properties['INTERFACE_COMPILE_DEFINITIONS'] if x]
-
- if 'INTERFACE_COMPILE_OPTIONS' in tgt.properties:
- self.public_compile_opts += [x for x in tgt.properties['INTERFACE_COMPILE_OPTIONS'] if x]
-
- if 'IMPORTED_CONFIGURATIONS' in tgt.properties:
- cfgs += [x for x in tgt.properties['IMPORTED_CONFIGURATIONS'] if x]
- cfg = cfgs[0]
-
- if 'CONFIGURATIONS' in tgt.properties:
- cfgs += [x for x in tgt.properties['CONFIGURATIONS'] if x]
- cfg = cfgs[0]
-
- is_debug = self.env.coredata.get_option(OptionKey('debug'))
- if is_debug:
- 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:
- libraries += [x for x in tgt.properties[f'IMPORTED_IMPLIB_{cfg}'] if x]
- elif 'IMPORTED_IMPLIB' in tgt.properties:
- libraries += [x for x in tgt.properties['IMPORTED_IMPLIB'] if x]
- elif f'IMPORTED_LOCATION_{cfg}' in tgt.properties:
- libraries += [x for x in tgt.properties[f'IMPORTED_LOCATION_{cfg}'] if x]
- elif 'IMPORTED_LOCATION' in tgt.properties:
- libraries += [x for x in tgt.properties['IMPORTED_LOCATION'] if x]
-
- if 'LINK_LIBRARIES' in tgt.properties:
- otherDeps += [x for x in tgt.properties['LINK_LIBRARIES'] if x]
-
- if 'INTERFACE_LINK_LIBRARIES' in tgt.properties:
- otherDeps += [x for x in tgt.properties['INTERFACE_LINK_LIBRARIES'] if x]
-
- if f'IMPORTED_LINK_DEPENDENT_LIBRARIES_{cfg}' in tgt.properties:
- otherDeps += [x for x in tgt.properties[f'IMPORTED_LINK_DEPENDENT_LIBRARIES_{cfg}'] if x]
- elif 'IMPORTED_LINK_DEPENDENT_LIBRARIES' in tgt.properties:
- otherDeps += [x for x in tgt.properties['IMPORTED_LINK_DEPENDENT_LIBRARIES'] if x]
-
- for j in otherDeps:
- if j in trace.targets:
- to_process += [j]
- elif reg_is_lib.match(j) or Path(j).exists():
- libraries += [j]
-
- for j in libraries:
- if j not in self.link_libraries:
- self.link_libraries += [j]
-
- processed += [curr]
elif self.type.upper() not in ['EXECUTABLE', 'OBJECT_LIBRARY']:
mlog.warning('CMake: Target', mlog.bold(self.cmake_name), 'not found in CMake trace. This can lead to build errors')
diff --git a/mesonbuild/cmake/tracetargets.py b/mesonbuild/cmake/tracetargets.py
new file mode 100644
index 0000000..21aad86
--- /dev/null
+++ b/mesonbuild/cmake/tracetargets.py
@@ -0,0 +1,117 @@
+# SPDX-License-Identifer: Apache-2.0
+# Copyright 2021 The Meson development team
+
+from .common import cmake_is_debug
+from .. import mlog
+
+from pathlib import Path
+import re
+import typing as T
+
+if T.TYPE_CHECKING:
+ from .traceparser import CMakeTraceParser
+ from ..environment import Environment
+ from ..compilers import Compiler
+
+class ResolvedTarget:
+ def __init__(self) -> None:
+ self.include_directories: T.List[str] = []
+ self.link_flags: T.List[str] = []
+ self.public_compile_opts: T.List[str] = []
+ self.libraries: T.List[str] = []
+
+def resolve_cmake_trace_targets(target_name: str,
+ trace: 'CMakeTraceParser',
+ env: 'Environment',
+ *,
+ clib_compiler: T.Optional['Compiler'] = None,
+ not_found_warning: T.Callable[[str], None] = lambda x: None) -> ResolvedTarget:
+ res = ResolvedTarget()
+ targets = [target_name]
+
+ # recognise arguments we should pass directly to the linker
+ reg_is_lib = re.compile(r'^(-l[a-zA-Z0-9_]+|-l?pthread)$')
+ reg_is_maybe_bare_lib = re.compile(r'^[a-zA-Z0-9_]+$')
+
+ is_debug = cmake_is_debug(env)
+
+ processed_targets: T.List[str] = []
+ while len(targets) > 0:
+ curr = targets.pop(0)
+
+ # Skip already processed targets
+ if curr in processed_targets:
+ continue
+
+ if curr not in trace.targets:
+ if reg_is_lib.match(curr):
+ res.libraries += [curr]
+ elif Path(curr).is_absolute() and Path(curr).exists():
+ res.libraries += [curr]
+ elif env.machines.build.is_windows() and reg_is_maybe_bare_lib.match(curr) and clib_compiler is not None:
+ # On Windows, CMake library dependencies can be passed as bare library names,
+ # CMake brute-forces a combination of prefix/suffix combinations to find the
+ # right library. Assume any bare argument passed which is not also a CMake
+ # target must be a system library we should try to link against.
+ res.libraries += clib_compiler.find_library(curr, env, [])
+ else:
+ not_found_warning(curr)
+ continue
+
+ tgt = trace.targets[curr]
+ cfgs = []
+ cfg = ''
+ mlog.debug(tgt)
+
+ if 'INTERFACE_INCLUDE_DIRECTORIES' in tgt.properties:
+ res.include_directories += [x for x in tgt.properties['INTERFACE_INCLUDE_DIRECTORIES'] if x]
+
+ if 'INTERFACE_LINK_OPTIONS' in tgt.properties:
+ res.link_flags += [x for x in tgt.properties['INTERFACE_LINK_OPTIONS'] if x]
+
+ if 'INTERFACE_COMPILE_DEFINITIONS' in tgt.properties:
+ res.public_compile_opts += ['-D' + re.sub('^-D', '', x) for x in tgt.properties['INTERFACE_COMPILE_DEFINITIONS'] if x]
+
+ if 'INTERFACE_COMPILE_OPTIONS' in tgt.properties:
+ res.public_compile_opts += [x for x in tgt.properties['INTERFACE_COMPILE_OPTIONS'] if x]
+
+ if 'IMPORTED_CONFIGURATIONS' in tgt.properties:
+ cfgs = [x for x in tgt.properties['IMPORTED_CONFIGURATIONS'] if x]
+ cfg = cfgs[0]
+
+ if is_debug:
+ 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:
+ res.libraries += [x for x in tgt.properties[f'IMPORTED_IMPLIB_{cfg}'] if x]
+ elif 'IMPORTED_IMPLIB' in tgt.properties:
+ res.libraries += [x for x in tgt.properties['IMPORTED_IMPLIB'] if x]
+ elif f'IMPORTED_LOCATION_{cfg}' in tgt.properties:
+ res.libraries += [x for x in tgt.properties[f'IMPORTED_LOCATION_{cfg}'] if x]
+ elif 'IMPORTED_LOCATION' in tgt.properties:
+ res.libraries += [x for x in tgt.properties['IMPORTED_LOCATION'] if x]
+
+ if 'LINK_LIBRARIES' in tgt.properties:
+ targets += [x for x in tgt.properties['LINK_LIBRARIES'] if x]
+ if 'INTERFACE_LINK_LIBRARIES' in tgt.properties:
+ targets += [x for x in tgt.properties['INTERFACE_LINK_LIBRARIES'] if x]
+
+ if f'IMPORTED_LINK_DEPENDENT_LIBRARIES_{cfg}' in tgt.properties:
+ targets += [x for x in tgt.properties[f'IMPORTED_LINK_DEPENDENT_LIBRARIES_{cfg}'] if x]
+ elif 'IMPORTED_LINK_DEPENDENT_LIBRARIES' in tgt.properties:
+ targets += [x for x in tgt.properties['IMPORTED_LINK_DEPENDENT_LIBRARIES'] if x]
+
+ processed_targets += [curr]
+
+ res.include_directories = sorted(set(res.include_directories))
+ res.link_flags = sorted(set(res.link_flags))
+ res.public_compile_opts = sorted(set(res.public_compile_opts))
+ res.libraries = sorted(set(res.libraries))
+
+ return res