[cmake-developers] Target's IMPORTED_LOCATION_* when CMAKE_INSTALL_PREFIX or CPACK_PACKAGING_INSTALL_PREFIX is "/"

Ben Keller irods.ben.keller at gmail.com
Tue Sep 6 15:00:03 EDT 2016


CMake version 3.5.0

When exporting from a project (with install(EXPORT ...)),
the<PROJECT>Targets.cmake file contains logic for computing the
_IMPORT_PREFIX. This _IMPORT_PREFIX is then used in the
<PROJECT>Targets-<configuration>.cmake file to generate the
IMPORTED_LOCATION_<uppercase-configuration>. The generation appears to
be accomplished by unconditionally appending a "/" to _IMPORT_PREFIX
before appending the rest of the path. If _IMPORT_PREFIX is "/", then
the IMPORTED_LOCATION_<uppercase-configuration> properties all start
with exactly two leading slashes ("//").

Exactly two leading slashes is apparently a special case in POSIX file
paths, such that its interpretation is left up to the implementation.
This means that changing the path prefix from "/" to "//" should not
be allowed.

A result of this is that when importing a library installed to
/usr/lib, the IMPORTED_LOCATION_DEBUG ends up being
"//usr/lib/libmylib.so". At this point in the project, CMake doesn't
contract the two leading slashes (as it apparently shouldn't), so
executables linking against the mylib target end up with "//usr/lib"
in their RPATH. This works fine with the Linux dynamic linker, but if
a program uses dladdr() to get the location of the shared library, the
leading "//" is still present. Manipulation of this path within the
program (e.g. with boost::filesystem) then fails to work as expected,
if the manipulation code is sensitive to the leading "//".

Example of generated cmake code when CPACK_PACKAGING_INSTALL_PREFIX is
"/" and <PROJECT>Targets.cmake is installed via the INSTALL() command
with DESTINATION "usr/lib/<PROJECT>/cmake":

[ -- From <PROJECT>Targets.cmake -- ]
# Compute the installation prefix relative to this file.
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)

[ -- From <PROJECT>Targets-<configuration>.cmake -- ]

IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/usr/lib/libmylib.so"


The workaround we are using for this currently is to compile a
modified version of cmake that appends the following cmake code below
the get_filename_component stanza in <PROJECTS>Targets.cmake:

if("${_IMPORT_PREFIX}" STREQUAL "/")
  set(_IMPORT_PREFIX "")
endif()


More information about the cmake-developers mailing list