如何为 "boost-like" 多组件库编写 cmake 模块?
How to write cmake modules for "boost-like" multi-component library?
我目前正在编写一个 c++ 库,它有几个 "sub libraries",例如 boost 库。
让我们将库命名为 "TestLib" 并将子库命名为 "Base" 和 "Ext",其中 Base 包含基本内容,不依赖于任何其他子库。然而,Ext 依赖于 Base 的一些 类。
每个 "sub library" 都应该编译成一个单独的 .a 或 .so 文件,但它们都应该共享一个命名空间 (TestLib)。
现在我的目标是编写干净的 cmake 脚本以实现这个目标。
最后我希望能够在 cmake 中做这样的事情:
find_package(TestLib 0.1 REQUIRED COMPONENTS Base Ext)
或
target_link_libraries(someapplication
PUBLIC
TestLib::Base
)
我已将每个 "sub library" 放在单独的 git 存储库中,并将它们作为子模块添加到只有 CMakeLists.txt 的新存储库中
只是在每个回购协议上调用 add_subdirectory。
我实现的大部分 cmake 东西都是从这个很棒的教程中获得的
https://pabloariasal.github.io/
并且 Base 部分按预期工作(这并不奇怪,因为它不依赖于任何其他东西)。
但我的问题来自 Ext 部分。为了编译它,我必须 link 针对 Base 库,这应该不难,并且通过一些试验和错误,我相信我会让它工作。
但我想以正确的方式去做。
我的方法是
find_package(TestLib COMPONENTS Base)
在 TestLib.Ext 的 CMakeLists.txt 中。
但是找不到,因为它没有 TestLibConfig.cmake.
有道理,但我不知道在这个文件里放什么。
我试图提供一些代码来准确描述我的问题,但由于这对 post 来说太多了,我为此创建了一个 github:
https://github.com/PowerSupplyTopologies/TestLib
这应该包含所有相关代码。
这对你们中的一些人来说可能微不足道,但我敢打赌会有更多的人可以从这种方法中受益。
提前感谢您的任何想法。
编辑:
Base CMakeLists.txt 中的库创建是:
set(TARGET_NAME testlibbase)
add_library(${TARGET_NAME}
src/ClassA.cpp
src/ClassB.cpp
)
#Add an alias so that library can be used inside the build tree, e.g. when testing
add_library(TestLib::${TARGET_NAME} ALIAS ${TARGET_NAME})
和
set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/TestLib)
install(TARGETS ${TARGET_NAME}
EXPORT ${TARGET_NAME}-targets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
#This is required so that the exported target has the name JSONUtils and not jsonutils
set_target_properties(${TARGET_NAME} PROPERTIES EXPORT_NAME Base)
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
#Export the targets to a script
install(EXPORT ${TARGET_NAME}-targets
FILE
TestLibBaseTargets.cmake
NAMESPACE
TestLib::
DESTINATION
${INSTALL_CONFIGDIR}
)
#Create a ConfigVersion.cmake file
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/TestLibBaseConfigVersion.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion
)
configure_package_config_file(${CMAKE_CURRENT_LIST_DIR}/cmake /TestLibBaseConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/TestLibBaseConfig.cmake
INSTALL_DESTINATION ${INSTALL_CONFIGDIR}
)
#Install the config, configversion and custom find modules
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/TestLibBaseConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/TestLibBaseConfigVersion.cmake
DESTINATION ${INSTALL_CONFIGDIR}
)
##############################################
## Exporting from the build tree
export(EXPORT ${TARGET_NAME}-targets FILE ${CMAKE_CURRENT_BINARY_DIR}/TestLibBaseTargets.cmake NAMESPACE TestLib::)
和分机:
set(TARGET_NAME testlibext)
add_library(${TARGET_NAME}
src/ClassC.cpp
)
#Add an alias so that library can be used inside the build tree, e.g. when testing
add_library(TestLib::${TARGET_NAME} ALIAS ${TARGET_NAME})
在您的元项目 TestLib 中,您可以创建一个 TestLibConfig.cmake 文件,如 CMake 文档中所述。
TestLibConfig.cmake
:
set(_supported_components Base Ext)
foreach(_comp ${Test_FIND_COMPONENTS})
if (NOT ";${_supported_components};" MATCHES _comp)
set(TestLib_FOUND False)
set(TestLib_NOT_FOUND_MESSAGE "Unsupported component: ${_comp}")
endif()
include("${CMAKE_CURRENT_LIST_DIR}/TestLib${_comp}Targets.cmake")
endforeach()
我目前正在编写一个 c++ 库,它有几个 "sub libraries",例如 boost 库。
让我们将库命名为 "TestLib" 并将子库命名为 "Base" 和 "Ext",其中 Base 包含基本内容,不依赖于任何其他子库。然而,Ext 依赖于 Base 的一些 类。
每个 "sub library" 都应该编译成一个单独的 .a 或 .so 文件,但它们都应该共享一个命名空间 (TestLib)。 现在我的目标是编写干净的 cmake 脚本以实现这个目标。
最后我希望能够在 cmake 中做这样的事情:
find_package(TestLib 0.1 REQUIRED COMPONENTS Base Ext)
或
target_link_libraries(someapplication
PUBLIC
TestLib::Base
)
我已将每个 "sub library" 放在单独的 git 存储库中,并将它们作为子模块添加到只有 CMakeLists.txt 的新存储库中 只是在每个回购协议上调用 add_subdirectory。
我实现的大部分 cmake 东西都是从这个很棒的教程中获得的 https://pabloariasal.github.io/
并且 Base 部分按预期工作(这并不奇怪,因为它不依赖于任何其他东西)。
但我的问题来自 Ext 部分。为了编译它,我必须 link 针对 Base 库,这应该不难,并且通过一些试验和错误,我相信我会让它工作。
但我想以正确的方式去做。
我的方法是
find_package(TestLib COMPONENTS Base)
在 TestLib.Ext 的 CMakeLists.txt 中。 但是找不到,因为它没有 TestLibConfig.cmake.
有道理,但我不知道在这个文件里放什么。
我试图提供一些代码来准确描述我的问题,但由于这对 post 来说太多了,我为此创建了一个 github:
https://github.com/PowerSupplyTopologies/TestLib
这应该包含所有相关代码。
这对你们中的一些人来说可能微不足道,但我敢打赌会有更多的人可以从这种方法中受益。
提前感谢您的任何想法。
编辑:
Base CMakeLists.txt 中的库创建是:
set(TARGET_NAME testlibbase)
add_library(${TARGET_NAME}
src/ClassA.cpp
src/ClassB.cpp
)
#Add an alias so that library can be used inside the build tree, e.g. when testing
add_library(TestLib::${TARGET_NAME} ALIAS ${TARGET_NAME})
和
set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/TestLib)
install(TARGETS ${TARGET_NAME}
EXPORT ${TARGET_NAME}-targets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
#This is required so that the exported target has the name JSONUtils and not jsonutils
set_target_properties(${TARGET_NAME} PROPERTIES EXPORT_NAME Base)
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
#Export the targets to a script
install(EXPORT ${TARGET_NAME}-targets
FILE
TestLibBaseTargets.cmake
NAMESPACE
TestLib::
DESTINATION
${INSTALL_CONFIGDIR}
)
#Create a ConfigVersion.cmake file
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/TestLibBaseConfigVersion.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion
)
configure_package_config_file(${CMAKE_CURRENT_LIST_DIR}/cmake /TestLibBaseConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/TestLibBaseConfig.cmake
INSTALL_DESTINATION ${INSTALL_CONFIGDIR}
)
#Install the config, configversion and custom find modules
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/TestLibBaseConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/TestLibBaseConfigVersion.cmake
DESTINATION ${INSTALL_CONFIGDIR}
)
##############################################
## Exporting from the build tree
export(EXPORT ${TARGET_NAME}-targets FILE ${CMAKE_CURRENT_BINARY_DIR}/TestLibBaseTargets.cmake NAMESPACE TestLib::)
和分机:
set(TARGET_NAME testlibext)
add_library(${TARGET_NAME}
src/ClassC.cpp
)
#Add an alias so that library can be used inside the build tree, e.g. when testing
add_library(TestLib::${TARGET_NAME} ALIAS ${TARGET_NAME})
在您的元项目 TestLib 中,您可以创建一个 TestLibConfig.cmake 文件,如 CMake 文档中所述。
TestLibConfig.cmake
:
set(_supported_components Base Ext)
foreach(_comp ${Test_FIND_COMPONENTS})
if (NOT ";${_supported_components};" MATCHES _comp)
set(TestLib_FOUND False)
set(TestLib_NOT_FOUND_MESSAGE "Unsupported component: ${_comp}")
endif()
include("${CMAKE_CURRENT_LIST_DIR}/TestLib${_comp}Targets.cmake")
endforeach()