Cmake+vscode+C++
本文档资料大部分节选自bilibili xiaobing1016,支持原创
Linux开发基础
1.1编译过程
前言 :
- GCC 编译器支持编译 Go、Objective-C,Objective-C ++,Fortran,Ada,D 和 BRIG(HSAIL)
等程序; - Linux 开发C/C++ 一定要熟悉 GCC
- VSCode是通过调用GCC编译器来实现C/C++的编译工作的;
实际使用中:
- 使用 gcc 指令编译 C 代码
- 使用 g++指令编译 C++ 代码
- 预处理-Pre-Processing //.i文件
1 | # -E 选项指示编译器仅对输入文件进行预处理 |
- 编译-Compiling // .s文件
1 | # -S 编译选项告诉 g++ 在为 C++ 代码产生了汇编语言文件后停止编译 |
- 汇编-Assembling // .o文件
1 | # -c 选项告诉 g++ 仅把源代码编译为机器语言的目标代码 |
- 链接-Linking // bin文件
1 | # -o 编译选项来为将产生的可执行文件用指定的文件名 |
这四步等价于g++ test.cpp -o test
1.2**g++**重要编译参数
- -g 编译带调试信息的可执行文件
1 | # -g 选项告诉 GCC 产生能被 GNU 调试器GDB使用的调试信息,以调试程序。 |
- -O[n] 优化源代码
1 | ## 所谓优化,例如省略掉代码中从未使用过的变量、直接将常量表达式用结果值代替等等,这些操作会缩减目标文件所包含的代码量,提高最终生成的可执行文件的运行效率。 |
- -l 和 -L 指定库文件 | 指定库文件路径
1 | # -l参数(小写)就是用来指定程序要链接的库,-l参数紧接着就是库名 |
- -I 指定头文件搜索目录
1 | # -I include |
- -Wall 打印警告信息
1 | # 打印出gcc提供的警告信息 xiaobing |
- -w 关闭警告信息
1 | # 关闭所有警告信息 |
- -std=c++11 设置编译标准
1 | # 使用 c++11 标准编译 test.cpp |
- -o 指定输出文件名
1 | # 指定即将产生的文件名 |
- -D 定 义 宏
1 | 的时候定义宏 |
示例代码:
1 | // -Dname 定义宏name,默认定义内容为字符串“1” |
注:使用 man gcc 命令可以查看gcc英文使用手册,见下图
1.3生成库文件并编译
在 Linux 中,库文件分成静态库和共享库两种。静态库以.a 作为后缀名,共享库以.so 结尾。所有库都是一些函数打包后的集合,
差别在于静态库每次被调用都会生成一个副本,类似于提前拷贝代码到主程序,省时间,而共享(动态)库则只有一个副本,更省空间,每次只是链接这个副本。静态库最后都会被集成到可执行文件中,动态库不会。
链接静态库生成可执行文件①:
1 | ## 进入src目录下 |
链接动态库生成可执行文件②:
1 | ## 进入src目录下 |
PIC就是position independent code,不加fPIC编译出来的so,是要再加载时根据加载到的位置再次重定位,导致无法真正共享
运行可执行文件
先看当前目录结构
运行静态库可执行文件
1 | # 运行可执行文件 |
运行动态库可执行文件
1 | # 运行可执行文件,在这里我们的路径是src内 |
1.4GDB调试器
前言:
GDB(GNU Debugger)是一个用来调试****C/C++*程序的功能强大的*调试器,是Linux系统开C/C++最常用的调试器
程序员可以使用GDB来跟踪程序中的错误,从而减少程序员的工作量。
Linux 开发C/C++ 一定要熟悉 GDB
*VSCode是通过调用GDB调试器来实现*C/C++**的调试工作的;
Windows 系统中,常见的集成开发环境(IDE),如 VS、VC等,它们内部已经嵌套了相应的调试器
GDB****主要功能:
设置断点(断点可以是条件表达式)
使程序在指定的代码行上暂停执行,便于观察
单步执行程序,便于调试
查看程序中变量值的变化
动态改变程序的执行环境
分析崩溃程序产生的core文件
常用调试命令参数
调试开始:执行gdb [exefilename] ,进入gdb调试程序,其中exefilename为要调试的可执行文件名
1 | $(gdb)help(h) # 查看命令帮助,具体命令查询在gdb中输入help + 命令 |
Tips:
编译程序时需要加上-g,之后才能用gdb进行调试:gcc -g main.c -o main
回车键:重复上一命令
实战演示
首先进入文件中,输入set nu
可以显示行号,行号对于我们的GDB调试是至关重要的
然后需要输入g++ -g sum.cpp -o a_yes_g
,注意,没有加-g的话,后续进入gdb会提示无法找到debug系统,并且-g之后的文件大小也是比不加-g要大一倍多的
顺带一提ctrl + l
可以切屏,也就是只保留最后一行指令,把前面显示的都清除掉
进入调试
宇宙第一IDE
由于已经学过,这里仅保留新学到的一些东西
alt + 上/下
,将当前行的语句整体移位
\r为回车,物理意义的行开头,\n为文本的结尾标志
快捷键
功能 | 快捷键 | 功能 | 快捷键 |
---|---|---|---|
转到文件 / 其他常用操作 | Ctrl + P | 关闭当前文件 | Ctrl + W |
打开命令面板 | Ctrl + Shift + P | 当前行上移/下移 | Alt + Up/Down |
打开终端 | Ctrl +` | 变量统一重命名 | F2 |
关闭侧边栏 | Ctrl + B | 转到定义处 | F12 |
复制文本 | Ctrl+C | 粘贴文本 | Ctrl+V |
保存文件 | Ctrl+S | 撤销操作 | Ctrl+Z |
在 Ctrl+P 窗口下还可以:
直接输入文件名,跳转到文件
?
列出当前可执行的动作!
显示 Errors 或 Warnings ,也可以 Ctrl+Shift+M:
跳转到行数,也可以 Ctrl+G 直接进入@
跳转到 symbol (搜索变量或者函数),也可以 Ctrl+Shift+O 直接进入@
根据分类跳转 symbol ,查找属性或函数,也可以 Ctrl+Shift+O 后输入:进入#
根据名字查找 symbol ,也可以 Ctrl+T
快捷键:编辑器与窗口管理
打开一个新窗口: Ctrl+Shift+N
关闭窗口: Ctrl+Shift+W
同时打开多个编辑器(查看多个文件)
新建文件 Ctrl+N
文件之间切换 Ctrl+Tab
切出一个新的编辑器(最多 3 个) Ctrl+\ ,也可以按住 Ctrl 鼠标点击 Explorer 里的文件名
左中右 3 个编辑器的快捷键 Ctrl+1 Ctrl+2 Ctrl+3
3 个编辑器之间循环切换 Ctrl+
编辑器换位置, Ctrl+k 然后按 Left 或 Right
↓ 代码编辑相关的快捷键 ↓
快捷键:格式调整
代码行缩进 Ctrl+[ 、 Ctrl+]
Ctrl+C 、 Ctrl+V 复制或剪切当前行/当前选中内容
代码格式化: Shift+Alt+F ,或 Ctrl+Shift+P 后输入 format code
上下移动一行: Alt+Up 或 Alt+Down
向上向下复制一行: Shift+Alt+Up 或 Shift+Alt+Down
在当前行下边插入一行 Ctrl+Enter
在当前行上方插入一行 Ctrl+Shift+Enter
快捷键:光标相关
移动到行首: Home xiaobing
移动到行尾: End
移动到文件结尾: Ctrl+End
移动到文件开头: Ctrl+Home
移动到定义处: F12
定义处缩略图:只看一眼而不跳转过去 Alt+F12
移动到后半个括号:Ctrl+Shift+]
选择从光标到行尾: Shift+End
选择从行首到光标处: Shift+Home
删除光标右侧的所有字: Ctrl+Delete
扩展/缩小选取范围:Shift+Alt+Left 和 Shift+Alt+Right
多行编辑(列编辑): Alt+Shift+鼠标左键 , Ctrl+Alt+Down/Up
同时选中所有匹配:Ctrl+Shift+L
Ctrl+D 下一个匹配的也被选中 (在 sublime 中是删除当前行,后面自定义快键键中,设置与
Ctrl+Shift+K 互换了)
- 回退上一个光标操作: Ctrl+U
快捷键:重构代码
找到所有的引用: Shift+F12
同时修改本文件中所有匹配的: Ctrl+F12
重命名:比如要修改一个方法名,可以选中后按 F2 ,输入新的名字,回车,会发现所有的文件都修改了
跳转到下一个 Error 或 Warning :当有多个错误时可以按 F8 逐个跳转
查看 diff : 在 explorer 里选择文件右键 Set file to compare ,然后需要对比的文件上右键选择 Compare with file_name_you_chose
快捷键:查找替换
查 找 Ctrl+F
查找替换 Ctrl+H
整个文件夹中查找 Ctrl+Shift+F
快捷键:显示相关
全屏: F11
zoomIn/zoomOut: Ctrl +/-
侧边栏显/隐: Ctrl+B
显示资源管理器 Ctrl+Shift+E
显示搜索 Ctrl+Shift+F
显 示 Git Ctrl+Shift+G
显 示 Debug Ctrl+Shift+D
显 示 Output Ctrl+Shift+U
Cmake
前言:
CMake是一个跨平台的安装编译工具,可以用简单的语句来描述所有平台的安装(编译过程)。
CMake可以说已经成为大部分C++开源项目标配
CMake是Gcc辅助工具,CMake定义了一系列编译规则。Gcc在这些编译规则下去进行编译
3.1 Cross-platform development
Let’s assume you have some cross-platform project with C++ code shared along different
platforms/IDEs. Say you use Visual Studio on Windows, Xcode on OSX and Makefile for Linux:
What you will do if you want to add new bar.cpp source file? You have to add it to every tool you use:
To keep the environment consistent you have to do the similar update several times. And the most important thing is that you have to do it manually (arrow marked with a red color on the diagram in this case). Of course such approach is error prone and not flexible.
CMake solve this design flaw by adding extra step to development process. You can describe your project in CMakeLists.txt file and use C Make to generate tools you currently interested in using cross-platform C Make code:
总之,Cmake类似于java的JDBC,是一个中间层,将不同平台的build tools统一起来,实现跨平台,我们需要修改什么只需要改一个文件就行了,不用像以前那样将该项目用到的每一个平台的文件都进行改动。
3.2 语法特性介绍
基本语法格式:指令(参数 1 参数 2….)
参数使用括弧括起
参数之间使用空格或分号分开
指令是大小写无关的,参数和变量是大小写相关的
变量使用${}方式取值,但是在 IF 控制语句中是直接使用变量名
3.3 重要指令和CMake常用变量
3.3.1 重要指令
cmake_minimum_required - 指定CMake的最小版本要求
- 语法: cmake_minimum_required(VERSION versionNumber [FATAL_ERROR]
1 | # CMake最小版本要求为2.8.3 |
project - 定义工程名称,并可指定工程支持的语言
- 语法: project(projectname [CXX] [C] [ Java])
1 | # 指定工程名为HELLOWORLD |
set - 显式的定义变量
- 语法:set(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
1 | # 定义SRC变量,其值为sayhello.cpp hello.cpp |
include_directories - 向工程添加多个特定的头文件搜索路径 —>相当于指定g++编译器的-I参数
- 语法: include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 …)
1 | # 将/usr/include/myincludefolder 和 ./include 添加到头文件搜索路径 |
link_directories - 向工程添加多个特定的库文件搜索路径 —>相当于指定g++编译器的-L参数
- 语法: link_directories(dir1 dir2 …)
1 | # 将/usr/lib/mylibfolder 和 ./lib 添加到库文件搜索路径 |
add_library - 生成库文件
- 语 法 : add_library(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL] source1 source2 … sourceN)
1 | # 通过变量 SRC 生成 libhello.so 共享库 |
add_executable - 生成可执行文件
语法:add_executable(exename source1 source2 … sourceN)
1 | # 编译main.cpp生成可执行文件main |
target_link_libraries - 为 target 添加需要链接的共享库 —>相同于指定g++编译器-l参数
- 语法: target_link_libraries(target library1<debug | optimized> library2…)
1 | # 将hello动态库文件链接到可执行文件main |
add_subdirectory - 向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置
- 语法: add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
1 | # 添加src子目录,src中需有一个CMakeLists.txt |
aux_source_directory - 发现一个目录下所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表
- 语法: aux_source_directory(dir VARIABLE)
1 | # 定义SRC变量,其值为当前目录下所有的源代码文件 |
3.3.2CMake常用变量
CMAKE_C_FLAGS gcc编译选项
CMAKE_CXX_FLAGS g++编译选项
1 | # 在CMAKE_CXX_FLAGS编译选项后追加-std=c++11 |
CMAKE_BUILD_TYPE 编译类型(Debug, Release)
1 | # 设定编译类型为debug,调试时需要选择debug |
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:库文件输出的存放路径*
3.4 CMake 编译工程
CMake目录结构:项目主目录存在一个CMakeLists.txt文件
两种方式设置编译规则:
包含源文件的子文件夹包含CMakeLists.txt文件,主目录的CMakeLists.txt通过add_subdirectory 添加子目录即可;
包含源文件的子文件夹未包含CMakeLists.txt文件,子目录编译规则体现在主目录的CMakeLists.txt中;
3.4.1 编译流程
在 linux 平台下使用 CMake **构建C/C++**工程的流程如下:
手动编写 CMakeLists.txt。
执行命令 cmake PATH 生成 Makefile ( PATH 是顶层CMakeLists.txt 所在的目录 )。
执行命令 make 进行编译。
3.4.2 两种构建方式
内部构建(in-source build):不推荐使用
- 内部构建会在同级目录下产生一大堆中间文件,这些中间文件并不是我们最终所需要的,和工程源 文件放在一起会显得杂乱无章。
1 | ## 内部构建 |
外部构建(out-of-source build):推荐使用
- 将编译输出文件与源文件放到不同目录中
1 | ## 外部构建 |
士兵突击开发实例演示
需求:
士兵 许三多 有一把枪,叫做 AK47
士兵 可以 开火
士兵 可以 给枪装填子弹
枪 能够 发射 子弹
枪 能够 装填子弹 —— 增加子弹数量
本次任务放在7文件夹运行,下面是7文件夹的目录排版结构图
一共两个头文件Gun.h
,Solider.h
,两个cpp文件Gun.cpp
, Solider.cpp
CMakeLists.txt
存放Cmake指令,main.cpp运行程序,build
文件夹存放CMake指令生成的东西
include
1 | // Gun.h |
1 | // Solider.h |
src
1 | // Gun.cpp |
1 | // Solider.cpp |
CMakeLists.txt
1 | cmake_minimum_required(VERSION 2.8) |
main.cpp
1 |
|
进入build中,
1 | cmake .. |
1 | this is a test string... |
Debugger
要学会vscode的Debugger一定要会配置当前工程文件夹中,launch.json和tasks.json,实现自动化debug
这里给出对应配置
1 | // launch.json |
1 | // tasks.json |