Reputation: 778
My project structure looks like this:
Parent/
CMakeLists.txt
file.cpp
third_party/
dependency/
CMakeLists.txt
lib/
dependency.lib
Note that dependency.lib is a precompiled/prebuilt library: I don't even have sources for it.
When I install Parent
, I want it to go into a dist folder like this (within the previous tree structure but omitted for clarity):
Parent/
dist/
Parent/
include/
bin/
lib/
cmake/
ParentTargets.cmake
Parent.lib
dependency.lib
The idea here is to just get both the generated as well as the dependency libraries all in one place for easier install.
Relevant parts of Parent's CMakeLists.txt
look like this (omitting a lot of stuff like includes, etc.):
cmake_minimum_required(VERSION 3.22)
project(Parent VERSION 0.1.0 LANGUAGES C CXX)
add_library(Parent)
target_sources(Parent PRIVATE file.cpp)
add_subdirectory("${CMAKE_SOURCE_DIR}/third_party/dependency")
target_link_libraries(Parent PRIVATE dependency)
# Manual copy of dependency.lib to install location
install(DIRECTORY "${CMAKE_SOURCE_DIR}/third_party/dependency/lib/"
DESTINATION lib
FILES_MATCHING
PATTERN "dependency.lib"
)
# Install all targets to ParentTargets export set.
# (omitting install dir variables, components, etc. for clarity)
install(
TARGETS
Parent dependency
EXPORT
ParentTargets
LIBRARY
DESTINATION lib
ARCHIVE
DESTINATION lib
)
# Write ParentTargets export set to targets file directly in install folder
install(EXPORT ParentTargets
FILE ParentTargets.cmake
NAMESPACE Parent::
DESTINATION lib/cmake
)
And this is what I have for the dependency's CMakeLists.txt
:
add_library(dependency INTERFACE)
target_link_libraries(dependency
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/lib/dependency.lib>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/lib/dependency.lib>
)
This almost sort of works, the issue is that if you look at the generated ParentTargets.cmake
, this is what CMake generates for the dependency
target:
# Create imported target Parent::dependency
add_library(Parent::dependency INTERFACE IMPORTED)
set_target_properties(Parent::dependency PROPERTIES
INTERFACE_LINK_LIBRARIES "E:/absolute/path/Parent/dist/Parent/lib/dependency.lib"
)
...its a hard-coded absolute path to my installation directory. This is not great, and usually for built libraries CMake would have generated a path like ${_IMPORT_PREFIX}/lib/dependency.lib
, which is what I wanted and important to have the install relocatable.
Here are my questions:
${_IMPORT_PREFIX}
there? I can't just use that on my CMakeLists.txt as it would evaluate to the empty string during generation, and I can't escape it like \${_IMPORT_PREFIX}
as it still places the escaped version in ParentTargets.cmake...Upvotes: 3
Views: 355
Reputation: 19916
Is this the right way of doing this? I could never find a good reference on how to package dependency static libraries alongside your project, and CMake doesn't seem to do this "on its own" too eagerly (I even had to manually copy the .lib there as you can see);
I think what you're doing is fine. If it were me, I would create and link to an IMPORTED STATIC
target named Parent::ThirdParty::dependency
for dependency.lib
in both the main build and in the package config file, and set its IMPORTED_LOCATION
property appropriately in each.
The reason being that CMake will validate that anything you link to that contains a ::
in its name is a CMake target. This tends to lead to fewer surprises on the link line and lets you attach things like include paths to the library.
How do I get CMake to use ${_IMPORT_PREFIX} there? [...]
Your issue is here:
$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/lib/dependency.lib>
CMAKE_INSTALL_PREFIX
is set to E:/absolute/path/Parent/dist/Parent
immediately and CMake has no chance to replace it with something like ${_IMPORT_PREFIX}
. Fortunately, there is a generator expression for this.
$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/lib/dependency.lib>
Try that instead.
Upvotes: 1