CMake:生成或提取共享库所需的标头

CMake: generate or extract header necessary for shared lib

本文关键字:共享 提取 CMake      更新时间:2023-10-16

我目前正在做一个更大的项目,但没有得到维护。

解释它尝试使用CMake,但不是很直观。无需包含来自每个子模块的共享库和标头,而是可以在顶级 CMakeList 中设置一个标志,以触发add_subdirectory,潜入顶级CMAKE_BUILD_DIR并安装到其中。这些 CMakeList 专门使用 glob RECUUSE 来查找所有源,并且大多数操作不是基于目标的,而是全局的。因此,主目标可以正确编译。这是主要CMakeList的一小部分

set(MY_BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(MY_SOURCE_BASE_DIR "${MY_BASE_DIR}/myproject")
# includes
include(build/global.cmake)
#include(externalLibs/mz-cmaketools-master/global.cmake)

# configuration options
option(MOD1 "" ON)
option(MOD2 "" ON)
option(MOD3 "" OFF)
option(MOD4 "" OFF)
option(MOD5 "" ON)
option(MOD6 "" OFF)
option(MOD7 "" ON)
message("-- Building myproject unit-tests - ${ENABLE_MYPROJECT_TEST}")
set(CMAKE_ECLIPSE_MAKE_ARGUMENTS "-j4")
if(MOD1)
message(STATUS "Building viral_core + viral_recon")
add_subdirectory(${MY_BASE_DIR}/externalLibs/viral/trunk/linux)

include_directories(${MY_BASE_DIR}/externalLibs/viral/trunk/source/)
else(MOD1)
if(MOD3)
message(WARNING "Building viral_core + viral_recon")
add_subdirectory(${MY_BASE_DIR}/externalLibs/viral/trunk/linux)
include_directories(${MY_BASE_DIR}/externalLibs/viral/trunk/source/)
endif(MOD3)
endif(MOD1)
# external libraries
include(${MY_BASE_DIR}/externalLibs.cmake)

include_directories(
${MY_BASE_DIR}
${MY_SOURCE_BASE_DIR}
${MY_BASE_DIR}/externalLibs/viral/trunk/source/
)

# depending on the supported robots we have different dependencies
if( MOD1 ) 
set(OPT1 TRUE)
endif()
...
# collect binaries
set(LIBRARY_OUTPUT_PATH ${MY_BASE_DIR} CACHE PATH "Library output path")
set(EXECUTABLE_OUTPUT_PATH ${MY_BASE_DIR} CACHE PATH "Executable output path")
message("-- Setting executable output path: ${EXECUTABLE_OUTPUT_PATH}")
message("-- Setting library output path   : ${LIBRARY_OUTPUT_PATH}")

# collect sources
file(GLOB MY 
"${MY_SOURCE_BASE_DIR}/*.h"
"${MY_SOURCE_BASE_DIR}/*.cpp"
)
source_group(base FILES ${MY_BASE})#
file(GLOB MY_UTIL 
"${MY_SOURCE_BASE_DIR}/util/*.h"
"${MY_SOURCE_BASE_DIR}/util/*.cpp"
)
source_group(util FILES ${MY_UTIL})
file(GLOB_RECURSE MY_KINEMATICS 
"${MY_SOURCE_BASE_DIR}/kinematics/*.h"
"${MY_SOURCE_BASE_DIR}/kinematics/*.cpp"
) 
source_group(kinematics FILES ${MY_KINEMATICS})
file(GLOB MY_COLLISION
"${MY_SOURCE_BASE_DIR}/collision/pqp/*.cpp"
"${MY_SOURCE_BASE_DIR}/collision/PQP*.cpp"
)
source_group(collision FILES ${MY_COLLISION})
...
add_library(MY SHARED
${MY_COLLISION}
${MY_UTIL}
${MY_KINEMATICS}
...}
)
....

最后,项目构建了几个库,但不发布使用它们所需的标头。这些库被放入构建目录的顶层。(无安装步骤(

问题

是否有可能使CMake导出库(目标(的包含标头。更准确地说,这些标头应仅位于源文件夹内及以下;来自/usr/...不应考虑。此外,如果将标头合并为一个标头,这是可以接受的。但是从 ~1700 个标头中,只有 ~40 个是相关的,所以一个简单的查找 RECURSE 对我来说似乎是不够的。

我确实看过GENERATE_EXPORT_HEADER但不要认为这就是我想要的。而且我没有更改项目的权限,所以我想对 SVN 存储库进行修补,并且不想制作存储库的另一个副本,因为大约有 10 个不同的副本在使用中。

我将不胜感激有关解决方案或策略的任何提示

这是我关于堆栈溢出的第一个问题,所以请怜悯:)

我希望我正确理解了你的问题。

我通常使用 CMakePackageConfigHelpers 为 lib 生成 cmake 配置文件,如果操作正确,好处是 CMake 会在您链接到具有包配置的库时自动设置传递依赖项并包含目录。

然后,可以使用install命令将目标、目录、包含文件复制到CMAKE_INSTALL_PREFIX目录中,或通过 CPack 复制到存档中。

在宣布我的目标之后,我通常会有类似的东西:

install(TARGETS MyLibrary
LIBRARY DESTINATION lib
)
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${GENERATED_DIR}/MyLibraryConfigVersion.cmake" COMPATIBILITY SameMajorVersion
)
configure_package_config_file(
"cmake/Config.cmake.in" 
"${GENERATED_DIR}/MyLibraryConfig.cmake"
INSTALL_DESTINATION "cmake"
)
install(FILES 
inc/someHeader.h
inc/someHeaderB.h
DESTINATION include/MyLibrary
)
install(FILES 
"${GENERATED_DIR}/MyLibraryConfig.cmake" 
"${GENERATED_DIR}/MyLibraryConfigVersion.cmake" 
DESTINATION "cmake"
)

然后,您可以将CMAKE_INSTALL_PREFIX设置为您选择的目录并运行make install,创建以下结构:

InstallationDir
├── cmake
│   ├── MyLibraryConfig.cmake
│   └── MyLibraryConfigVersion.cmake
├── include
│   └── MyLibrary
│       ├── someHeaderB.h
│       └── someHeader.h
└── lib
└── MyLibrary.so

然后,您可以在CONFIG模式下使用find_package在链接 MyLibrary.so 时自动设置包含目录、编译选项等。

只是一个提示:target_include_directories函数优于include_directories。如果您不使用它,我不确定配置文件生成的效果如何。另请查看以下功能,以便对目标进行更高级的控制:set_target_propertiestarget_link_librariestarget_compile_definitions