[cmake-developers] -Wl,-rpath-link and --sysroot on Linux

Clemens Lang Clemens.Lang at bmw-carit.de
Wed Jul 4 12:17:44 EDT 2018


I think I may have found a problem related to CMake’s handling of -Wl,-rpath-link on Linux in combination with cross-compiling against a sysroot. You can grab a minimal example that exposes the behavior at https://github.com/neverpanic/cmake-rpath-link-example.

The example uses a chain of linkage from an executable to a library B, which in turn links to a library A. Both libraries are in subdirectories of the build tree that are not part of the default search path of the linker. CMake adds -Wl,-rpath during the build to ensure that these libraries are found. The key here is that library B links against library A privately, i.e. A is not part of B’s link interface.

When linking the executable that uses library B, CMake adds -Wl,-rpath /path/to/directory/of/lib/b and path/to/libB.so to the linking command line. When linking executables (or libraries with --no-allow-shlib-undefined), binutils ld attempts to locate all transitively linked libraries to ensure no symbols are missing. According to the binutils ld documentation[1] “[t]he -rpath option is also used when locating shared objects which are needed by shared objects explicitly included in the link; see the description of the -rpath-link option.” This allows the linker to find the required library file (lib A in the example) when not compiling against a sysroot. However, when --sysroot is passed to the linker, all rpaths found in the libraries are prefixed with the sysroot, causing the linker to fail to locate lib A. See also the documentation for the -rpath-link option in [1], which explains the linker’s search behavior.

The solution to the problem is passing -Wl,-rpath-link,/path/to/directory/of/lib/a. CMake does support generating this flag, but does not currently do so in this case. cmComputeLinkInformation::AddSharedDepItem would add the required entry to cmComputeLinkInformation::OrderDependentRPath when SharedDependencyMode is SharedDepModeDir (which is the case), however AddSharedDepItem is only called in cmComputeLinkInformation::Compute if the LinkEntry obtained from cmComputeLinkDepends::Compute has the IsSharedDep flag set.

This flag gets set in cmComputeLinkDepends::HandleSharedDependency, which is called for every entry added to cmComputeLinkDepends::SharedDepQueue in cmComputeLinkDepends::FollowLinkEntry. This would require that every indirect library dependency (part of the link interface or otherwise) would have to be added to cmLinkInterface::SharedDeps as returned from cmGeneratorTarget::GetLinkInterface.

cmLinkInterface::SharedDeps gets set in cmGeneratorTarget::ComputeLinkInterface, but that currently only happens when cmOptionalLinkInterface::ExplicitLibraries (i.e. the INTERFACE_LINK_LIBRARIES property) is not null. To my mind, that does not make a lot of sense (and in fact, adding a library to the link interface of lib B in the example hides the problem).

I don’t feel familiar enough with the internals of CMake link interface handling to determine that changing cmGeneratorTarget::ComputeLinkInterface to always populate SharedDeps is the right thing to do and does not have unintended side effects, so I’m looking for feedback.

I’m attaching a patch that shows what a solution could look like, but I’m not positive that it’s correct.

Note that https://cmake.org/Bug/view.php?id=14684 seems related.

[1] https://sourceware.org/binutils/docs/ld/Options.html#Options
Clemens Lang • Development Specialist
BMW Car IT GmbH • Lise-Meitner-Str. 14 • 89081 Ulm • http://bmw-carit.com
Geschäftsführer: Kai-Uwe Balszuweit und Christian Salzmann
Sitz und Registergericht: München HRB 134810
-------------- next part --------------
A non-text attachment was scrubbed...
Name: cmake-rpath-link.patch
Type: application/octet-stream
Size: 3355 bytes
Desc: cmake-rpath-link.patch
URL: <https://cmake.org/pipermail/cmake-developers/attachments/20180704/20cd67ec/attachment.obj>

More information about the cmake-developers mailing list