PeterErnsthaft
PeterErnsthaft

Reputation: 395

CMake: how do I avoid getting absolute paths in INTERFACE target properties?

General problem: I get absolute paths in my INTERFACE_LINK_LIBRARIES and INTERFACE_INCLUDE_DIRECTORIES properties for a target, which is a problem because these variables get exported via the install(EXPORT), which will mean trouble if anything is relocated. I traced the origin of these absolute paths back to the find_package command, which (for some but not all packages) sets variables like Boost_LIBRARIES with absolute paths. When they are used with e.g. the target_link_libraries command, they end up in the INTERFACE_LINK_LIBRARIES.

Q: How do I best avoid the exported target properties from being poluted with absolute paths?

The trivial solution is obviously to just overwrite the respective variables with some strings that only name the libraries (hardcoded), but I guess there should be a better way.

Specific problem (Example): see https://github.com/cartographer-project/cartographer/issues/1688


EDIT: My (modified) cartographer-config.cmake.in (note: you can ignore the stuff associated to ceres, since that does not give me trouble, eventhough it places an abs path in the hint):

# Copyright 2016 The Cartographer Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

#  Usage from an external project:
#    In your CMakeLists.txt, add these lines:
#
#    find_package(cartographer REQUIRED)
#    target_link_libraries(MY_TARGET_NAME PUBLIC cartographer)

@PACKAGE_INIT@

set_and_check(CARTOGRAPHER_CMAKE_DIR "@PACKAGE_CARTOGRAPHER_CMAKE_DIR@")

find_dependency(Boost)
find_dependency(Lua)

set(CERES_DIR_HINTS @Ceres_DIR@)

if (cartographer_FIND_QUIETLY)
   find_package(Ceres QUIET HINTS ${CERES_DIR_HINTS})
elseif (cartographer_FIND_REQUIRED)
   find_package(Ceres REQUIRED HINTS ${CERES_DIR_HINTS})
else ()
   find_package(Ceres HINTS ${CERES_DIR_HINTS})
endif()

include("${CARTOGRAPHER_CMAKE_DIR}/CartographerTargets.cmake")                                                                                  

Upvotes: 1

Views: 1643

Answers (1)

Tsyvarev
Tsyvarev

Reputation: 65996

How do I best avoid the exported target properties from being poluted with absolute paths?

Hide absolute paths behind the IMPORTED target:

# Express an external library via IMPORTED target
add_library(lib_external IMPORTED)
set_target_properties(lib_external PROPERTIES
  IMPORTED_LOCATION "${XXX_LIBRARY} (some absolute path)"
  INTERFACE_INCLUDE_DIRECTORIES "${XXX_INCLUDE_DIRECTORIES} (some absolute path)"
)

# Use external library via the target created
target_link_libraries(my_lib lib_external)

Such way, the config file for my_lib will contain only the name of the IMPORTED library, but not its properties.

In the config file for your project you just need to create IMPORTED target with the same name and fill its properties according to the current machine (where your project is used).

find_package for most of modern packages (including Boost) already returns an IMPORTED target. In the configuration file for your project you may use find_dependency, which discovers the package on the current machine and creates an IMPORTED target again.

For old packages, which find_package just returns XXX_LIBRARIES and XXX_INCLUDE_DIRECTORIES variables, you may create the IMPORTED target manually. In the configuration file for your project you may use find_dependency too, and again create IMPORTED target manually.


When use find_dependency macro, remember to pass the same parameters which you have passed to the find_package() in the project's CMakeLists.txt. This is primary about COMPONENTS parameter and variables like Boost_USE_STATIC_LIBS, which affects on the package searching.

If you want to specify VERSION requirement, then this requirement should express binary compatibility of the library on the target machine with the library against which the project has been actually built.

HINST and PATHS options for find_package are unlikely needed to be transferred to the find_dependency: call to the find_dependency is processed on the target machine, which paths could be different from ones on the build machine.

Upvotes: 2

Related Questions