前言: 自己在使用cmake进行编译工程的时候不太了解cmake的基本使用方法,有时候出现找不到第三方库的问题也不知如何排查,因此相对cmake有个稍微系统的认识,希望能用这个强大的工具来更好的为自己的工程服务,因此总结为了几篇博客,主要参考的是官网的Tutorial,加入了自己的认识,另外,其实cmake本质上是一个工具,工具的作用就是用来帮助我们更好的构建项目的,所以对于工具能够满足使用要求就好,不必细枝末节的完全掌握,如有错误请斧正.
测试cmake版本:3.20.4
测试平台:ubuntu16.04
Tutorial源代码:https://github.com/FreddyName/cmake_tutorialshttps://github.com/FreddyName/cmake_tutorials
系列博客目录:
cmake学习1: 基本的CMakeLists.txt的编写https://blog.csdn.net/Heart_M/article/details/120626697
cmake学习2: 如何将源代码编译成库并使用https://blog.csdn.net/Heart_M/article/details/120632708
cmake学习3: 如何安装自己的工程在本地https://blog.csdn.net/Heart_M/article/details/120640741
cmake学习4: 如何将自己的工程打包给别人https://blog.csdn.net/Heart_M/article/details/120641933
cmake学习5: 如何将自己的库作为第三方库给别人使用https://blog.csdn.net/Heart_M/article/details/120643023
下面考虑这样一种情况:当我们在编写自己的代码的时候,我们可能需要在其他文件里实现一般的功能,比如说对一个数开平方(MathFunctions/mysqrt.cxx),然后在main函数里调用,因为mysqrt.cxx具有一般性,因此想要把他编译成库以便其他的工程也能使用,这是很常见的,我们的文件组织形式如下:
单独一个MathFunctions文件夹将,里面的mysqrt.cxx是对sqrt函数的自己实现,里面的CMakeLists.txt文件负责将其编译成库.
我们整体的思路应该是这样的:
- 在二级目录下的CMakeLists.txt中将mysqrt.cxx编译成库
- 在一级目录下的CMakeLists.txt设置选择是否使用自己的库
- 在源文件中根据选择项进行编程
在二级目录下的CMakeLists.txt中将mysqrt.cxx编译成库
这个的实现只需要在MathFunctions/CMakeLists.txt中增加下面一行:
add_library(MathFunctions mysqrt.cxx)
此行命令将mysqrt.cxx编译成名字为MathFunctions 的库,但是需要注意的是我们不需要单独对MathFunctions/CMakeLists.txt进行cmake操作,而是在顶层CMakeLists.txt中对其进行包含构建.
add_library的使用: 这个命令的作用是将源代码文件编译成库方便供其他人使用,一般来说我们可以选择编译成动态库(Linux下以lib<库名>.so命名)和静态库(Linux下以lib<库名>.a命名),可以通过参数指定(不加参数默认编译为静态库):
add_library(MathFunctions SHARED mysqrt.cxx) #编译成libMathFunctions.so动态库
add_library(MathFunctions STATIC mysqrt.cxx) #编译成libMathFunctions.a静态库
在一级目录下的CMakeLists.txt设置选择是否使用自己的库
在实际的编写CMakeLists.txt文件的时候,有时候我们可以设置变量来控制程序的编译,下面就是通过设置USE_MYMATH来控制程序是不是使用自己的sqrt函数(这里就用到了上一节中将cmake中的变量传递到其他文件的方法)
option(USE_MYMATH "Use tutorial provided math implementation" ON)
configure_file(TutorialConfig.h.in TutorialConfig.h)
if(USE_MYMATH)
add_subdirectory(MathFunctions)
list(APPEND EXTRA_LIBS MathFunctions)
list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
endif()
add_executable(Tutorial tutorial.cxx)
target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
${EXTRA_INCLUDES}
)
- add_subdirectory的目的是包含MathFunctions文件夹,这样的顶层执行cmake构建的时候也能执行MathFunctions里面的CMakeLists文件(下层cmake操作得到的TARGETS可以被顶层cmake所使用)
- option的目的是定义一个USE_MYMATH变量当做是否使用MathFunctions库的开关,这样就可以在CMakeLists和源代码里面根据开关执行不同的操作.
- configure_file其实就是将cmake里面的变量传到源代码里,在上一篇中有介绍
- list这一行:list理解为一个列表,可以对其进行不同的操作,APPEND是增加命令, EXTRA_LIBS 和 EXTRA_INCLUDES是列表,也就是说将MathFunctions加入到EXTRA_LIBS列表,将$那个路径加入到EXTRA_INCLUDES里面
- target_link_libraries和target_include_directories分别是为Tutorial链接到所需要的库和找到所需要的头文件
在源文件中根据选择项进行编程
这里就涉及到如何将cmake里面的USE_MYMATH变量传递到源代码里,这就用到configure_file命令了,它能将TutorialConfig.h.in文件中的变量根据cmake中的赋值将其转为对应的值并写入TutorialConfig.h文件中,然后在源码中包含TutorialConfig.h这个文件就能使用cmake中的变量了
TutorialConfig.h.in
#cmakedefine USE_MYMATH
tutorial.cxx
#ifdef USE_MYMATH #include "MathFunctions.h" #endif ... #ifdef USE_MYMATH const double outputValue = mysqrt(inputValue); #else const double outputValue = sqrt(inputValue); #endif ...
测试:
在Step2同级目录下执行
mkdir build_Step2 cd build_Step2 cmake ../Step2 cmake --build .
然后在build_Step2目录下生成Tutorial 可执行文件和TutorialConfig.h文件:
当option设置为ON的时候,生成的TutorialConfig.h文件中有关USE_MYMATH变量的语句为#define USE_MYMATH
当option设置为OFF的时候,生成的TutorialConfig.h文件中有关USE_MYMATH变量的语句为
另一种对MathFunctions库的使用方法
上面我们对MathFunctions库的使用方法是: 如果构建的target需要链接MathFunctions库,那么需要指定MathFunctions库而且还需要include MathFunctions的路径 ,其实我们在add_library来构建MathFunctions库的时候发现,所有需要链接此库的target都需要include此库构建的路径(target_include_directories),而此库构建自身的时候却不需要,这种属性叫做INTERFACE,也就是他的消费者需要include此路径,而其本身不需要,那么我们也可以这样控制:
在MathFunctions/CMakeLists.txt中增加
target_include_directories(MathFunctions
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
)
然后在CMakeLists.txt中删除和包含此路径相关的操作:
也能达到相同的效果!



