跨平台工程构建:CMake 的使用(三) 引入库
目录
前一章介绍了 cmake 的基本语法 以及如何构建一个最简单的工程。这里接着聊一聊使用 cmake 构建工程的常用操作:添加库
一、由源代码添加库
这一节中我们将向工程中添加一个库项目。
假设我们需要开发一个 mathlib
库, 并在其他项目中调用,可以像下面这样操作:
1. 在工程路径下建立子文件夹 mathlib
2. 在 ./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) |
3. 在主工程中添加代码:
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
可选, 指明该库是必须的,若没发现库则会终止 cmakeCOMPONENTS
可选,指明该包需要的组件
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) #where you boost source dir set(BOOST_LIBRARYDIR D:/code/opensource/boost/boost_1_68_0/stage/lib) # where you boost lib dir 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) #安装 cmake 文件 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) |