我有projectA,我正在导入一个库:
add_library(foo STATIC IMPORTED)
set_property(TARGET foo PROPERTY IMPORTED_LOCATION /path/to/foo.a)
然后我在项目的几个地方使用foo
,一切正常。
我希望导出一个在此项目中构建的库,以便在另一个具有完全断开连接的CMake配置的项目中使用。我有:
...
target_link_libraries(thislib foo)
export(TARGETS thislib FILE /path/to/thislib.cmake)
导入projectB也需要foo(因为导入的库需要它),并且抱怨它cannot find -lfoo
。我尝试将其添加到export
命令,但后来我得到了:
CMake Error at thislib/CMakeLists.txt:37 (export):
export given target "foo" which is not built by this project.
我只想将我在本地使用的相同配置导出到另一个(导入)项目。我不想明确地告诉projectB关于foo
。有没有办法实现这个目标?
答案 0 :(得分:2)
我没有找到问题的实际解决方案,但我发布了自己的解决方法以供将来参考。
我意识到导出中会发出foo
依赖 。它只是没有路径。由于我还没有弄清楚如何让cmake随之导出路径,因此我将export
命令恢复为上述问题中显示的命令(没有foo
)。
然后我回到导入foo
的原始位置,移除了add_library
和set_property
,将其替换为:
set(foo /path/to/foo.a)
然后将target_link_libraries
更改为:
target_link_libraries(thislib ${foo})
换句话说,它不仅仅是一个真正的导入库,而是一个原始的库路径。这确实被正确写入导出文件并允许projectB链接。
答案 1 :(得分:0)
你需要
foo
)foolibs.cmake
而不是直接使用/path/to/thislib.cmake
(由export(TARGETS thislib...
生成的导出文件创建另一个,thislib-and-deps.cmake
包括:{/ p>
include(<...>/foolibs.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/thislib.cmake)
答案 2 :(得分:0)
我也找不到理想的方法来做到这一点。但这是我现在使用的解决方法。这是额外的工作,而不是干,但我认为它实现了正确的事情。
想象一下,lib B
取决于第三方库A
。 A
要么定义了查找模块,要么我们可以为它实现自定义查找模块。两者都可行。假设我们已经写了FindA.cmake
并存储在${CMAKE_SOURCE_DIR}/cmake
中。另外,假设您运行cmake生成B
的构建系统时,提供A_ROOT
来帮助cmake找到A
。
然后在B的顶级CMakeLists.txt
我们需要:
# Use FindA.cmake, defined in the cmake/ directory.
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
find_package(A REQUIRED)
# ... (define the B target here)...
# Copy the config file to the build dir
configure_file(cmake/BConfig.cmake cmake/BConfig.cmake @ONLY)
# Copy A's find module (skip this step if FindA is not custom).
configure_file(cmake/FindA.cmake cmake/FindA.cmake COPYONLY)
# Create the target export.
export(EXPORT BTargets
FILE ${CMAKE_BINARY_DIR}/cmake/BTargets.cmake
NAMESPACE B::
)
# Register B so cmake can find B's config file.
export(PACKAGE B)
现在在cmake/BConfig.cmake
:
# Get the exported find module onto the module path.
# This step is unnecessary if the find module is part of cmake.
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
# Store the root so that find_package will work.
# You may have to store other variables here, too, but
# the principle is just more of the same.
set(A_ROOT @A_ROOT@) # **Could optionally cache this.
find_package(A MODULE REQUIRED)
# The usual one-liner for a config file.
include("${CMAKE_CURRENT_LIST_DIR}/BTargets.cmake")
为了将解决方案带回家,让我们看一下第二个例子,Rocket
这次使用Boost
,它已经定义了一个查找模块。
CMakeLists.txt
:
option(Boost_USE_MULTITHREADED ON)
option(Boost_USE_STATIC_LIBS OFF)
find_package(Boost REQUIRED COMPONENTS filesystem program_options)
add_library(Rocket rocket.cpp)
target_link_libraries(Rocket
PUBLIC Boost::filesystem
PRIVATE Boost::program_options
)
configure_file(cmake/BConfig.cmake cmake/BConfig.cmake @ONLY)
export(EXPORT RocketTargets
FILE ${CMAKE_BINARY_DIR}/RocketTargets.cmake
NAMESPACE Rocket::
)
export(PACKAGE Rocket)
然后cmake/RocketConfig.cmake
会:
set(BOOST_ROOT @BOOST_ROOT@ CACHE PATH "In case boost was relocated.")
set(Boost_USE_MULTITHREADED @Boost_USE_MULTITHREADED@)
set(Boost_USE_STATIC LIBS @Boost_USE_STATIC_LIBS@)
find_package(Boost REQUIRED COMPONENTS filesystem program_options)
include("${CMAKE_CURRENT_LIST_DIR}/RocketTargets.cmake")
所以是的。打字似乎太多了。似乎cmake应该能够从export
中的CMakeLists.txt
语句生成所有代码。但这种策略似乎达到了目标。
另外,我还没有测试过,但我怀疑,如果你的传递依赖使用CONFIG
而不是MODULE
find_package
,那么它应该很容易也可以在配置文件中添加CMAKE_PREFIX_PATH
。