CmakeList.txt
本文主要参考
Linux下Cmake简明教程
Cmake入门基础
1. 首先体验一波cmake如何操作
- 编写main.cc
#include <iostream>
using namespace std;
int main()
{
cout << "Hello" << endl;
return 0;
}
- 在main.cc的目录下编写CmakeList.txt
cmake_minimum_required(VERSION 2.8)
project(demo)
add_executable(main main.cpp)
在终端下切到main.cc所在的目录下,然后输入以下命令运行cmake
cmake .
2. 同一目录下的多个源文件
此类在工程代码学习过程中经常遇到。即,同一目录下的多个源文件。
举例说明,现目录如下:
├── CMakeLists.txt
├── main.cc
├── Test.h
├── Test.cc
/*Test.cc*/
#include <iostream>
#include "Test.h"
void func(int abc)
{
std::cout << abc << std::endl;
}
/*Test.h*/
#ifndef _TEST_H_
#define _TEST_H_
void func(int abc);
#endif
/*main.cc*/
#include <iostream>
#include "Test.h"
int main(void)
{
func(10);
return 0;
}
此目录CmakeList.txt如下所示
cmake_minimum_required (VERSION 2.8)
project (demo)
add_executable(main main.cc Test.cc)
可以类推,在同一目录下有多个源文件,只要add_executable里把所有的源文件添加进去就可以了。但是如果这个源文件很多很多,这样做不合适,cmake提供了一个命令可以把指定目录下所有的源文件存储在一个变量中,这个命令就是aux_source_directory(dir var)
dir:指定目录 var:存放源文件列表的变量
cmake_minimum_required (VERSION 2.8)
project (demo)
aux_source_directory(. SRC_LIST)
add_executable(main ${SRC_LIST})
使用aux_source_directory把当前目录下的源文件存列表存放到变量SRC_LIST里,然后在add_executable里调用SRC_LIST(注意调用变量时的写法)
aux_source_directory()也存在弊端,它会把指定目录下的所有源文件都加进来,可能会加入一些我们不需要的文件,此时我们可以使用set命令去新建变量来存放需要的源文件。
cmake_minimum_required (VERSION 2.8)
project (demo)
set(SRC_LIST
./main.cc
./Test.cc)
add_executable(main ${SRC_LIST})
3. 不同目录下的多个源文件
工程中,一般程序文件比较多时,需要分类管理,把代码根据功能放在不同的目录里方便查找。
├── CMakeLists.txt
├── main.cc
├── Test1
└── Test.cc
└── Test.h
├── Test2
└── Test2.cc
└── Test2.h
其中,CMakeLists.txt和main.c在同一目录下
cmake_minimum_required (VERSION 2.8)
project (demo)
include_directories (Test1 Test2)
aux_source_directory (Test1 SRC_LIST)
aux_source_directory (Test2 SRC_LIST1)
add_executable (main main.cc ${SRC_LIST} ${SRC_LIST1})
include_directories
:该命令是用来向工程添加多个指定头文件的搜索路径,路径之间用空格分隔。
因为main.cc里include了Test.h和Test2.h,如果没有这个命令来指定头文件所在位置,就会无法编译。当然,也可以在main.cc里使用include来指定路径,如下:
#include "Test1/Test.h"
#include "Test2/Test2.h"
4. 组织结构
一般会把源文件放到src目录下,把头文件放入到include文件下,生成的对象文件放入到build目录下,最终输出的elf文件会放到bin目录下,这样整个结构更加清晰。
├── bin
├── build
├── include
└── Test.h
└── Test2.h
├── src
└── main.cc
└── Test.cc
└── Test2.cc
└── CMakeLists.txt
├── CMakeLists.txt
最外层CMakeLists.txt,内容如下,
cmake_minimum_required (VERSION 2.8)
project (demo)
add_subdirectory (src)
出现一个新的命令add_subdirectory(),这个命令可以向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制的存放位置,具体用法可以百度。
这里指定src目录下存放了源文件,当执行cmake时,就会进入src目录下去找src目录下的CMakeLists.txt,所以在src目录下也建立一个CMakeLists.txt,内容如下,
aux_source_directory (. SRC_LIST)
include_directories (../include)
add_executable (main ${SRC_LIST})
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
这里又出现一个新的命令set,是用于定义变量的,EXECUTABLE_OUT_PATH和PROJECT_SOURCE_DIR是CMake自带的预定义变量,其意义如下,
- EXECUTABLE_OUTPUT_PATH :目标二进制可执行文件的存放位置
- PROJECT_SOURCE_DIR:工程的根目录
这里set的意思是把存放elf文件的位置设置为工程根目录下的bin目录。
最外面的CMakeLists.txt用于掌控全局,使用add_subdirectory来控制其它目录下的CMakeLists.txt的运行。
cmake_minimum_required (VERSION 2.8)
project (demo)
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
aux_source_directory (src SRC_LIST)
include_directories (include)
add_executable (main ${SRC_LIST})
同时,还要把src目录下的CMakeLists.txt删除。
4.1 标准框架工程实例
CMakeList.txt
cmake_minimum_required (VERSION 2.8)
project (demo)
include_directories (include) #指定头文件所在目录
aux_source_directory (Func1 SRC_LIST1)
aux_source_directory (Func2 SRC_LIST2)
add_executable (main src/main.cpp ${SRC_LIST1} ${SRC_LIST2})
这里主要是将头文件放在include,源文件放在src。
5. 重新生成make clean
#在build文件夹下
make clean #清除生成的可执行文件
make -j6
6. Cmake自带的预定义变量
这些预定义变量可以在CMakeList.txt里可以直接使用,加上变量名取出值就可以直接使用${}
预定义变量名称 | 作用 |
---|---|
PROJECT_NAME | 通过 project() 指定项目名称 |
PROJECT_SOURCE_DIR | 工程的根目录 |
PROJECT_BINARY_DIR | 执行 cmake 命令的目录 |
CMAKE_CURRENT_SOURCE_DIR | 当前 CMakeList.txt 文件所在的目录 |
CMAKE_CURRENT_BINARY_DIR | 编译目录,可使用 add subdirectory 来修改 |
EXECUTABLE_OUTPUT_PATH | 二进制可执行文件输出位置 |
LIBRARY_OUTPUT_PATH | 库文件输出位置 |
BUILD_SHARED_LIBS | 默认的库编译方式 ( shared 或 static ) ,默认为 static |
CMAKE_C_FLAGS | 设置 C 编译选项 |
CMAKE_CXX_FLAGS | 设置 C++ 编译选项 |
CMAKE_CXX_FLAGS_DEBUG | 设置编译类型 Debug 时的编译选项 |
CMAKE_CXX_FLAGS_RELEASE | 设置编译类型 Release 时的编译选项 |
CMAKE_GENERATOR | 设置编译类型 Release 时的编译选项 |
CMAKE_COMMAND | CMake 可执行文件本身的全路径 |
CMAKE_BUILD_TYPE | 工程编译生成的版本, Debug / Release |
7. add_subdirectory 多库联编
在构建大型工程时,涉及到多个库联编。
之前是只有demo这一个project,有时候会写一些通用库便于移植/单独测试/任务分解,然后多个库联编,就是会有多个cmakelist.txt,而且这些库/project之间可能互相依赖。
假设project(demo)依赖Func3这个project,demo目录结构如上图所示。
cmake_minimum_required (VERSION 2.8)
project (demo)
include_directories (include)
aux_source_directory (Func1 SRC_LIST1)
aux_source_directory (Func2 SRC_LIST2)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Func3) #增加依赖库的根目录
add_executable (main src/main.cpp ${SRC_LIST1} ${SRC_LIST2})
target_link_libraries(${PROJECT_NAME} Func3) #指定demo需要依赖Func3这个库
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
通过add_subdirectory,target_link_libraries配合使用可以实现多库联编。
被依赖的Func3,可以独立于demo这个project运行,也可以单独编译。
8. 路径下遍历全局表达式匹配 file
#作用就是将src路径下的所有.cc文件,打包取个别名叫做变量SRC_FILES
#GLOB :产生一张与全局表达式匹配的所有文件的表 并存入指定变量SRC_FILES中
file(GLOB SRC_FILES src/*.cc)
#取出变量SRC_FILES的值,也就是打包在一起的所有.cc文件
#将这些打包在一起的.cc文件生成STATIC静态库,静态库的名称就是工程名
add_library(${PROJECT_NAME} STATIC ${SRC_FILES})
上面的*.cc也可以换成*.txt,*.proto
GLOB_RECURSE :与 GLOB 类似, 但会遍历匹配路径下面的所有子路径并匹配文件
file(GLOB_RECURSE SRC_FILES src/*.cc)
9. find_package 引入外部依赖包
环境变量的名字遵循packagename_property,即包名-属性。
假设此时我们需要引入google glog库来进行日志的记录,我们需要自行安装glog库,再进行引用。
PACKAGENAME_FOUND:当库被查找到时置为true,否则为false
PACKAGENAME_INCLUDE_DIRS或PACKAGENAME_INCLUDES:软件包导出的头文件路径PACKAGENAME_LIBRARIES或_LIBS:软件包导出的库的路径
CMakeList.txt写法
find_package(GLOG)
add_executable(glogtest glogtest.cc)
if(GLOG_FOUND)
message(STATUS ”GLOG library found”)
else()
message(FATAL_ERROR ”GLOG library not found”)
endif()
#找到glog库后就可以链接了
target_link_libraries(${PROJECT_NAME} glog)