CMake入门学习
Posted ych9527
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CMake入门学习相关的知识,希望对你有一定的参考价值。
一、CMakeLists.txt简单编写
- add_executable
- 在这个函数之之中,填充elf可执行文件名称,以及依赖的.c文件即可
cmake_minimum_required (VERSION 2.8) //cmake最低版本要求为2.8
project (demo) //工程名demo
add_executable(main main.c testFunc.c) //最终生成的elf文件是main,使用的源文件是main.c和testFunc.c
-
aux_source_directory(dir var)
-
add_executable之中添加所有依赖的.c文件,可以cmake . 生成elf可执行文件,但是如果工程项目非常之大,这样是比较麻烦的。因此有了新命令aux_source_directory(dir var),可以将指定目录下的所有源文件存储在一个变量之中
-
dir:指定目录
-
var:用于存放源文件列表的变量
//此时有多个源文件 cmake_minimum_required (VERSION 2.8) //cmake最低版本要求为2.8 project (demo) //工程名demo aux_source_directory(. SRC_LIST) //把当前目录下的源文件存列表存放到变量SRC_LIST里 add_executable(main $SRC_LIST) //在add_executable里调用SRC_LIST
-
aux_source_directory()也存在弊端,它会把指定目录下的所有源文件都加进来,可能会加入一些我们不需要的文件,此时我们可以使用set命令去新建变量来存放需要的源文件,如下
cmake_minimum_required (VERSION 2.8) project (demo) set( SRC_LIST ./main.c ./testFunc1.c ./testFunc.c)
-
-
-
include_directories
-
向工程添加多个指定头文件的搜索路径,路径之间用空格分隔,和在main.c之中用 //include "name.h"包含头文件是一样的效果
//有两个文件夹,分别装有一个头文件和一个cpp文件,将其整理分门别类 cmake_minimum_required (VERSION 2.8) project (demo) include_directories (test_func test_func1)//向工程添加多个指定头文件的搜索路径,路径之间用空格分隔 //源文件分布在两个目录之下,因此添加两次变量 aux_source_directory (test_func SRC_LIST) aux_source_directory (test_func1 SRC_LIST1) add_executable (main main.c $SRC_LIST $SRC_LIST1)
-
二、正规项目组织方式
-
正规组织方法如下
-
源文件放到src目录下
-
把头文件放入到include文件下
-
生成的对象文件放入到build目录下
-
最终输出的elf文件会放到bin目录下,这样整个结构更加清晰
[ych@2ec71362f5e6 ~]$ tree test/ test/ ├── bin //elf可执行文件 ├── built //生成的对象 ├── CMakeLists.txt ├── include //头文件 │ ├── testFunc1.h │ └── testFunc.h └── src //源文件 ├── main.c ├── testFunc1.c └── testFunc.c
-
-
add_subdirectory()
-
这个命令可以向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制的存放位置
-
add_subdirectory(子文件夹名)表示对子文件夹项目进行cmake编译
make_minimum_required (VERSION 2.8) project (demo) add_subdirectory (src) //表示对子文件夹项目进行cmake编译
-
这里指定src目录下存放了源文件,当执行cmake时,就会进入src目录下去找src目录下的CMakeLists.txt,所以在src目录下也建立一个CMakeLists.txt
-
使用了2个CMakeLists.txt,最外层的CMakeLists.txt用于掌控全局,使用add_subdirectory来控制其它目录下的CMakeLists.txt的运行
aux_source_directory (. SRC_LIST) //把当前目录下的源文件存列表存放到变量SRC_LIST里 include_directories (../include) //头文件所在位置 add_executable (main $SRC_LIST) //将变量中的源文件拿出来 // set 用于定义变量 //本句的意思是,将生成的可执行放到当前工程目录的bin目录之下 set (EXECUTABLE_OUTPUT_PATH $PROJECT_SOURCE_DIR/bin)
-
EXECUTABLE_OUT_PATH和PROJECT_SOURCE_DIR是CMake自带的预定义变量,其意义如下
- EXECUTABLE_OUTPUT_PATH :目标二进制可执行文件的存放位置
- PROJECT_SOURCE_DIR:工程的根目录
-
-
如果使用一个CMakeLists.txt,改动如下
- **小技巧:**在built目录下执行cmake … ,cmake运行生成的所有附带文件就全部集中在built文件夹之下,不会和其它文件混在一起,如果不想要了,直接清空built文件夹即可
cmake_minimum_required (VERSION 2.8) project (demo) set (EXECUTABLE_OUTPUT_PATH $PROJECT_SOURCE_DIR/bin) //将生成的可执行放在bin目录下 aux_source_directory (src SRC_LIST) //将src下所有的源文件添加到变量之中 include_directories (include) //头文件所在位置 add_executable (main $SRC_LIST) //进行生成
-
三、动态库和静态库的编译控制
-
有时只需要编译出动态库和静态库,然后等着让其它程序去使用。让我们看下这种情况该如何使用cmake。首先按照如下重新组织文件,只留下testFunc.h和TestFunc.c
test/ ├── built ├── CMakeLists.txt ├── lib ├── main.c └── testFunc ├── testFunc.c └── testFunc.h
-
CMakeLists.txt文件内容如下
cmake_minimum_required (VERSION 3.5) project (demo) set (SRC_LIST $PROJECT_SOURCE_DIR/testFunc/testFunc.c)// 将工程根目录下的.C文件拿出来放到变量之中 add_library (testFunc_shared SHARED $SRC_LIST) //add_library: 生成动态库或静态库 add_library (testFunc_static STATIC $SRC_LIST) set_target_properties (testFunc_shared PROPERTIES OUTPUT_NAME "testFunc")//设置最终生成的库的名称 set_target_properties (testFunc_static PROPERTIES OUTPUT_NAME "testFunc") set (LIBRARY_OUTPUT_PATH $PROJECT_SOURCE_DIR/lib)//库文件的默认输出路径,设置为lib
-
add_library: 生成动态库或静态库(第1个参数指定库的名字;第2个参数决定是动态还是静态,如果没有就默认静态;第3个参数指定生成库的源文件)
-
set_target_properties: 设置最终生成的库的名称,还有其它功能,如设置库的版本号等等
[ych@2ec71362f5e6 lib]$ ls libtestFunc.a libtestFunc.so //可以看到动静态库的名字是很整齐的 如果不使用set_target_properties也可以,那么库的名称就是add_library里定义的名称,只是连续2次使用add_library指定库名称时(第一个参数),这个名称不能相同,而set_target_properties可以把名称设置为相同,只是最终生成的库文件后缀不同(一个是.so,一个是.a),这样相对来说会好看点。
-
LIBRARY_OUTPUT_PATH: 库文件的默认输出路径,这里设置为工程目录下的lib目录
-
四、对库进行链接
-
新建目录,结构如下
file/ ├── bin ├── build ├── CMakeLists.txt ├── src │ └── main.c └── testFunc ├── inc └── lib
-
CMakeLists.txt内容如下
cmake_minimum_required (VERSION 3.5) project (demo) set (EXECUTABLE_OUTPUT_PATH $PROJECT_SOURCE_DIR/bin)//设置生成的elf文件在bin目录之下 set (SRC_LIST $PROJECT_SOURCE_DIR/src/main.c)//将点C文件添加至变量之中 include_directories ($PROJECT_SOURCE_DIR/testFunc/inc)//添加头文件的位置 find_library(TESTFUNC_LIB testFunc HINTS $PROJECT_SOURCE_DIR/testFunc/lib)//在指定目录下查找指定库 //在lib目录下有testFunc的静态库和动态库,find_library(TESTFUNC_LIB testFunc ...默认是查找动态库,如果想直接指定使用动态库还是静态库,可以写成find_library(TESTFUNC_LIB libtestFunc.so ...或者find_library(TESTFUNC_LIB libtestFunc.a add_executable (main $SRC_LIST)//将变量中的.C拿出来 target_link_libraries (main $TESTFUNC_LIB)//把目标文件与库文件进行链接
- find_library: 在指定目录下查找指定库,并把库的绝对路径存放到变量里
- 第一个参数是变量名称
- 第二个参数是库名称
- 第三个参数是HINTS
- 第4个参数是路径
- target_link_libraries: 把目标文件与库文件进行链接
- find_library: 在指定目录下查找指定库,并把库的绝对路径存放到变量里
-
五、添加编译选项
-
add_compile_options()
- 有时编译程序时想添加一些编译选项,如-Wall,-std=c++11等,就可以使用add_compile_options来进行操作
cmake_minimum_required (VERSION 2.8) project (demo) set (EXECUTABLE_OUTPUT_PATH $PROJECT_SOURCE_DIR/bin) add_compile_options(-std=c++11 -Wall) //添加编译选项 add_executable(main main.cpp)
六、添加控制选项
-
有时希望在编译代码时只编译一些指定的源码,可以使用cmake的option命令,主要遇到的情况分为2种:
- 本来要生成多个bin或库文件,现在只想生成部分指定的bin或库文件
- 对于同一个bin文件,只想编译其中部分代码(使用宏来控制)
-
情况一
- 工程架构如下
proc/ ├── bin ├── build ├── CMakeLists.txt └── src ├── CMakeLists.txt ├── main1.c └── main2.c
-
外层CMakeLists.txt
cmake_minimum_required(VERSION 2.8) project(demo) #第一个参数:option名字 #第二个参数:字符串,描述option干啥的 #第三个:optins的值,不写就是OFF option(MYDEBUG "enable debug compilation" OFF) set (EXECUTABLE_OUTPUT_PATH $PROJECT_SOURCE_DIR/bin) //将elf放置bin目录之下 add_subdirectory(src) # 对子文件夹src项目进行cmake编译
- option命令
- 第一个参数是这个option的名字
- 第二个参数是字符串,用来描述这个option是来干嘛的
- 第三个是option的值,ON或OFF,也可以不写,不写就是默认OFF
- option命令
-
src里层CMakeLists.txt
cmake_minimum_required(VERSION 2.8) add_executable(main1 main1.c) if(MYDEBUG) //如果option为NO,就编译main2 add_executable(main2 main2.c) else() message(STATUS "Currently is not in debug mode") endif()
-
cmake … -DMYDEBUG=ON
-
直接在编译的时候设置option的值
cmake .. && make ls ../bin/ main1 cmake .. -DMYDEBUG=ON ls ../bin/ main1 main2
-
-
情况二
-
假设有如下文件
#include <stdio.h> int main(void) #ifdef WWW1 printf("hello world1\\n"); #endif #ifdef WWW2 printf("hello world2\\n"); #endif return 0;
-
add_definitions()
-
通过宏定义来打印文件,CMakeLists.txt文件内容如下
-
通过与add_definitions()的配合,就可以控制单个bin文件的打印输出了
cmake_minimum_required(VERSION 3.5) project(demo) set (EXECUTABLE_OUTPUT_PATH $PROJECT_SOURCE_DIR/bin) #生成的可执行文件放置bin目录之中 #设置option的名字 option(WWW1 "print one message" OFF) option(WWW2 "print another message" OFF) #进行判断 if (WWW1) add_definitions(-DWWW1) endif() if (WWW2) add_definitions(-DWWW2) endif() add_executable(main main.c) // 效果如下 cmake .. -DWWW1=ON -DWWW2=OFF ../bin/main hello world1 cmake .. -DWWW1=OFF -DWWW2=ON ../bin/main hello world2 cmake .. -DWWW1=ON -DWWW2=ON ../bin/main hello world1 hello world2
-
以上是关于CMake入门学习的主要内容,如果未能解决你的问题,请参考以下文章