我有一个foo依赖于bar. bar安装后提供良好的效果barConfig.cmake。
cmake_minimum_required(VERSION 3.7)
project(foo VERSION 1.0)
find_package(bar)
add_library(foo SHARED foo.c)
target_link_libraries(foo PUBLIC bar)
install(TARGETS foo EXPORT fooTargets LIBRARY DESTINATION lib)
export(EXPORT fooTargets FILE fooTargets.cmake)
install(EXPORT fooTargets FILE fooTargets.cmake DESTINATION lib/cmake)
Run Code Online (Sandbox Code Playgroud)
这很好用。我们只需apt install bar-dev编译即可foo。
但由于这些包都是我们开发的并且是相关的,所以我的团队希望在同一个 IDE 会话中开发它们并同时编译它们。我想允许这样做,但我不想改变这样一个事实:这些已经作为单独的包部署并且可以独立构建。
if (DIRECTORY_EXISTS ../bar)
set(BAR_NO_INSTALL ON)
set(BAR_SKIP_TESTS ON)
add_subdirectory(../bar ${CMAKE_CURRENT_BINARY_DIR}/bar)
else()
find_package(bar)
endif()
Run Code Online (Sandbox Code Playgroud)
如果../bar/存在,则结果为:
CMake Error: install(EXPORT "fooTargets" ...) includes target "foo" which
requires target "bar" that is not in the export set.
Run Code Online (Sandbox Code Playgroud)
如何避免需要bar在foo包中导出?
我试图找出为什么find_package(bar)行得通,但add_subdirectory(bar)行不通。 barConfig.cmakeviabarTargets.cmake定义bar如下:
add_library(bar SHARED IMPORTED)
set_property(TARGET bar APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG)
set_target_properties(bar PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "../bar/include"
IMPORTED_LOCATION_NOCONFIG "build/libbar.so.1.0.13574"
IMPORTED_SONAME_NOCONFIG "libbar.so.1"
)
Run Code Online (Sandbox Code Playgroud)
我的猜测是在自动生成IMPORTED的. 我尝试添加设置属性(如下),但没有发现任何差异:barbarConfig.cmake
set_target_properties(bar PROPERTIES IMPORTED TRUE)
Run Code Online (Sandbox Code Playgroud)
fooConfig.cmake确实包括创建目标的以下内容bar(不是bar::bar)。
find_depdendency(bar)
Run Code Online (Sandbox Code Playgroud)
我尝试了以下别名,希望别名无法导出对我有帮助。但它仍然期望我导出bar。
add_library(barImported ALIAS bar)
target_link_libraries(foo PUBLIC barImported)
Run Code Online (Sandbox Code Playgroud)
我尝试仅链接构建接口,希望bar在安装时不需要导出。但这也没有效果。
target_link_libraries(foo PUBLIC $<BUILD_INTERFACE:bar>)
Run Code Online (Sandbox Code Playgroud)
这是我想出的解决方案。这适用于任意库foo(动态和静态版本加上测试),它也可以以与我导入相同的方式成为依赖项bar:
cmake_minimum_required(VERSION 3.7)
include(GNUInstallDirs)
project(foo VERSION 1.0)
# Options set to
# ON explicitly for build machines,
# OFF by default for developers who build dependencies inline and only build for local use
option(FOO_EXPORT_TARGETS "Generate fooConfig.cmake for packaging." OFF)
option(FOO_BUILD_TESTS "Build and run tests. Default off for aircraft. Turn on in your IDE if developing foo" OFF)
# This is best implemented as a macro/function from an included cmake
set(BAR_ROOT "/noexist" CACHE PATH "Location of BAR for in-source building")
if (DIRECTORY_EXISTS "${BAR_ROOT}")
add_subdirectory(${BAR_ROOT})
else()
find_package(bar)
endif()
set(fooSources foo.c)
set(fooPublicHeaders include/foo.h)
add_library(fooObjects OBJECT ${fooSources})
target_include_directories(fooObjects
PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
PRIVATE
$<TARGET_PROPERTY:bar,INTERFACE_INCLUDE_DIRECTORIES>
)
add_library(foo SHARED $<TARGET_OBJECTS:fooObjects>)
add_library(fooStatic STATIC $<TARGET_OBJECTS:fooObjects>)
target_link_libraries(foo PUBLIC fooObjects bar)
target_link_libraries(fooStatic PUBLIC fooObjects barStatic)
set_target_properties(fooObjects foo fooStatic
PROPERTIES
POSITION_INDEPENDENT_CODE ON
)
if (NOT FOO_EXPORT_TARGETS)
install(TARGETS foo LIBRARY DESTINATION lib)
else()
set_target_properties(foo fooStatic
PROPERTIES
VERSION ${foo_VERSION}
SOVERSION ${foo_VERSION_MAJOR}
PUBLIC_HEADER "${fooPublicHeaders}"
)
install(
TARGETS foo fooStatic fooObjects
EXPORT fooTargets
RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}/foo
)
include(CMakePackageConfigHelpers)
set(configDir "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/foo-${foo_VERSION_MAJOR}")
configure_package_config_file(
"${CMAKE_CURRENT_LIST_DIR}/fooConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/fooConfig.cmake"
INSTALL_DESTINATION ${configDir}
)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/fooConfigVersion.cmake"
VERSION ${foo_VERSION}
COMPATIBILITY SameMajorVersion
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/fooConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/fooConfigVersion.cmake"
DESTINATION ${configDir}
)
export (EXPORT fooTargets FILE fooTargets.cmake)
install(EXPORT fooTargets FILE fooTargets.cmake DESTINATION ${configDir})
endif()
if (FOO_BUILD_TESTS)
add_executable(test_foo test.c)
target_link_libraries(test_foo foo)
enable_testing()
add_test(NAME test_foo COMMAND test_foo WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
endif()
Run Code Online (Sandbox Code Playgroud)
具有以下内容fooConfig.cmake.in:
include(CMakeFindDependencyMacro)
@PACKAGE_INIT@
find_dependency(bar)
if(NOT TARGET foo)
include("${CMAKE_CURRENT_LIST_DIR}/fooTargets.cmake")
endif()
Run Code Online (Sandbox Code Playgroud)
构建机器由此创建一个 debian 包。这就是debian/rules文件的样子,以确保它是在没有任何源内构建、打包和测试的情况下进行编译的:
#!/usr/bin/make -f
#export DH_VERBOSE = 1
%:
dh $@
override_dh_auto_configure:
dh_auto_configure -- \
-DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) \
-DFOO_BUILD_TESTS=ON \
-DFOO_EXPORT_TARGETS=ON \
-DBAR_ROOT=/noexist
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2888 次 |
| 最近记录: |