分享一次学习cmake基础的过程。

Cmake的简单学习历程,用于记录与分享,共勉。

 

一、单个文件cmake编译

  1. 本次使用的是MacOS作为运行的平台,CMake是跨平台的,教程在Linux和Windows应该也是可以工用的。
  2. 打开终端,并且新建一个cmake_test文件夹用于保存测试的cmake例程。

mkdir cmake_test

cd cmake_test

  1. 进入cmake_test文件夹后,新建一个main.c的文件。

touch main.c

  1. 再新建CMakeLisrs.txt文件,我们主要编写的cmake的命令就是在这个文件里。

touch CMakeLists.txt

  1. 为了方便编辑代码,我们打开vscode编辑器,如果没有下载vscode可以自行安装,或者使用其他代码编辑器也可以。

code .

  1. 新建build文件夹用于保存cmake编译后产生的文件

mkdir build

  1. 现在当前文件夹中的文件总共有三个

  1. 接下来开始编写main.c文件打印hello world。

分享一次学习cmake基础的过程。_第1张图片

  1. 在CMakeLists.txt文件中输入以下命令

分享一次学习cmake基础的过程。_第2张图片

第一句的意思是要求cmake3.0版本以上,可以根据实际设定最低要求版本。

第二句是设置项目名称。

第三句是关键,意思是使用源代码main.c文件,最后生成可执行的elf文件为main。

  1. 文件都准备完成后,进入build文件夹,之所以新建build文件夹,是为了保存cmake编译生成的文件,与源代码分开,这样会更加清晰。

cd build

  1. 开始编译cmake。两个点表示上一级目录,cmake与..中间必须有一个空格,否则会出错。

cmake ..

分享一次学习cmake基础的过程。_第3张图片

  1. 可以看到cmake编译完成后,会在build(当前文件夹)生成make文件。

ls

  1. 输入make编译生成main文件,可以看到main文件的颜色和其他的颜色不同。

分享一次学习cmake基础的过程。_第4张图片

  1. 运行mian。可以看到输出了hello_world!。

./main

  1. 如果想清除make生成的文件,输入

make clean

 

二、同一目录下多个文件cmake编译

1.在cmke_test文件夹下新建fun1.c和fun1.h文件。

分享一次学习cmake基础的过程。_第5张图片

2.填入以下内容,函数fun1的功能是打印输入的数值。

分享一次学习cmake基础的过程。_第6张图片分享一次学习cmake基础的过程。_第7张图片

3.修改main.c文件,调用fun1来打印。

分享一次学习cmake基础的过程。_第8张图片

4修改CMakeLists.txt文件。

分享一次学习cmake基础的过程。_第9张图片

可以看到我们把fun1.c文件添加在main.c的后面,表示调用的源文件是main.c和fun1.c。

5.运行cmake编译成make文件,再运行make编译生成main文件,运行main查看输出结果。

分享一次学习cmake基础的过程。_第10张图片

可以看到调用fun1函数成功打印了test_fun1:10。

6.从以上的实验可以看出,如果在同一目录下有多个源文件,那么只要在add_executable里把所有源文件都添加进去就可以了。但是如果有很多个源文件,这样每个添加的方式很不合理,无法体现cmake的优越性,cmake提供了一个命令可以把指定目录下所有的源文件存储在一个变量中,这个命令就是 aux_source_directory(dir var)。

第一个参数dir是指定目录,第二个参数var是用于存放源文件列表的变量。

7.新建fun2.c和fun2.h文件,内容如下:

分享一次学习cmake基础的过程。_第11张图片

分享一次学习cmake基础的过程。_第12张图片

8.修改mian.c文件调用fun2函数。

分享一次学习cmake基础的过程。_第13张图片

9.修改CMakeLists.txt文件,

分享一次学习cmake基础的过程。_第14张图片

aux_source_directory把当前目录下的源文件存放到变量SRC_LIST里,然后在add_executable里调用SRC_LIST(注意调用变量时的写法 ${变量})

10.编译通过后运行main,可以看到fun1,和fun2都打印了对应的值。

分享一次学习cmake基础的过程。_第15张图片

 

三、多个目录下的不同源文件cmake编译

一般情况下,我们不同功能的源文件会用单独的文件夹保存,这样我们就有在多个目录下调用不同源文件的需求。

1.在cmake_test文件夹下新建fun1和fun2文件夹,在把之前 fun1和fun2的相关文件移动到对应的文件夹下。整理后的文件夹结构如下:

分享一次学习cmake基础的过程。_第16张图片

2.修改CMakeLists.txt,增加include_directories (fun1 fun2)命令,意思是告诉编译器可以到fun1和fun2找头文件,多个路径可以用空格键分隔。aux_source_directory命令把两个文件夹保存到对应的变量中。

add_executable把源代码都添加进去。

分享一次学习cmake基础的过程。_第17张图片

 

四、头文件和源文件分开放cmake编译

1.当我们有时候需要把头文件放在同一个文件,而把源文件放在另一个文件夹时,我们可以新建include文件夹用于存放.h文件,新建src文件夹存放.c文件。整理后结构如下图所示(.gitignore文件是Git的文件,与实际项目无关,可以忽略)

分享一次学习cmake基础的过程。_第18张图片

2.修改CMakeLists.txt的内容,add_subdirectory (src)命令的意思是添加源文件的目录到工程中,参数src是源文件所在的文件夹名,还有其他参数用于指定外部文件夹在输出文件夹中的位置等,这里不需要用到可以忽略。

分享一次学习cmake基础的过程。_第19张图片

3.上面指定了src为源文件的目录,所以当我们运行cmake命令时,就会查找src目录下的CMakeLists.txt文件,这样我们需要在src目录下新建一个CMakeLists.txt,内容如下:

分享一次学习cmake基础的过程。_第20张图片

最后一句是set命令,用于定义变量。

第一个参数EXECUTABLE_OUT_PATH

为cmake自带的预定义变量,表示目标二进制可执行文件的存放位置。

第二个参数${PROJECT_SOURCE_DIR}/build表示当前工程根目录下的build文件夹。其中PROJECT_SOURCE_DIR也是cmake自带的预定义变量,表示工程根目录。

4.最后工程项目的文件结构如下图所示:

分享一次学习cmake基础的过程。_第21张图片

5.接下来运行cmake .. && make编译,并且查看生成的文件,可以看到main已经生成,还生成了src文件夹,保存src文件夹下的CMakeLists.txt编译生成的文件。

分享一次学习cmake基础的过程。_第22张图片

6.运行./main,可以看到程序已经可以运行。

五、cmake编译生成.a静态库

1.在cmake_test文件夹下新建lib文件夹,用于保存库的源文件和头文件。然后把测试的fun相关的源文件和头文件放进lib文件夹,并且在lib文件夹下新建CMakeLists.txt文件。最后的结构如下所示。

分享一次学习cmake基础的过程。_第23张图片

2.lib下的CMakeLists.txt文件的内容为:

分享一次学习cmake基础的过程。_第24张图片

其中,add_library的功能为生成动态或静态库,第一个参数指定库的名字,输出名字时,cmake会自动把库的前缀和后缀补全,例如此命令会生成名字为‘liblibFun_static.a’的静态库;第二个参数指定是动态库还是静态库,如果没有指定,默认为静态库,SHARED则指定为动态库;第三个参数指定生成库的源文件。

set_target_properties设置输出的名称,如果是动态库还可以设置版本号等。使用此命令可以把上面命令生成的‘liblibFun_static.a’自动重命名为‘libfun.a’。

LIBRARY_OUTPUT_PATH:指定库文件的默认输出路径,这里指定在工程目录下的lib目录。

3.开始编译

cmake .. && make

分享一次学习cmake基础的过程。_第25张图片

4.可以看到lib文件夹已经生成了libfun.a的静态库。

分享一次学习cmake基础的过程。_第26张图片

 

六、cmake链接静态库

1.在根目录的CMakeLists.txt文件中添加add_subdirectory (src),表示把告诉cmake去src目录下执行另一个CMakeLists.txt。

分享一次学习cmake基础的过程。_第27张图片

2.在src目录下添加CMakeLists.txt文件,内容如下:

分享一次学习cmake基础的过程。_第28张图片

以上出现了两个新的命令:

link_directories:告诉cmake要调用的库的路径,

target_link_libraries:链接目标文件和库文件。如果不指定全名,默认是链接动态库,由于我们只有静态库,所以可以不用设置,如果同时存在动态库和静态库,又只想调用静态库,则库名称需要写全名,如target_link_libraries (main libfun.a)

3.为了测试我们的库是否调用成功,我们修改main.c文件来变化输出的内容。将fun1和fun2的输出值都加1。

分享一次学习cmake基础的过程。_第29张图片

4.编译

cmake .. && make

分享一次学习cmake基础的过程。_第30张图片

5.可以使用ls命令查看已经生成main文件,运行./main成功。

分享一次学习cmake基础的过程。_第31张图片

 

七、cmake添加编译选项

有时编译时需要添加一些编译选项,如src下有多个项目,有时只需要编译一个项目即可,但是每次都修改add_executable参数会比较麻烦,所以增加编译控制选项来修改编译的项目和生成的名称。

1.修改根目录下的CMakeLists.txt文件。

分享一次学习cmake基础的过程。_第32张图片

在最前面增加了if逻辑判断,如果没有设置PROJ,则参数FATAL_ERROR输出一个致命性错误并且停止后续的编译,后面的是打印的提示信息,正确的例子:cmake .. -DPROJ=testfun1。如果已经设置了PROJ,则把接收到的PROJ的值打印出来。

project (${PROJ}):设置项目名称,后面可以直接调用变量PROJECT_NAME表示我们设置项目名称。

2.在src文件夹下新建testfun1和testfun2文件夹,并且原来src目录下的main.c文件复制一份后分别移到新建的两个文件夹中,最终文件夹架构为:

分享一次学习cmake基础的过程。_第33张图片

3.分别修改testfun1和testfun2下的main.c文件。

分享一次学习cmake基础的过程。_第34张图片

分享一次学习cmake基础的过程。_第35张图片

4.修改src目录下的CMakeLists.txt文件。

分享一次学习cmake基础的过程。_第36张图片

aux_source_directory (${PROJECT_NAME} SRC_LIST):把设置好的项目目录(src/xxx)添加到变量SRC_LIST中。

add_executable (${PROJECT_NAME} ${SRC_LIST}):设置生成文件为工程名xxx。

target_link_libraries (${PROJECT_NAME} fun):链接库。

5.开始编译项目testfun1。并且运行./testfun1。

分享一次学习cmake基础的过程。_第37张图片

6.编译项目testfun2,并且运行./testfun2。

分享一次学习cmake基础的过程。_第38张图片

 

八、总结

到此,基础的cmake操作已经学习完毕,但是还有很多cmake高级的用法没有学习到,比如其他命令,或者不同的参数的意义等。还是要在实践中检验,cmake作为跨平台的编译工具真的很值得学习,能够在后续的开发中收益满满。

此文是自我学习的记录与分享,资料参考自网络,如果文中有不对的地方,请不吝留言指正,感谢大家。

你可能感兴趣的:(嵌入式)