Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 40 additions & 6 deletions mesonbuild/cmake/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,21 @@ def postprocess(self, output_target_map: OutputTargetMap, root_src_dir: Path, su
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')

# Handle set_source_files_properties(... OBJECT_DEPENDS ...): compiling a
# source may depend on (usually generated) files. Attach these at the target
# level so the generating custom targets are built first.
if trace.object_depends:
src_keys = set()
for x in self.sources + self.generated:
p = x if x.is_absolute() else self.src_dir / x
src_keys.add(p.resolve().as_posix())
for src, deps in trace.object_depends.items():
src_path = Path(src)
if not src_path.is_absolute():
continue
if src_path.resolve().as_posix() in src_keys:
self.depends_raw += deps

temp = []
for cmd in self.link_libraries:
# Let meson handle this arcane magic
Expand Down Expand Up @@ -502,7 +517,14 @@ def handle_frameworks(flags: T.List[str]) -> T.List[str]:
for arg in self.depends_raw:
dep_tgt = output_target_map.target(arg)
if dep_tgt:
self.depends.append(dep_tgt)
if dep_tgt not in self.depends:
self.depends.append(dep_tgt)
continue
# File-level dependencies (e.g. from OBJECT_DEPENDS) resolve to the
# custom target generating the file
gen = output_target_map.generated(Path(arg))
if gen and gen not in self.depends:
self.depends.append(gen)

def process_object_libs(self, obj_target_list: T.List['ConverterTarget'], linker_workaround: bool) -> None:
# Try to detect the object library(s) from the generated input sources
Expand Down Expand Up @@ -1130,12 +1152,24 @@ def process_target(tgt: ConverterTarget) -> None:
if i.name not in processed:
process_target(i)
objec_libs += [extract_tgt(i)]
for i in tgt.depends:
if not isinstance(i, ConverterCustomTarget):
# CMake guarantees that all dependencies of a target -- including those
# of linked and add_dependencies targets, transitively -- are built
# before any of the target's sources compile (the ninja backend emits
# cmake_object_order_depends_target_* edges for this). Collect all
# reachable custom targets so their generated files exist in time.
dep_stack = list(tgt.depends)
visited_deps: T.Set[str] = set()
while dep_stack:
i = dep_stack.pop(0)
if i.name in visited_deps:
continue
if i.name not in processed:
process_custom_target(i)
dependencies += [extract_tgt(i)]
visited_deps.add(i.name)
if isinstance(i, ConverterCustomTarget):
if i.name not in processed:
process_custom_target(i)
dependencies += [extract_tgt(i)]
elif isinstance(i, ConverterTarget):
dep_stack += i.depends

# Generate the source list and handle generated sources
sources += tgt.sources
Expand Down
32 changes: 32 additions & 0 deletions mesonbuild/cmake/traceparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ def __init__(self, cmake_version: str, build_dir: Path, env: 'Environment', perm

self.explicit_headers: T.Set[Path] = set()

# Object dependencies set via set_source_files_properties(... OBJECT_DEPENDS ...),
# mapping the source file to the files its compilation depends on
self.object_depends: T.Dict[str, T.List[str]] = {}

# T.List of targes that were added with add_custom_command to generate files
self.custom_targets: T.List[CMakeGeneratorTarget] = []

Expand Down Expand Up @@ -120,6 +124,7 @@ def __init__(self, cmake_version: str, build_dir: Path, env: 'Environment', perm
'add_custom_target': self._cmake_add_custom_target,
'set_property': self._cmake_set_property,
'set_target_properties': self._cmake_set_target_properties,
'set_source_files_properties': self._cmake_set_source_files_properties,
'target_compile_definitions': self._cmake_target_compile_definitions,
'target_compile_options': self._cmake_target_compile_options,
'target_include_directories': self._cmake_target_include_directories,
Expand Down Expand Up @@ -605,6 +610,33 @@ def _cmake_set_target_properties(self, tline: CMakeTraceLine) -> None:

self.targets[i].properties[name] = value

def _cmake_set_source_files_properties(self, tline: CMakeTraceLine) -> None:
# DOC: https://cmake.org/cmake/help/latest/command/set_source_files_properties.html
args = list(tline.args)

sources: T.List[str] = []
idx = 0
while idx < len(args) and args[idx] != 'PROPERTIES':
if args[idx] in {'DIRECTORY', 'TARGET_DIRECTORY'}:
# skip the scope arguments
idx += 1
while idx < len(args) and args[idx] not in {'DIRECTORY', 'TARGET_DIRECTORY', 'PROPERTIES'}:
idx += 1
continue
sources += args[idx].split(';')
idx += 1

object_depends: T.List[str] = []
idx += 1
while idx + 1 < len(args):
if args[idx] == 'OBJECT_DEPENDS':
object_depends += args[idx + 1].split(';')
idx += 2

if object_depends:
for i in sources:
self.object_depends.setdefault(i, []).extend(object_depends)

def _cmake_add_dependencies(self, tline: CMakeTraceLine) -> None:
# DOC: https://cmake.org/cmake/help/latest/command/add_dependencies.html
args = list(tline.args)
Expand Down
Loading