Cmake概述
什么是cmake
cmake是一个跨平台的安装编译工具,可以用简单的语言来描述所有平台的c++工程安装
为什么要用cmake
在1.1文章中我们已经学习了最原始的c++工程编译方式,由于我们的示例工程很简单,所以使用原生的编译命令行并没有那么难,但是当我们的工程复杂度提高,使用原生方式编译很繁琐,而且部署到不同的平台时,我们需要对编译命令进行修改,此时cmake横空出世,它能帮助我们简化编译命令,并且实现一次书写,各个平台都可复用。
cmake安装
cmake语法格式
模板
指令(参数1 参数2 参数3...)
-
使用()将参数括起来,参数之间使用空格或者分号隔开
-
使用${变量名}的方式取变量值,但是在if语句中直接使用变量名取值
-
指令不区分大小写,参数和变量名区分大小写
cmake重要命令
- cmake_minimum_required
指定CMake的最小版本要求:
cmake_minimum_required(VERSION 2.8.1)
完整语法**cmake_minimum_required(VERSION versionNumber [FATAL_ERROR])**
- project
指定工程名称:
project(HelloWorld)
完整语法**project(projectname [CXX] [C] [Java])**
- set
定义变量
# 定义src变量的值为swap.cpp main.cpp
set(src swap.cpp main.cpp)
完整语法**set(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])**
- include_directories
指定多个头文件的搜索目录,相当于g++编译命令中的-I参数
# 添加./include和/usr/include/myInclude到头文件搜索路径中
include_directories(./include /usr/include/myInclude)
完整语法**include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 …)**
- target_include_directories
指定目标包含的头文件路径,目标 由 add_library()或 add_executable()生成。
- link_directories
向工程添加多个特定的库文件搜索路径,相当于指定g++编译器的-L参数
# 添加/usr/lib/myLib ./lib到库文件搜索路径中
link_directories(/usr/lib/myLib ./lib)
- add_library
生成库文件
# 通过变量 src 生成 libhello.so
add_library(hello SHARED ${src})
完整语法:**add_library(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL] source1 source2 … sourceN)**
- add_compile_options
添加编译参数
# 添加-Wall -std=c++11 -O2编译参数
add_compile_options(-Wall -std=c++11 -O2)
- add_executable
生成可执行文件
# 编译main.cpp和src/swap.cpp生成可执行文件main
add_executable(main main.cpp src/swap.cpp)
- target_link_libraries
为目标文件链接指定库
# 将libhello.so动态库文件链接到可执行文件main
target_link_libraries(main hello)
- aux_source_directory
发现一个目录下所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表
# 定义SRC变量,其值为当前目录下所有的源代码文件
aux_source_directory(. SRC)
# 编译SRC变量所代表的源代码文件,生成main可执行文件
add_executable(main ${SRC})
cmake重要变量
- CMAKE_CXX_FLAGS
g++编译选项
# 在CMAKE_CXX_FLAGS编译选项后追加-std=c++11\
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
- CMAKE_BUILD_TYPE
编译类型(Debug, Release)
# 设定编译类型为debug,调试时需要选择debug
set(CMAKE_BUILD_TYPE Debug)
# 设定编译类型为release,发布时需要选择release
set(CMAKE_BUILD_TYPE Release)
- CMAKE_C_COMPILER
指定C编译器
- CMAKE_CXX_COMPILER
指定C++编译器
- EXECUTABLE_OUTPUT_PATH
可执行文件输出的存放路径
- LIBRARY_OUTPUT_PATH
库文件输出的存放路径
- PROJECT_BINARY_DIR和PROJECT_SOURCE_DIR
参考: stormzhou.blog.csdn.net/article/det…
Cmake编译工程
在项目的主目录下要有一个CMakeLists.txt文件
两种方式设置编译规则:
- 包含源文件的子文件夹包含CMakeLists.txt文件,主目录的CMakeLists.txt通过add_subdirectory添加子目录即可;
- 包含源文件的子文件夹未包含CMakeLists.txt文件,子目录编译规则体现在主目录的CMakeLists.txt中。
编译基本流程
- 编写CMakeLists.txt文件
- 执行cmake PATH生成MakeFile(PATH是顶层CMakeLists.txt所在的目录)
- 执行make命令进行编译
两种构建方式
- 内部构建
不推荐使用。该构建方式在同级目录下构建,会产生一大堆中间文件,让项目工程显的很杂乱。
- 外部构建
在工程主目录下先新建一个build文件,切换到build目录下执行cmake..和make。
mkdir build
cd build
cmake ..
make
项目练习
HelloWorld项目
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(helloworld)
add_executable(helloMain main.cpp)
编译前:
cd build && cmake .. && make
编译后:
多目录工程——直接编译
编译前的目录结构:
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(SWAP)
include_directories(include)
add_executable(fromCmakeBin main.cpp src/swap.cpp)
cd build && cmake .. && make
编译后的目录结构:
多目录工程——生成库编译
我们要实现的编译过程如下:
- 将src目录下的swap.cpp编译为libswap.a的静态库
- 然后将main.cpp编译为可执行文件StaticMain
- 将libswap.a链接到目标文件StaticMain
- StaticMain输出到build/bin目录下
编译前的目录结构:
swap.h
#pragma once
class swap
{
public:
swap(int a, int b)
{
this->_a = a;
this->_b = b;
}
void run();
void printInfo();
private:
int _a;
int _b;
}
swap.cpp
#include "swap.h"
#include <iostream>
void swap::run()
{
int temp;
temp = this->_a;
this->_a = this->_b;
this->_b = temp;
}
void swap::printInfo()
{
std::cout << "_a:" << this->_a << std::endl;
std::cout << "_b:" << this->_b << std::endl;
}
main.cpp
#include "swap.h"
int main(int argc, char **argv){
swap mySwap(109, 90);
mySwap.printInfo();
mySwap.run();
mySwap.printInfo();
return 0;
}
CMakelists.txt
# 指定cmake版本要求
cmake_minimum_required(VERSION 3.0)
# 项目名称
project(SWAP_LIBRARY)
# 添加编译选项
add_compile_options(-Wall -std=c++11)
# 设置编译类型,发布Debug版本
set(CMAKE_BUILD_TYPE Debug)
# 设置最终可执行文件的输出目录
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
# 将src/swap.cpp编译为静态库libswap.a
add_library(swap STATIC src/swap.cpp)
# 指定libswap.a的头文件搜索目录
target_include_directories(swap PUBLIC ${PROJECT_SOURCE_DIR}/include)
# 将main.cpp编译为可执行文件StaticMain
add_executable(StaticMain main.cpp)
# 将libswap.a链接到StaticMain
target_link_libraries(StaticMain swap)
命令行执行CMakeLists.txt
cd build
cmake ..
make
cmake编译后的文件目录:
一些坑以及疑惑
1.win平台报错cmake ..报错
解决方案:加上-G "MinGW Makefiles"
cmake .. -G "MinGW Makefiles"