Linux C++ VsCode多文件编译运行
大型工程一般都使用cmake编译,cmake可以实现跨平台开发,同时,修改一个文件时,只需对该文件进行编译链接就可以了,不需要对其他未修改文件编译,可以节约时间。本文章重点介绍使用cmake和make进行C++开发。
使用VsCode插件C/C++ Program Generator进行开发可以查看这篇博客:https://www.cnblogs.com/Fight-go/p/15717719.html
本篇博客以一个简单的交换两个数的类Swap的程序为样例,交换两个数的程序的文件结构如下:
build文件夹用来存放Cmake产生的中间文件,out用来存放输出的可执行文件。
样例的源代码如下:
#pragma once
#include <iostream>
class swap
{
private:
int _a;
int _b;
public:
swap(int a, int b) : _a(a), _b(b){ }
void run();
void printInfo();
};
#include "swap.h"
void swap::run()
{
int temp;
temp = _a;
_a = _b;
_b = temp;
}
void swap::printInfo()
{
std::cout << "_a = " << _a << std::endl;
std::cout << "_b = " << _b << std::endl;
}
#include "swap.h"
int main()
{
swap myswap123(10, 20);
std::cout << "Before swap:" << std::endl;
myswap123.printInfo();
myswap123.run();
std::cout << "After swap:" << std::endl;
myswap123.printInfo();
return 0;
}
1. CMAKE重要指令和常用变量
1.1 重要指令
- cmake_minimum_required -指定Cmake的最小版本要求
- 语法:cmake_minimum_required(VERSION versionNumber[FATAL_ERROR])
# CMake最小版本要求3.22.1
cmake_minimum_required (VERSION 3.22.1)
- project -定义工程名称,并指定工程支持的语言
- 语法:project(projectname[CXX][C][Java])
# 指定工程名为HELLOWORLD
project(HELLOWORLD)
- set -显式的定义变量
- 语法:set(VAR[VALUE][CACHE TYPE DOCSTRING [FORCE]])
# 定义SRC变量,其值为main.cpp hello.cpp
set(SRC main.cpp hello.cpp)
- include_directories -向工程添加多个特定的头文件搜索路径-->相当与g++的-I参数
- 语法:include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2)
# 将/usr/include/myincludefolder和./inculde添加到头文件搜索路径
include_directories(/usr/include/myincludefolder ./inculde)
- link_directories -向工程添加多个特定的库文件搜索路径-->相当与g++的-L参数
- 语法:link_directories(dir1 dir2 ...)
# 将/usr/include/myincludefolder和./inculde添加到库文件搜索路径
link_directories(/usr/include/myincludefolder ./inculde)
- add_library -生成库文件
- 语法:add_library(libname[SHARED|STATIC|MODULE][EXCULDE_FROM_ALL]source1 source2 ...sourceN)
# 通过变量 SRC 生成 libhello.so 共享库
add_library(hello SHARED ${SRC})
- add_compile_options -添加编译参数
- 语法:add_compile_options(<option>...)
# 添加编译参数
add_compile_options(-Wall -std=c++11 -O2)
- add_executable -生成可执行文件
- 语法:add_executable(exname source1 source2...sourceN)
# 编译main.cpp生成可执行文件main
add_executable(main main.cpp)
- target_link_libraries -为target添加需要链接的共享库--->相当于指定g++编译-l参数
- 语法:target_link_libraries(target library1<debug|optimized> library2...)
# 将hello动态库文件链接到可执行文件main
target_link_libraries(main hello)
- add_subdirectory -向当前工程目录添加存放源文件的子目录,并可以制定中间二进制和目标二进制存放的位置
- 语法:add_subdirectory(source_dir[binary_dir][EXCLUDE_FROM_ALL])
# 通过变量 SRC子目录,src中需要一个CMakeLists.txt
add_subdirectory(src)
- aux_source_directory -发现一个目录下所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表
- 语法:aux_source_directory(dir VARIABLE)
# 定义SRC变量,其值为当前目录下所有的源代码文件
aux_source_directory(. SRC)
# 编译SRC变量所代码的源代码文件,生成main可执行文件
add_excuatable(main ${SRC})
1.2 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
<projectname>_BINARY_DIR
1.这三个变量指代的内容是一致的。
2.如果是in source build,指的就是工程顶层目录
3.如果是out-of-source编译,指的是工程编译发生的目录
4.PROJECT_BINARY_DIR跟其他指令稍有区别,不过现在,你可以理解为他们是一致的。 -
CMAKE_SOURCE_DIR
PROJECT_SOURCE_DIR
<projectname>_SOURCE_DIR
1.这三个变量指代的内容是一致的,不论采用何种编译方式,都是更成顶层目录。
2.也就是在in source build时,它跟 CMAKE_BINARY_DIR等变量一致
3.如果是out-of-source编译,指的是工程编译发生的目录
4.PROJECT_SOURCE_DIR跟其他指令稍有区别,现在,你可以理解为他们是一致的。 -
CMAKE_C_COMPILER: 指定C编译器
-
CMAKE_CXX_COMPILER: 指定CXX编译器
-
EXCUTABLE_OUTPUT_PATH: 可执行文件输出的存放路径
-
LIBRARY_OUTPUT_PATH: 库文件输出的存放路径
2. 编写CMakeLists.txt文件
首先,编写CmakeLists.txt文件,在工作区文件夹创建CmakeLists.txt,编写如下代码:
# 最小版本,可以通过cmake --version查看
cmake_minimum_required(VERSION 3.22.1)
# 项目名称,建议大写
project(SWAP)
# 搜索自定义的头文件目录,可以使用绝对路径 ${CMAKE_SOURCE_DIR}/include
include_directories(include)
# 设置编译时的选项,如O2优化,开启警告,使用的C++标准等
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
# 调试时使用该项
set(CMAKE_BUILD_TYPE Debug)
# 生成可执行文件命令,第一个参数是生成可执行文件的名称,后面的参数是源文件代码
add_executable(main main.cpp src/swap.cpp)
# 指定生成可执行文件的输出目录
set(EXECUTABLE_OUTPUT_PATH "../out")
编写完成之后,可以使用终端命令,检验CMakeLists文件编写是否正确,在终端进入bulid目录,输入以下指令:
cmake .. # 之所以使用cmake ..是因为CMakeLists.txt在build目录的上级
make
../out/main # 运行生成的可执行文件
运行结果如下:
可以看到运行成功。
3. 配置launch.json文件和task.json文件
launch.json文件完成的是调试工作,有两个参数很关键,分别是
program和preLaunchTask,两个参数分别代表了调试运行程序的名称和在调试运行前执行的任务。该两项需要修改,如图所示:
launch.json的代码如下:
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "g++ - Build and debug active file",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/out/${fileBasenameNoExtension}",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "Build",
"miDebuggerPath": "/usr/bin/gdb"
}
]
}
task.json执行的是编译产生可执行文件的工作,其代码如下:
{
"version":"2.0.0",
"options": {
"cwd": "${workspaceFolder}/build"
},
"tasks": [
{
"type": "shell", // open the shell 打开终端
"label": "cmake",
// 执行命令 cmake ..
"command": "cmake",
"args": [
".."
]
},
{
"label": "make",
"group": "build",
"command": "make", // 执行命令make
"args": [
]
},
{
"label": "Build",
"dependsOrder": "sequence",
"dependsOn":[
"cmake",
"make"
]
}
],
}
配置好两个文件就可以按F5调试运行了,运行结果和之前一样,至此使用cmake和vscode编译运行多文件C++程序完成。