==cmake_minimum_required== - 指定CMake的最小版本要求

语法: cmake_minimum_required(VERSION versionNumber [FATAL_ERROR])

# CMake最小版本要求为2.8.3
cmake_minimum_required(VERSION 2.8.3)

==project== - 定义工程名称,并可指定工程支持的语言

语法: project(projectname [CXX] [C] [Java])

#可以用来指定工程的名字和支持的语言,默认支持所有语言

PROJECT (HELLO)   指定了工程的名字,并且支持所有语言—建议

PROJECT (HELLO CXX)      指定了工程的名字,并且支持语言是C++

**PROJECT (HELLO C CXX)      指定了工程的名字,并且支持语言是C和C++**

该指定隐式定义了两个CMAKE的变量
<projectname>_BINARY_DIR,本例中是 HELLO_BINARY_DIR
<projectname>_SOURCE_DIR,本例中是 HELLO_SOURCE_DIR
**MESSAGE关键字就可以直接使用者两个变量,当前都指向当前的工作目录**,后面会讲外部编译
问题:如果改了工程名,这两个变量名也会改变
解决:又定义两个预定义变量:**PROJECT_BINARY_DIR和PROJECT_SOURCE_DIR**,这两个变量和HELLO_BINARY_DIR,HELLO_SOURCE_DIR是一致的。所以改了工程名也没有关系

==set==- 显式的定义变量

语法:set(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]]) 如果源文件名中含有空格,就必须要加双引号

# 定义SRC变量,其值为sayhello.cpp hello.cpp

set(SRC sayhello.cpp hello.cpp)

==include_directories== - 向工程添加多个 ==特定的头文件== 搜索路径 —>相当于指定g++编译器的-I参数

语法: include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 …)

# 将/usr/include/myincludefolder 和  ./include 添加到头文件搜索路径

include_directories(/usr/include/myincludefolder ./include)
├── CMakeLists.txt    #最外层的CMakeList.txt
├── main.cpp    #源文件,包含被测试的头文件
├── sub    #子目录
 └── test.h    #测试头文件,是个空文件,被外层的main,cpp包含

场景2:使用include_directories包含子目录sub,并在main.cpp里面包含"test.h"。

# CMakeList.txt
cmake_minimum_required(VERSION 3.18.2)
project(include_directories_test)
include_directories(sub) #与上个场景不同的地方在于此处
add_executable(test main.cpp)
    
    
//main.cpp
#include "test.h"
#include <stdio.h>
int main(int argc, char **argv)
{
    printf("hello, world!\n");
    return 0;

==add_library== - 生成库文件

语法: add_library(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL]source1 source2 … sourceN)

# 通过变量 SRC 生成 libhello.so 共享库

add_library(hello SHARED ${SRC})

ADD_LIBRARY(hello SHARED ${ LIBHELLO_SRC})

  • hello:就是正常的库名,生成的名字前面会加上lib,最终产生的文件是libhello.so

  • SHARED,动态库 STATIC,静态库

  • ${LIBHELLO_SRC} :源文件

构建实例

任务:

1,建立一个静态库和动态库,提供 HelloFunc 函数供其他程序编程使用,HelloFunc 向终端输出 Hello World 字符串。

2,安装头文件与共享库。

看code 构建静态和动态库

1. 构建静态和动态库

[root@localhost cmake2]# tree
.
├── build
├── CMakeLists.txt
└── lib
    ├── CMakeLists.txt
    ├── hello.cpp
    └── hello.h

hello.h中的内容

#ifndef HELLO_H
#define Hello_H

void HelloFunc();

#endif

hello.cpp中的内容

#include "hello.h"
#include <iostream>
void HelloFunc(){
    std::cout << "Hello World" << std::endl;
}

项目中的cmake内容

PROJECT(HELLO)
ADD_SUBDIRECTORY(lib bin)

lib中CMakeLists.txt中的内容

SET(LIBHELLO_SRC hello.cpp)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})

自动生成在 build/bin(自动创建的) 中

  • hello:就是正常的库名,生成的名字前面会加上lib,最终产生的文件是libhello.so

  • SHARED,动态库 STATIC,静态库

  • ${LIBHELLO_SRC} :源文件

    ../_images/image-20220812154252052.pngimage-20220812154252052


同时构建静态和动态库

用到 SET_TARGET_PROPERTIES

这条指令可以用来设置输出的名称,对于动态库,还可以用来指定动态库版本和 API 版本

同时构建静态和动态库

lib中CMakeLists.txt中的内容:

SET(LIBHELLO_SRC hello.cpp)

// 静态
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})
//对hello_static的重名为hello
SET_TARGET_PROPERTIES(hello_static PROPERTIES  OUTPUT_NAME "hello")
//cmake 在构建一个新的target 时,会尝试清理掉其他使用这个名字的库,因为,在构建 libhello.so 时, 就会清理掉 libhello.a
SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)


// 动态
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
SET_TARGET_PROPERTIES(hello PROPERTIES  OUTPUT_NAME "hello")
SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)

../_images/image-20220728220427809.pngimage-20220728220427809

动态库的版本号

一般动态库都有一个版本号的关联

libhello.so.1.2
libhello.so ->libhello.so.1
libhello.so.1->libhello.so.1.2

CMakeLists.txt 插入如下

SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)

VERSION 指代动态库版本,SOVERSION 指代 API 版本

2. 安装头文件 和 共享库

动态库和静态库需要安装头文件

将在lib里的 hello.h 安装到 usr/include/hello 目录

../_images/image-20220812154523061.pngimage-20220812154523061

给动态库和静态库需要安装头文件. 将 hello 的共享库安装到 usr/lib目录,

lib中的继续添加cmake内容

//文件放到该目录下
INSTALL(FILES hello.h DESTINATION include/hello)
    //这里的include应该是自动创建在当前Cmakelist所在目录

//二进制,静态库,动态库安装都用TARGETS
//ARCHIVE 特指静态库,LIBRARY 特指动态库,RUNTIME 特指可执行目标二进制。
INSTALL(TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)

注意:

安装的时候,指定一下路径,放到系统下

在build下:

cmake -D CMAKE_INSTALL_PREFIX=/usr ..

具体过程

../_images/image-20220812160113059.pngimage-20220812160113059

3. 使用

新建一个目录来使用外部共享库和头文件

[root@MiWiFi-R4CM-srv cmake3]# tree
.
├── build
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    └── main.cpp

main.cpp

#include <hello.h>          // 使用动态库

int main(){
	HelloFunc();            // 使用动态库
}

src里的camke

INCLUDE_DIRECTORIES(/usr/include/hello)   // 动态库的头文件

ADD_EXECUTABLE(hello main.cpp)

TARGET_LINK_LIBRARIES(hello libhello.so)  //动态库的lib文件

项目下的:

PROJECT(HELLO)

CMAKE_MINIMUM_REQUIRED(VERSION 2.8.3)

ADD_SUBDIRECTORY(src bin)

../_images/image-20220812171327338.pngimage-20220812171327338

解决:

mv /usr/lib/libhello.so /usr/lib64/

../_images/image-20220812171424005.pngimage-20220812171424005


==add_compile_options== - 添加编译参数

语法:add_compile_options(

# 添加编译参数 -Wall -std=c++11 -O2

add_compile_options(-Wall -std=c++11 -O2)

==add_executable==- 生成可执行文件

语法:add_executable(exename source1 source2 … sourceN)

# 编译main.cpp  生成 可执行文件main

add_executable(main main.cpp)

生成的可执行文件名是hello,源文件读取变量SRC_LIST中的内容 注意:工程名的 HELLO 和生成的可执行文件 hello 是没有任何关系的

也可以直接写 ADD_EXECUTABLE(hello main.cpp)

../_images/image-20220728090945010.pngimage-20220728090945010

==add_subdirectory== - 向当前工程添加存放源文件的子目录,指定 中间 和 目标的二进制存放的位置

语法: add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

#添加包含CMakeLists.txt和源文件的子目录 —> 相当于把整个文件变成一个.cpp文件

# 添加src子目录,src中需有一个CMakeLists.txt

add_subdirectory(src)

ADD_SUBDIRECTORY(src bin)

将 src 子目录加入工程并指定编译输出(包含编译中间结果)路径为bin 目录

如果不进行 bin 目录的指定,那么编译结果(包括中间结果)都将存放在build/src 目录

==aux_source_directory== - 发现一个目录下所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表

语法: aux_source_directory(dir VARIABLE)

# 定义SRC变量,其值为当前目录下所有的源代码文件
aux_source_directory(. SRC)

# 编译SRC变量所代表的源代码文件,生成main可执行文件

add_executable(main ${SRC})

../_images/image-20220728184226529.pngimage-20220728184226529

aux_source_directory(目录 存放文件列表的变量)

例如我们想搜索当前目录下的所有cpp则为

aux_source_directory(. CPP_LIST)

但是这个命令只会仅仅搜索当前目录下的文件(即tool2.cpp),tool1目录中无法搜索到,有两种解决办法:

1:再增加一个aux_source_directory(./tool1 CPP_LIST2),即可成功编译

../_images/image-20220728184407615.pngimage-20220728184407615

2.使用cmake单独将tool1文件夹编译为一个so

具体步骤:

1.在tool1文件夹中新建一个CMakeLists.txt ,其中内容为:

aux_source_directory(. tool1_file) #查找当前目录下的tool1相关文件

add_library(tool1lib ${tool1_file})   #将他们编译为一个叫tool1lib的文件

2.主目录的cmakelists修改为:

cmake_minimum_required(VERSION 2.6)  #指定cmake最低版本为2.6
 
project(FirstCmakeDemo)  #指定工程名称
aux_source_directory(. CPP_LIST)  #搜索当前目录下的所有cpp文件
add_subdirectory(tool1)           #将tool1文件夹加入子目录,这样他就可以去tool1文件夹中查找编译
 
add_executable(out_file ${CPP_LIST}) #生成目标文件
 
target_link_libraries(out_file tool1lib)
#添加链接库,其库的名字由tool1文件夹中的CMakeLists.txt来指定生成

CMake常用变量

  • CMAKE_C_FLAGS gcc编译选项 // c语言

  • CMAKE_CXX_FLAGS g++编译选项 // c++

# 在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_BINARY_DIR

  • PROJECT_BINARY_DIR _BINARY_DIR

  1. 这三个变量指代的内容是一致的。

  2. 如果是 in source build,指的就是工程顶层目录。

  3. 如果是 out-of-source 编译,指的是工程编译发生的目录。

  4. PROJECT_BINARY_DIR 跟其他指令稍有区别,不过现在,你可以理解为他们是一致 的。

​ CMAKE_SOURCE_DIR

  • PROJECT_SOURCE_DIR _SOURCE_DIR

  1. 这三个变量指代的内容是一致的,不论采用何种编译方式,都是工程顶层目录。

  2. 也就是在 in source build时,他跟 CMAKE_BINARY_DIR 等变量一致。

  3. PROJECT_SOURCE_DIR 跟其他指令稍有区别,现在,你可以理解为他们是一致的。

CMAKE_C_COMPILER:指定C编译器 CMAKE_CXX_COMPILER:指定C++编译器 EXECUTABLE_OUTPUT_PATH:可执行文件输出的存放路径 LIBRARY_OUTPUT_PATH:库文件输出的存放路径

CMake编译工程

CMake目录结构:项目主目录存在一个CMakeLists.txt文件 两种方式设置编译规则:

  1. 包含源文件的子文件夹包含CMakeLists.txt文件,主目录的CMakeLists.txt通过add_subdirectory 添加子目录即可;

  2. 包含源文件的子文件夹未包含CMakeLists.txt文件,子目录编译规则体现在主目录的 CMakeLists.txt中; 6.4.1 编译流程 在 linux 平台下使用 CMake 构建C/C++工程的流程如下: 手动编写 CMakeLists.txt。 执行命令 cmake PATH 生成 Makefile ( PATH 是顶层CMakeLists.txt 所在的目录 )。 执行命令make 进行编译。 6.4.2 两

内部构建和外部构建

内部构建:

../_images/image-20220728161428721.pngimage-20220728161428721

cmake .

../_images/image-20220728161724144.pngimage-20220728161724144

make

../_images/image-20220728162017284.pngimage-20220728162017284

../_images/image-20220728162205964.pngimage-20220728162205964


外部构建 :

进入build文件 camke ..

cmake 点点”表示在上一级目录(CMakeLists.txt所在目录)编译

外部构建

将编译输出文件与源文件放到不同目录中

## 外部构建
# 1. 在当前目录下,创建build文件夹
mkdir build
# 2. 进入到build文件夹
cd build
# 3. 编译上级目录的CMakeLists.txt,生成Makefile和其他文件
cmake ..
# 4. 执行make命令,生成target
make

../_images/image-20220728162625601.pngimage-20220728162625601

make

../_images/image-20220728163021988.pngimage-20220728163021988

把所有生成文件都放在build目录中

../_images/image-20220728162835070.pngimage-20220728162835070

多文件

../_images/image-20220728163615159.pngimage-20220728163615159

../_images/image-20220728163943522.pngimage-20220728163943522

例子2:

../_images/image-20220728165313977.pngimage-20220728165313977


配置VSCode的json文件并调试项目

xiaobing

../_images/image-20220728170419101.pngimage-20220728170419101

多文件编译

../_images/image-20220728214607008.pngimage-20220728214607008

看文件 mutil

cmake_minimum_required(VERSION 3.0)

project(MUTIL)

#设置hello world 给环境变量TARGET
set(TARGET helloworld)

#添加头文件              -- 有.h的地方
include_directories(
    hello
    world
)

#添加包含CMakeLists.txt和源文件的子目录
add_subdirectory(hello)
add_subdirectory(world)

aux_source_directory(. DIRSRCS)

#生成可执行文件
add_executable(${TARGET} ${DIRSRCS})

#helloworld 链接静态库hello和world
target_link_libraries(${TARGET}  hello world)
#把指定目录下所有源代码和头文件文件入变量DIR_HELLO    “.”是指cmakelists文件当前目录
aux_source_directory(. DIR_HELLO)

#从${DIR_HELLO}文件中生成hello库, STATIC是生成静态库
add_library(hello STATIC ${DIR_HELLO})
aux_source_directory(. DIR_WORLD)

add_library(world STATIC ${DIR_WORLD})

案例2

SheepMarket
├─ .vscode
│  ├─ c_cpp_properties.json
│  ├─ launch.json
│  ├─ settings.json
│  └─ tasks.json
├─ build
│  ├─ fontcolor.exe
│  ├─ init.exe
│  ├─ main.exe
│  └─ menu.exe
├─ CMakeLists.txt
├─ include
│  ├─ Administrator.h
│  ├─ consumer .h
│  ├─ fontcolor.h
│  ├─ init.h
│  ├─ menu.h
│  └─ system.h
├─ src
├  ├─ CMakeLists.txt
│  ├─ Administrator.cpp
│  ├─ consumer .cpp
│  ├─ fontcolor.cpp
│  ├─ init.cpp
│  ├─ main.cpp
│  ├─ menu.cpp
│  └─ system.cpp
└─ 功能总览.md
cmake_minimum_required(VERSION 3.0)
project(SHEEPMARKET)

set(TARGET main)

include_directories(${PROJECT_SOURCE_DIR}/include)
aux_source_directory(. DIRSRC)

add_subdirectory(${PROJECT_SOURCE_DIR}/src)

add_executable(${TARGET} ${DIRSRC})


target_link_libraries(${TARGET} src)
aux_source_directory(. DIRSRCS)
/include_directories(${PROJECT_SOURCE_DIR}/include)
add_library(src STATIC ${DIRSRCS})

CMake入门到精通实战