Cmake的使用

Cmake的使用vscodeCmake简介Cmake语法重要指令和CMake常用变量重要指令CMake常用变量CMake编译工程CMake代码实践CMake完整项目调试步骤launch.json和tasks.jsonCmake简介简介CMake是一个跨平台的安装编译工具,可以用简单的语句来描述所有平台的安装(编译过程)。CMake可以说已经成为大部分C++开源项目标配传统的C++文件不通系统对应不通的编译比如 当添加一个文件的时候需要对不通操作系统中的工程进行修改有了Cmake以后,只需要编写

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

Cmake简介

简介

  • CMake是一个跨平台的安装编译工具,可以用简单的语句来描述所有平台的安装(编译过程)。

  • CMake可以说已经成为大部分C++开源项目标配

传统的C++文件不通系统对应不通的编译
在这里插入图片描述
比如 当添加一个文件的时候需要对不通操作系统中的工程进行修改
在这里插入图片描述
有了Cmake以后,只需要编写一个CmakeLists文件就可以对应将一个C++工程不通操作系统
在这里插入图片描述
当新添加一个文件的时候只需要更改对应的CmakeLists即可
在这里插入图片描述

Cmake语法

基本语法格式:指令(参数 1 参数 2…)

  • 参数使用括弧括起
  • 参数之间使用空格或分号分开

指令是大小写无关的,参数和变量是大小写相关的

set(HELLO hello.cpp)
add_executable(hello main.cpp hello.cpp)
ADD_EXECUTABLE(hello main.cpp ${HELLO})

变量使用${}方式取值,但是在 IF 控制语句中是直接使用变量名

重要指令和CMake常用变量

重要指令

cmake_minimum_required – 指定CMake的最小版本要求

# CMake最小版本要求为2.8.3
cmake_minimum_required(VERSION 2.8.3)
  • 语法:cmake_minimum_required(VERSION versionNumber [FATAL_ERROR])

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

# 指定工程名为HELLOWORLD
project(HELLOWORLD)
  • 语法:project(projectname [CXX] [C] [Java])

set – 显式的定义变量

# 定义SRC变量,其值为main.cpp hello.cpp
set(SRC sayhello.cpp hello.cpp)
  • 语法:set(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])

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

# 将/usr/include/myincludefolder 和 ./include 添加到头文件搜索路径
include_directories(/usr/include/myincludefolder ./include)
  • 语法:include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 …)

link_directories – 向工程添加多个特定的库文件搜索路径 —>相当于指定g++编译器的-L参数

# 将/usr/lib/mylibfolder 和 ./lib 添加到库文件搜索路径
link_directories(/usr/lib/mylibfolder ./lib)
  • 语法:link_directories(dir1 dir2 …)

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 – 添加编译参数

1# 添加编译参数 -Wall -std=c++11
2add_compile_options(-Wall -std=c++11 -O2)
  • 语法:add_compile_options(

add_executable – 生成可执行文件

# 编译main.cpp生成可执行文件main
add_executable(main main.cpp)
  • 语法:add_executable(exename source1 source2 … sourceN)

target_link_libraries – 为 target 添加需要链接的共享库 —>相同于指定g++编译器-l参数,用在add_executable之后(link_library用在add_excutable之前)

# 将hello动态库文件链接到可执行文件main
target_link_libraries(main hello)
  • 语法:target_link_libraries(target library1library2…)

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

# 添加src子目录,src中需有一个CMakeLists.txt
add_subdirectory(src)
  • 语法:add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

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

# 定义SRC变量,其值为当前目录下所有的源代码文件
aux_source_directory(. SRC)
# 编译SRC变量所代表的源代码文件,生成main可执行文件
add_executable(main ${SRC})
  • 语法:aux_source_directory(dir VARIABLE)

CMake常用变量

CMAKE_C_FLAGS gcc编译选项
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_BINARY_DIR
PROJECT_BINARY_DIR
__BINARY_DIR

这三个变量指代的内容是一致的。
如果是 in source build,指的就是工程顶层目录。
如果是 out-of-source 编译,指的是工程编译发生的目录。
PROJECT_BINARY_DIR 跟其他指令稍有区别,不过现在,你可以理解为他们是一致的。

CMAKE_SOURCE_DIR
PROJECT_SOURCE_DIR
__SOURCE_DIR

这三个变量指代的内容是一致的,不论采用何种编译方式,都是工程顶层目录。
也就是在 in source build时,他跟 CMAKE_BINARY_DIR 等变量一致。
PROJECT_SOURCE_DIR 跟其他指令稍有区别,现在,你可以理解为他们是一致的。

CMAKE_C_COMPILER:指定C编译器

CMAKE_CXX_COMPILER:指定C++编译器

EXECUTABLE_OUTPUT_PATH:可执行文件输出的存放路径

LIBRARY_OUTPUT_PATH:库文件输出的存放路径

CMake编译工程

CMake目录结构:项目主目录存在一个CMakeLists.txt文件

两种方式设置编译规则:

  • 包含源文件的子文件夹包含CMakeLists.txt文件,主目录的CMakeLists.txt通过add_subdirectory添加子目录即可;
  • 包含源文件的子文件夹未包含CMakeLists.txt文件,子目录编译规则体现在主目录的CMakeLists.txt中;

编译流程

在 linux 平台下使用 CMake 构建C/C++工程的流程如下:

手动编写 CmakeLists.txt。
执行命令 cmake PATH生成 Makefile ( PATH 是顶层CMakeLists.txt 所在的目录 )。
执行命令make 进行编译。
# important tips
.          # 表示当前目录
./         # 表示当前目录

..      # 表示上级目录
../     # 表示上级目录

两种构建方式
内部构建(in-source build):不推荐使用

内部构建会在同级目录下产生一大堆中间文件,这些中间文件并不是我们最终所需要的,和工程源文件放在一起会显得杂乱无章。

## 内部构建

# 在当前目录下,编译本目录的CMakeLists.txt,生成Makefile和其他文件
cmake .
# 执行make命令,生成target
make

外部构建(out-of-source build):推荐使用

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

## 外部构建
 
# 1. 在当前目录下,创建build文件夹
mkdir build 

# 2. 进入到build文件夹
cd build

# 3. 编译上级目录的CMakeLists.txt,生成Makefile和其他文件
cmake ..

# 4. 执行make命令,生成target
make

CMake代码实践

针对第五章写的两个小项目来写对应的CMakeLists.txt

最小CMake工程

# Set the minimum version of CMake that can be used
cmake_minimum_required(VERSION 3.0)

# Set the project name
project (HELLO)

# Add an executable
add_executable(hello_cmake main.cpp)

多目录工程 – 直接编译

cmake_minimum_required(VERSION 3.0)

project(HELLOWORLD)

#对应 -Iinclude
include_directories(include)

#main_cmake 是输出文件名
add_executable(main_cmake main.cpp src/swap.cpp)

多目录工程 – 生成库编译

# Set the minimum version of CMake that can be used
cmake_minimum_required(VERSION 3.0)
 
#project name 
project(SWAP_LIBRARY)
 
#add compile options
add_compile_options("-Wall -std=c++11")
 
#set CMAKE_BUILD_TYPE
set( CMAKE_BUILD_TYPE Debug ) 

# set output binary path 
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

############################################################
# Create a library
############################################################

#Generate the static library from the library sources
add_library( swap_library STATIC src/Swap.cpp )

target_include_directories( swap_lib PUBLIC ${PROJECT_SOURCE_DIR}/include )

############################################################
# Create an executable
############################################################

# Add an executable with the above sources
add_executable( swap_01 main.cpp )

# link the new swap_01 target with the swap_lib target
target_link_libraries( swap_01 swap_liby )

CMake完整项目

.
│  CMakeLists.txt
│  main.cpp
│  myexe.exe
│
├─build
├─include
│      Gun.h
│      Solider.h
│
└─src
        Gun.cpp
        Solider.cpp

main.cpp

#include "Gun.h"
#include "Solider.h"

void test(){ 
   
    Solider solider("xusanduo");
    solider.addGun(new Gun("AK47"));
    solider.addBulletToGun(20);
    solider.fire();
}
int main(){ 
   
    test();
    return 0;
}

Gun.h

#pragma once
#include<string>

class Gun{ 
   
public:
    Gun(std::string type){ 
   
        this->_bullet_count = 0;
        this->_type = type;
    }
    void addBullet(int bullet_num);
    bool shoot();
private:
    int _bullet_count;
    std::string _type;
};

Solider.h

#pragma once

#include<string>
#include "Gun.h"
class Solider{ 
   
public:
    Solider(std::string name);
    void addBulletToGun(int num);
    bool fire();
    void addGun(Gun *ptr_gun);
    ~Solider();
private:
    std::string _name;
    Gun * _ptr_gun;
};

Gun.cpp

#include "Gun.h"
#include<iostream>
using namespace std;

void Gun::addBullet(int bullet_num){ 
   
    this->_bullet_count += bullet_num;
}

bool Gun::shoot(){ 
   
    if (this->_bullet_count <= 0)
    { 
   
        cout << "there is no bullet !" << endl;
        return false;
    }
    this->_bullet_count -= 1;
    cout << "shoot successfully" << endl;
    return true;
}

Solider.cpp

#include "Solider.h"

Solider::Solider(std::string name){ 
   
    this->_name = name;
    this->_ptr_gun = nullptr;
}

void Solider::addGun(Gun *ptr_gun){ 
   
    this->_ptr_gun = ptr_gun;
}

void Solider::addBulletToGun(int num){ 
   
    this->_ptr_gun->addBullet(num);
}

bool Solider::fire(){ 
   
    this->_ptr_gun->shoot();
    return true;
}
Solider::~Solider(){ 
   
    if(this->_ptr_gun == nullptr){ 
   
        return;
    }
    delete this->_ptr_gun;
    this->_ptr_gun = nullptr;
}
  1. 命令行编译
g++ .\main.cpp .\src\Gun.cpp .\src\Solider.cpp -Iinclude -o myexe
  1. cmake编译
    CMakeLists.txt文件
cmake_minimum_required(VERSION 3.0)

project(SOLIDER)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")

set(CMAKE_BUILD_TYPE Debug)

include_directories(include)
#或者include_directories(${CMAKE_SOURCE_DIR}/include)

add_executable(myexe main.cpp src/Gun.cpp src/Solider.cpp)

编译

cd build

cmake ..

make

当更改文件后 直接用make命令构建即可 make会只编译修改的文件

调试步骤launch.json和tasks.json

{ 
   
    "version": "0.2.0",
    "configurations": [
        { 
   
            "name": "(gdb) 启动",
            "type": "cppdbg",
            "request": "launch",
            "program": "输入程序名称,例如 ${workspaceFolder}/a.exe",   //可执行文件
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",    //进入当前工作目录
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "miDebuggerPath": "/path/to/gdb",   //gdb路径
            "setupCommands": [
                { 
   
                    "description": "为 gdb 启用整齐打印",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "build"    //调试之前执行的任务 一般是生成exe文件
        }
    ]
}

tasks.json

{ 
   
    "version": "2.0.0",
    "options": { 
   
        "cwd": "${workspaceFolder}/build"	#进入build目录
    },
    "tasks": [
        { 
   
            "type": "shell",	#第一个task
            "label": "cmake",
            "command": "cmake",
            "args": [
                ".."
            ]
        },
        { 
   
            "label": "make",	#第二个task
            "group": { 
   
                "kind": "build",
                "isDefault": true
            },
            "command": "mingw32-make.exe",	#win10下是mingw32.make linux下是make
            "args": [

            ]
        },
        { 
   
            "label": "Build",	#task任务名 和launch.json中的preLaunchTask对应
            "dependsOrder": "sequence",	#顺序执行task任务
            "dependsOn":[
                "cmake",
                "make"
            ]
        }
    ]
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/168517.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 哈佛大学《幸福课》笔记

    哈佛大学《幸福课》笔记前述整个九月份以来一直在找工作,工作签好后有各种杂事需要做。当然,更主要的原因是自己懒,所以博客有一个多月没有更新了。今天将自己在大二暑假跟着视频学过的哈佛大学的《幸福课》整理成一篇文章,希望自己以后能够克服困难,多阅读,多学习,多写作,每天能够过的开心充实有意义。《幸福课》笔记(Tal的幸福秘籍)1、你问的问题经常会决定你所做的探索,问题会带来探索。2、信念创造现实,如何理解

    2022年7月25日
    10
  • MFC应用程序——标签控件_IP控件_时间控件_List Control控件_Tree Control控件_命令按钮_列表框_组合框_图片_滚动控件「建议收藏」

    MFC应用程序——标签控件_IP控件_时间控件_List Control控件_Tree Control控件_命令按钮_列表框_组合框_图片_滚动控件「建议收藏」标签控件应用【Tab Control 标签控件】 标签控件也比较常见。它可以把多个页面集成到一个窗口中, 每个页面对应一个标签,用户点击某个标签时,它对应的页 面就会显示。 使用标签控件我们可以同时加载多个有关联的页面,用 户只需点击标签即可实现页面切换,方便灵活的进行操作。 每个标签除了可以显示标签文本,还可以显示图标。 标签控件相当于是一个页面的容器,可以容纳多个对话 框,而且一般也只容纳对…

    2022年8月18日
    6
  • 面试题:MyBatis二级缓存[通俗易懂]

    面试题:MyBatis二级缓存[通俗易懂]①、一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。②、二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。写这篇文章的初衷:MyBatis二级缓存在实际工作中一般都不会使用,但是就有有些面试官一直问这个问题,所

    2025年12月3日
    4
  • sntp 校时问题

    sntp 校时问题1 背景由于项目中的数据对时间比较敏感 目前常常出现校时问题 导致时间偏差 出现曲线数据丢失和曲线数据重复等问题 因此对 sntp 源码进行深入分析 要了解 SNTP 首先需要了解 NTP 协议 SNTP 是 NTP 的子集 简化了 NTP 的许多算法和步骤 得到了效率 但时间的精度不如 NTP 可是对于民用时间来说足够了 大概最多差距几秒的样子 NTP NetworkTimeP 网络时间协议 是由 RFC1305 定义的时间同步协议 用来在分布式时间服务器和客户端之间进行时间同步 NTP 基于 UDP 报

    2025年6月20日
    4
  • 电阻色环表色环电阻识别表_电阻的色环识别方法

    电阻色环表色环电阻识别表_电阻的色环识别方法色环电阻色环电阻是电子电路中最常用的电子元件,色环电阻就是在普通的电阻封装上涂上不一样的颜色的色环,用来区分电阻的阻值。保证在安装电阻时不管从什么方向来安装,都可以清楚的读出它的阻值。色环电阻的基本单位有:欧姆(Ω)、千欧(KΩ)、兆欧(MΩ)。1兆欧(MΩ)=1000千欧(KΩ)=1000000欧(Ω)。平常使用的色环电阻可以分为四环和五环,通常用四环。其中四环电阻前二环为数字,第三环表

    2025年6月11日
    5
  • SpringCloud笔记:配置Eurake注册中心与高可用集群

    SpringCloud笔记:配置Eurake注册中心与高可用集群SpringCloud是目前非常流行的一个微服务框架,基于springboot,由多个独立模块集合而成。每个模块既可以是一个服务项目,比如会员服务,订单服务等,也可以是公用的API给其他模块使用。可以理解为把一个大的项目拆分成很多小的模块,这些模块通过httpclient+json的形式完成服务之间的通讯,而且每个模块都有自己独立的业务和部署,使得粒度更加精细。五大组件如下:服务注册与发现——…

    2022年5月30日
    59

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号