Skip to content

Commit

Permalink
cmake: Fix old style dependency lookup with imported targets
Browse files Browse the repository at this point in the history
This also includes some refactoring, since the alternaticve would
have been to duplicate the huge traceparser target code block again.

fixes mesonbuild#9581
  • Loading branch information
mensinda authored and jpakkane committed Dec 1, 2021
1 parent 4f882ff commit 45c5300
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 169 deletions.
6 changes: 5 additions & 1 deletion mesonbuild/cmake/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,17 @@
'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
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
12 changes: 12 additions & 0 deletions mesonbuild/cmake/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,18 @@
'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

Expand Down
83 changes: 6 additions & 77 deletions mesonbuild/cmake/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
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
Expand Down Expand Up @@ -342,84 +343,12 @@ def postprocess(self, output_target_map: OutputTargetMap, root_src_dir: Path, su
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')

Expand Down
117 changes: 117 additions & 0 deletions mesonbuild/cmake/tracetargets.py
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 45c5300

Please sign in to comment.