cmake: Only propagate interface link flags in dep

CMake has two target properties, LINK_OPTIONS and INTERFACE_LINK_OPTIONS.
The former is for link flags that apply only to the target (PRIVATE).
The latter is used for link flags that propagate to dependents (PUBLIC
or INTERFACE). Meson currently propagates all flags, PUBLIC and PRIVATE,
as part of the generated dependency() which causes problems when some of
the private flags are highly disruptive, e.g. `-Wl,--version-script`.

Tease apart the two kinds of link flags and, for non-static libraries,
only propagate the PUBLIC/INTERFACE flags and not the PRIVATE ones.
pull/13429/head
Jonathon Anderson 5 months ago committed by Eli Schwartz
parent b1f4e1495d
commit 6165db80bb
  1. 8
      docs/markdown/snippets/cmake_only_public_link_flags_in_dep.md
  2. 10
      mesonbuild/cmake/interpreter.py
  3. 4
      mesonbuild/cmake/tracetargets.py

@ -0,0 +1,8 @@
## Dependencies from CMake subprojects now use only PUBLIC link flags
Any [[@dep]] obtained from a CMake subproject (or `.wrap` with `method = cmake`)
now only includes link flags marked in CMake as `PUBLIC` or `INTERFACE`.
Flags marked as `PRIVATE` are now only applied when building the subproject
library and not when using it as a dependency. This better matches how CMake
handles link flags and fixes link errors when using some CMake projects as
subprojects.

@ -223,6 +223,7 @@ class ConverterTarget:
self.install_dir: T.Optional[Path] = None
self.link_libraries = target.link_libraries
self.link_flags = target.link_flags + target.link_lang_flags
self.public_link_flags: T.List[str] = []
self.depends_raw: T.List[str] = []
self.depends: T.List[T.Union[ConverterTarget, ConverterCustomTarget]] = []
@ -347,6 +348,7 @@ class ConverterTarget:
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_link_flags += rtgt.public_link_flags
self.public_compile_opts += rtgt.public_compile_opts
self.link_libraries += rtgt.libraries
@ -1167,12 +1169,18 @@ class CMakeInterpreter:
# declare_dependency kwargs
dep_kwargs: TYPE_mixed_kwargs = {
'link_args': tgt.link_flags + tgt.link_libraries,
'link_with': id_node(tgt_var),
'compile_args': tgt.public_compile_opts,
'include_directories': id_node(inc_var),
}
# Static libraries need all link options and transient dependencies, but other
# libraries should only use the link flags from INTERFACE_LINK_OPTIONS.
if tgt_func == 'static_library':
dep_kwargs['link_args'] = tgt.link_flags + tgt.link_libraries
else:
dep_kwargs['link_args'] = tgt.public_link_flags
if dependencies:
generated += dependencies

@ -42,6 +42,7 @@ class ResolvedTarget:
def __init__(self) -> None:
self.include_directories: T.List[str] = []
self.link_flags: T.List[str] = []
self.public_link_flags: T.List[str] = []
self.public_compile_opts: T.List[str] = []
self.libraries: T.List[str] = []
@ -111,7 +112,8 @@ def resolve_cmake_trace_targets(target_name: str,
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]
res.public_link_flags += [x for x in tgt.properties['INTERFACE_LINK_OPTIONS'] if x]
res.link_flags += res.public_link_flags
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]

Loading…
Cancel
Save