CMake库打包以及支持find_package(一)

简介: CMake库打包以及支持find_package(一)

本文对CMake中库的打包,安装,导出以及支持find_package,使其能够很简单的应用到其他的项目中进行详细的总结。


CMake打包库


假设我们的库的结构如下:


- include/
  - my_library/
    - header-a.hpp
  - header-b.hpp
  - config.hpp
  - ...
- src/
  - source-a.cpp
  - source-b.cpp
  - config.hpp.in
  - ...
  - CMakeLists.txt
- example/
  - example-a.cpp
  - ...
  - CMakeLists.txt
- tool/
  - tool.cpp
  - CMakeLists.txt
- test/
  - test.cpp
  - CMakeLists.txt
- CMakeLists.txt
- ...


在这个库中包含了不同的头文件和源文件,还包含一些例子,工具和单元测试模块。对于库、示例和单元测试,每个模块分别拥有自己的CMakeLists.txt,在其中定义了编译的目标并且在子目录中包含了相关的代码。而项目的根目录的CMakeLists.txt则定义了配置选项,并将这些子模块的加入编译中去。

库的相关配置在config.hpp.in中被定义,然后这个文件会被CMake预处理为config_impl.hpp,然后被config.hpp包含到项目中去(#include "config_impl.hpp")。

这种方法非常重要,能够让我们对不同的CMake配置文件进行分离,比如一些不相干的配置的宏等等


项目根目录的CMakeLists.txt文件:


cmake_minimum_required(VERSION 3.0)
project(MY_LIBRARY)
# define library version (update: apparently you can also do it in project()!)
set(MY_LIBRARY_VERSION_MAJOR 1 CACHE STRING "major version" FORCE)
set(MY_LIBRARY_VERSION_MINOR 0 CACHE STRING "minor version" FORCE)
set(MY_LIBRARY_VERSION ${MY_LIBRARY_VERSION_MAJOR}.${MY_LIBRARY_VERSION_MINOR} CACHE STRING "version" FORCE)
# some options
option(MY_LIBRARY_USE_FANCY_NEW_CLASS "whether or not to use fancy new class" ON)
option(MY_LIBRARY_DEBUG_MODE "whether or not debug mode is activated" OFF)
# add subdiretories
add_subdirectory(src)
add_subdirectory(example)
add_subdirectory(tool)
add_subdirectory(test)


这个文件中有一些option操作,这些配置选项能够讲相关配置写入到config.hpp.in中,我们需要在config.hpp.in定义这些选项,类似这种形式:#cmakedefine01

注意,库的版本号我们使用了force,这个就阻止了用户在CMakeCache.txt中更改这个版本号

库模块的src/CMakeLists.txt文件:


# set headers
set(header_path "${MY_LIBRARY_SOURCE_DIR}/include/my_library")
set(header ${header_path}/header-a.hpp
       ${header_path}/header-b.hpp
       ${header_path}/config.hpp
       ...)
# set source files
set(src source-a.cpp
    source-b.cpp
    ...)
# configure config.hpp.in
configure_file("config.hpp.in" "${CMAKE_CURRENT_BINARY_DIR}/config_impl.hpp")
# define library target
add_library(my_library ${header} ${src})
target_include_directories(my_library PUBLIC ${MY_LIBRARY_SOURCE_DIR}/include


首先,我们定义了头文件和源文件的列表,方便后续使用。

注意头文件的路径变量header_path,这个变量在不同的CMake子文件中是不同的,而源文件因为在同一目录中,则可以直接定义。

这个CMake文件同样能够生成config_impl.hpp,并保存在当前定义的库生成的二进制目录中(${CMAKE_CURRENT_BINARY_DIR}),然后被包含在config.hpp中,最终在库被使用能够被找到。

target_include_directories指定了这个库要用到的头文件,PUBLIC制定的包含目录包括了include/的子目录和当前CMake的二进制目录(为了包含config_impl.hpp)。

其余模块的的CMakeLists.txt类似

到这一步,其余的用户就能够通过add_subdirtectory()来添加库的目录,然后调用target_link_libraries(my_target PUBLIC my_library)来链接库,并且需要设置include_directories来包含相关的头文件,从而能够调用我们的库。


CMake安装库


我们需要安装的东西包括:头文件,可执行的工具以及已经编译好的库。这些都能够直接使用install()命令来直接安装。当我们使用cmake install(make install)这类命令时,会拷贝这些文件到${CMAKE_INSTALL_PREFIX}中(Linux下默认是/usr/local)。

首先,我们在项目的CMakeLists.txt定义相关的位置和变量:

set(tool_dest "bin")

set(include_dest "include/my_library-"${MY_LIBRARY_VERSION}")

set(main_lib_dest "lib/my_library-"${MY_LIBRARY_VERSION}")

然后我们配置install()命令:


# in tool/CMakeLists.txt  
install(TARGETS my_library_tool DESTINATION "${tool_dest}")  
# in src/CMakeLists.txt  
install(TARGETS my_library DESTINATION "${main_lib_dest}")  
install(FILES ${header} DESTINATION "${include_dest}")  
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/config_impl.hpp DESTINATION "${include_dest}")


这会将可执行工具安装到${CMAKE_INSTALL_PREFIX}/bin上,头文件安装到${CMAKE_INSTALL_PREFIX}/include/my_library-1.0,库安装到${CMAKE_INSTALL_PREFIX}/lib/my_library-1.0。现在就已经满足了我们的一个目标了:不同版本的库不会产生冲突,因为版本号成为了安装路径的一部分。

对于工具tool,我们假设其能够具有很好的兼容性,并且将其直接放到bin/文件夹中,这样其能够直接在终端运行,如果你有需求,你应该对这部分做一些自定义的调整。

但是目前仍然没有解决一个问题:每个编译出来的库可以拥有不同的配置。因为现在只有一个配置文件。我们当然也能通过配置不同的识别名称来区别不同的配置,就像利用不同的版本号一样,但是这对于大多数文件是不需要,因此我们不必采用这种方案。

再次忽略掉tool,那么就只剩下两个文件需要依赖不同的配置:编译得到的库和生成的config_impl.hpp文件。因为其中包含了对于库的一些宏的操作,因此我们需要根据配置的不同,将这两个文件放在不同的位置。

但是我们怎么去区分呢?

可以使用编译类型${CMAKE_BUILD_TYPE}这个变量。通过指示DebugReleaseMinSizeRel以及RelWithDebInfo,来指示不同的配置选项。

我们也可以定义自己的编译类型以及相对应的一些编译选项操作。

现在我们可以在项目的根CmakeLists.txt中添加一个新的变量了lib_dest

set(lib_dest ${main_lib_dest}/${CMAKE_BUILD_TYPE}")

并且需要更改config_impl.hpp和库目标的路径,将其安装到lib_dest中,这样对于不同的编译类型(也就是不同的配置),我们就会得到不同的config_impl.hpp和库文件。

现在,经过这些配置,我们已经能够区别不同版本和不同配置的库,将其安装到不同的目标路径中,比如${CMAKE_INSTALL_PREFIX}/lib/my_library-1.0/Debug

目录
相关文章
|
7月前
|
存储 Linux Python
Python分享之路径与文件 (os.path包, glob包)
Python分享之路径与文件 (os.path包, glob包)
|
Oracle 关系型数据库 Go
【开发工具】解决 Goland 报错:Found several packages [main, xxx] in ...
【开发工具】解决 Goland 报错:Found several packages [main, xxx] in ...
1201 0
【开发工具】解决 Goland 报错:Found several packages [main, xxx] in ...
|
27天前
|
JavaScript 开发者 资源调度
Spartacus 2211 开发版本采用 npm install 结合 package-lock.json 避免 build 出错
Spartacus 2211 开发版本采用 npm install 结合 package-lock.json 避免 build 出错
9 0
Spartacus 2211 开发版本采用 npm install 结合 package-lock.json 避免 build 出错
|
2月前
|
测试技术 编译器 持续交付
【Conan 入门教程 】深入理解Conan中的测试包:test_package目录的精髓
【Conan 入门教程 】深入理解Conan中的测试包:test_package目录的精髓
68 0
|
4月前
|
C++ Windows
CMake中的find_package(xxx REQUIRED)在windows平台怎么解
CMake中的find_package(xxx REQUIRED)在windows平台怎么解
|
11月前
|
存储 Linux 计算机视觉
CMake库打包以及支持find_package(二)
CMake库打包以及支持find_package(二)
188 0
|
11月前
|
机器人 Linux 编译器
替代notepad++,notepad--介绍及插件cmake编译
替代notepad++,notepad--介绍及插件cmake编译
|
Linux Shell
pkg-config 自动补全 C 编译库依赖
pkg-config 是一个在源代码编译时查询已安装的库的使用接口的计算机工具软件。
79 0
ROS学习-编译Package包
ROS学习-编译Package包
87 0
|
前端开发 JavaScript 程序员
CommonJs自定义模块的使用/npm 包 第三方模块/package.json版本信息
CommonJs自定义模块的使用/npm 包 第三方模块/package.json版本信息
99 0
CommonJs自定义模块的使用/npm 包 第三方模块/package.json版本信息

热门文章

最新文章