前一章介绍了 cmake 的基本语法 以及如何构建一个最简单的工程。这里接着聊一聊使用 cmake 构建工程的常用操作:添加库
一、由源代码添加库
这一节中我们将向工程中添加一个库项目。
假设我们需要开发一个 mathlib 库, 并在其他项目中调用,可以像下面这样操作:
在工程路径下建立子文件夹 mathlib
在 ./mathlib 中添加项目源文件 mymath.h , mymath.cxx,并添加 CMakeLists.txt:
mymath.h :
1 2 3 4 5 6 7 8 9 #ifdef WIN32 #define MATH_API __declspec(dllexport) #else #define MATH_API #endif namespace MyMath{ MATH_API int add (int , int ) ; }
mymath.cxx:
1 2 3 4 5 #include "mymath.h" int MyMath::add (int a, int b) { return a+b; }
CMakeLists.txt:
1 add_library (mathlib mymath.cxx mymath.h)
在主工程中添加代码:
src.cxx:
1 2 3 4 5 6 7 #include <iostream> #include "mymath.h" int main () { std::cout<<MyMath::add (4 ,2 )<<std::endl; return 0 ; }
CMakeLists.txt:
1 2 3 4 5 6 7 cmake_minimum_required (VERSION 3.0 )add_subdirectory (mathlib)include_directories (mathlib)add_executable (proj src.cxx)target_link_libraries (proj mathlib)
二、由二进制文件添加库
很多时候我们没有库的源码,或者不想源码引入工程中重复编译。此时我们将添加二进制的库。
添加二进制库的一般操作为:
使用 link_directories 设置库的路径
add_executable 生成文件
target_link_libraries 链接库
如下:
CMakeLists.txt:
1 2 3 4 5 6 7 cmake_minimum_required (VERSION 3.0 )include_directories (./include )link_directories (${CMAKE_BINARY_DIR} /lib)add_executable (proj src.cpp)target_link_libraries (proj mathlib)
src.cpp:
1 2 3 4 5 6 7 #include <iostream> #include "mymath/mymath.h" int main () { std::cout<<MyMath::add (2 ,4 )<<std::endl; return 0 ; }
其中库文件 mathlib.lib 放在 build/lib 路径下。另外要注意这几个命令的顺序。
三、使用 find_package 添加库(包)
在使用以上两种方法时,我们需要知道库的源文件(或头文件) / 库文件(a/lib/so/dylib) 的位置,然后通过 include_directories link_directories 等命令引入工程。如果事先不知道这些信息,也可以使用 find_package 命令来添加预定义在 CMAKE_MODULE_PATH 的或内置的 Find.cmake 模块。
1 2 3 4 find_package (<PackageName> [version] [EXACT] [QUIET] [MODULE] [REQUIRED] [[COMPONENTS] [components...]] [OPTIONAL_COMPONENTS components...] [NO_POLICY_SCOPE])
version 兼容版本号。格式应该是 major[.minor[.patch[.tweak]]]
EXACT 可选,要求精确版本号
QUIET 可选 , 当没有发现库时不发生警告信息
REQUIRED 可选, 指明该库是必须的,若没发现库则会终止 cmake
COMPONENTS 可选,指明该包需要的组件
cmake 内置了很多常用的包的 cmake 模块,可以直接调用,它们在 cmake 安装目录下的 share/cmake-3.13/Modules 下。例如当我们需要引入 boost 时的工程:
CMakeLists.txt:
1 2 3 4 5 6 7 8 9 10 11 12 cmake_minimum_required (VERSION 3.0 )set (BOOST_ROOT D:/code/opensource/boost/boost_1_68_0) set (BOOST_LIBRARYDIR D:/code/opensource/boost/boost_1_68_0/stage/lib) find_package (Boost 1.60 REQUIRED)IF (Boost_FOUND) include_directories (${Boost_INCLUDE_DIR} ) link_directories (${Boost_LIBRARY_DIR} ) ENDIF ()add_executable (test src.cxx)
src.cxx:
1 2 3 4 5 6 #include <iostream> #include <boost/asio/io_service.hpp> int main () { boost::asio::io_service ios; return 0 ; }
find_package 工作原理
find_package( ) 先在 ${CMAKE_MODULE_PATH} 路径下,然后在 <CMake_Install_dir>/share/cmake-3.13/Modules 下查找 Find<Nmae>.cmake 。如果没有找到,则会寻找 <Name>Config.cmake 或 <lower-case-name>-config.cmake。前一种称为 模块模式 ,后一种称为 配置模式 。cmake 默认优先使用模块模式,如果找不到模块,则使用配置模式,通常安装库时会拷贝一份 Config.cmake 到系统目录中,因此没有指定搜索路径时也有可能顺利找到包。 不管哪种模式,只要找到包就会定义下面这些变量:
1 2 3 4 <NAME>_FOUND <NAME>_INCLUDE_DIRS or <NAME>_INCLUDES <NAME>_LIBRARIES or <NAME>_LIBRARIES or <NAME>_LIBS <NAME>_DEFINITIONS
如果 <NAME>_FOUND 被定义,说明包已经找到了。那么可以使用 include_directories() 引入 <NAME>_INCLUDE_DIRS 头文件 ,使用 link_directories() 和 target_link_libraries() 来引入库文件。
自定义包
这里以前面的 mathlib 为例,看一下如何自定义一个 cmake 包。
mathlib的 CMakeLists.txt 定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 cmake_minimum_required (VERSION 3.0 )add_library (mathlib mymath.cxx mymath.h)SET (CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR} /install ) target_include_directories (mathlib PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR} > $<INSTALL_INTERFACE:include >) set_target_properties (mathlib PROPERTIES PUBLIC_HEADER "mymath.h" ) install (TARGETS mathlib EXPORT mathlib-targets PUBLIC_HEADER DESTINATION include /mathlib ARCHIVE DESTINATION lib LIBRARY DESTINATION lib RUNTIME DESTINATION bin) install (EXPORT mathlib-targets FILE mathlib-config.cmake DESTINATION lib/cmake/mathlib)
完成编译后,以上工程会在源文件目录下生成:
install/include/mymath 包含了头文件 mymath.h
install/lib 包含生成的库文件 mathlib.lib
install/lib/cmake/mathlib 包含了两个 cmake 文件 : mathlib-config.cmake , mathlib-config-debug.cmake
使用上面的包:
src.cpp:
1 2 3 4 5 6 #include <iostream> #include <mathlib/mymath.h> int main () { std::cout<<MyMath::add (2 ,4 )<<std::endl; return 0 ; }
CMakeLists.txt
1 2 3 4 5 6 7 8 9 10 11 12 13 cmake_minimum_required (VERSION 3.0 )set (mathlib_DIR "...xxx.../mathlib/install/lib/cmake/mathlib" )find_package (mathlib REQUIRED)IF (mathlib_FOUND) message ("mathlib founded" ) include_directories (${mathlib_INCLUDES} ) link_directories (${mathlib_LIBRARIES} ) ENDIF ()add_executable (proj src.cpp)target_link_libraries (proj mathlib)