文章目录
开发环境搭建
安装VScode和GCC编译器。
项目文件夹
一般一个项目中应该包含
include文件夹------用于保存头文件
src文件夹------用于保存源文件
GCC编译器
GCC编译器支持编译go、c、c++等语言。vscode就是通过调用GCC编译器来实现c/c++的编译工作的。
在使用过程中,
使用gcc指令编译c代码;
使用g++指令编译c++代码。
编译过程
1.预处理
在此阶段编译器会处理以"#"开头的预处理指令,如#include、#define 等;
处理后的文件通常会将头文件的内容替换到 #include 指令所在的位置,并且会展开 #define 宏定义。
cpp
# -E 选项指示编译器仅对输入文件进行预处理
g++ -E test.cpp -o test.i //.i文件
2.编译
在这个阶段,预处理后的源代码被翻译成汇编代码。
cpp
# -S 编译选项告诉 g++ 在为 C++ 代码产生了汇编语言文件后停止编译
# g++ 产生的汇编语言文件的缺省扩展名是 .s
g++ -S test.i -o test.s
3.汇编
汇编器将汇编代码转换为二进制目标文件,汇编器将汇编代码转换为机器指令,并生成目标文件,目标文件中包含了机器指令、符号表、重定位信息和其他元数据。
cpp
# -c 选项告诉 g++ 仅把源代码编译为机器语言的目标代码
# 缺省时 g++ 建立的目标代码文件有一个 .o 的扩展名。
g++ -c test.s -o test.o
4.链接
将所有的目标文件以及可能的库文件链接在一起形成最终的可执行文件。链接器将各个目标文件中的符号引用解析为实际的内存地址,并且将程序所需要的库文件链接到最终的可执行文件中。
cpp
# -o 编译选项来为将产生的可执行文件用指定输出路径与文件名
g++ test.o -o test
g++的重要编译参数
- -g 编译带调试信息的可执行文件
cpp
# -g 选项告诉 GCC 产生能被 GNU 调试器GDB使用的调试信息,以调试程序。
# 产生带调试信息的可执行文件test
g++ -g test.cpp
- -O[n] 优化源代码
-O2 较常使用。
cpp
## 所谓优化,例如省略掉代码中从未使用过的变量、直接将常量表达式用结果值代替等等,这些操作
会缩减目标文件所包含的代码量,提高最终生成的可执行文件的运行效率。
# -O 选项告诉 g++ 对源代码进行基本优化。这些优化在大多数情况下都会使程序执行的更快。 -O2
选项告诉 g++ 产生尽可能小和尽可能快的代码。 如-O2,-O3,-On(n 常为0--3)
# -O 同时减小代码的长度和执行时间,其效果等价于-O1
# -O0 表示不做优化
# -O1 为默认优化
# -O2 除了完成-O1的优化之外,还进行一些额外的调整工作,如指令调整等。
# -O3 则包括循环展开和其他一些与处理特性相关的优化工作。
# 选项将使编译的速度比使用 -O 时慢, 但通常产生的代码执行速度会更快。
# 使用 -O2优化源代码,并输出可执行文件
g++ -O2 test.cpp
- -l|-L 指定库文件|库文件路径
cpp
# -l参数(小写)就是用来指定程序要链接的库,-l参数紧接着就是库名
# 在/lib和/usr/lib和/usr/local/lib里的库直接用-l参数就能链接 LINUX系统下的
# 链接glog库
g++ -lglog test.cpp
# 如果库文件没放在上面三个目录里,需要使用-L参数(大写)指定库文件所在目录
# -L参数跟着的是库文件所在的目录名
# 链接mytest库,libmytest.so在/home/bing/mytestlibfolder目录下
g++ -L/home/bing/mytestlibfolder -lmytest test.cpp
- -I 指定头文件搜索目录
cpp
# -I
# /usr/include目录一般是不用指定的,gcc知道去那里找,但 是如果头文件不在/usr/icnclude
里我们就要用-I参数指定了,比如头文件放在/myinclude目录里,那编译命令行就要加上
I/myinclude 参数了,如果不加你会得到一个"xxxx.h: No such file or directory"的错
误。-I参数可以用相对路径,比如头文件在当前 目录,可以用-I.来指定。上面我们提到的--cflags参
数就是用来生成-I参数的。
g++ -I/myinclude test.cpp
- -Wall 打印警告信息
cpp
# 打印出gcc提供的警告信息
g++ -Wall test.cpp
- -std=c++11 设置编译编译标准
cpp
# 使用 c++11 标准编译 test.cpp
g++ -std=c++11 test.cpp
- -o 指定输出文件路径与文件名
cpp
# 指定即将产生的文件名
# 指定输出可执行文件名为test
g++ test.cpp -o test
CMake
cmake是一个跨平台的安装编译工具,可以用简单的语句来描述所有平台的编译过程。
语法特性
基本语法格式:指令(参数1 参数2......)
参数使用括号括起来;
参数之间使用空格或者分号分开;
指令是大小写无关的,参数和变量是大小写相关的
bash
set(HELLO hello.cpp)
add_executable(hello main.cpp hello.cpp)
ADD_EXECUTABLE(hello main.cpp ${HELLO})
变量使用 ${} 方式取值。
重要指令
cmake_minimum_required - 指定CMake的最低版本要求
语法: cmake_minimum_required(VERSION versionNumber [FATAL_ERROR])
bash
# CMake最小版本要求为2.8.3
cmake_minimum_required(VERSION 2.8.3)
project - 定义工程名称,并可指定工程支持的语言
语法: : project(projectname [CXX] [C] [Java])
bash
# 指定工程名为HELLOWORLD
project(HELLOWORLD)
**set - 显式的定义变量
语法:set(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
bash
# 定义SRC变量,其值为sayhello.cpp hello.cpp
set(SRC sayhello.cpp hello.cpp)
include_directories - 向工程添加多个特定的头文件搜索路径 --->相当于指定g++编译器的-I参数
语法: include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 ...)
bash
# 将/usr/include/myincludefolder 和 ./include 添加到头文件搜索路径
include_directories(/usr/include/myincludefolder ./include)
add_compile_options - 添加编译参数
语法:add_compile_options()
bash
# 添加编译参数 -Wall -std=c++11 -O2
add_compile_options(-Wall -std=c++11 -O2)
link_directories - 向工程添加多个特定的库文件搜索路径 --->相当于指定g++编译器的-L参数
语法: link_directories(dir1 dir2 ...)
bash
# 将/usr/lib/mylibfolder 和 ./lib 添加到库文件搜索路径
link_directories(/usr/lib/mylibfolder ./lib)
add_library - 生成库文件
语法: add_library(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL]
source1 source2 ... sourceN)
bash
# 通过变量 SRC 生成 libhello.so 共享库
add_library(hello SHARED ${SRC})
add_executable - 生成可执行文件
语法:add_executable(exename source1 source2 ... sourceN)
bash
# 编译main.cpp生成可执行文件main
add_executable(main main.cpp)
target_link_libraries - 为 target 添加需要链接的共享库 --->相同于指定g++编译器-l参数
语法: target_link_libraries(target library1<debug | optimized> library2...)
bash
# 将hello动态库文件链接到可执行文件main
target_link_libraries(main hello)
aux_source_directory - 发现一个目录下所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表
语法: aux_source_directory(dir VARIABLE)
bash
# 定义SRC变量,其值为当前目录下所有的源代码文件
aux_source_directory(. SRC)
# 编译SRC变量所代表的源代码文件,生成main可执行文件
add_executable(main ${SRC})
add_subdirectory - 向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置
语法: add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
bash
# 添加src子目录,src中需有一个CMakeLists.txt
add_subdirectory(src)
以下为一个CMakeLists.txt的基本模板
bash
# 指定最低版本
cmake_minimum_required(VERSION 3.0)
# 设定工程名称
project(MYPROJECT)
# 设定编译参数
add_compile_options(-Wall -std=c++11 -g -O2)
# 设定所有源码列表,设定该指令可以简化add_execuable()指令的编写
aux_source_directory(./src SRC_DIR)
# 包含头文件路径 include_directories("路径1" "路径1" ......) → g++ -I./***
include_directories(./include)
# 设定链接库路径,一般用于链接第三方库 link_directories("路径1" "路径2"...) → g++ -L./***
link_directories(../lib)
# 生成动态/静态链接库 add_library(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL]
# add_library(动/静链接库名称 [STATIC/SHARED](可选参数默认为STATIC) source1 source2 source3......)
add_library()
# 生成可执行文件 add_executable(exename source1 source2 ... sourceN)
add_executable(mywsap main.cpp ${SRC_DIR})
# 为target添加需要链接的第三方库、共享库 → g++ -l target_link_libraries(target library1<debug | optimized> library2...)
target_link_libraries()
CMake编译工程
CMake目录结构:项目主目录存在一个CMakeLists.txt文件
两种方式设置编译规则:
- 在包含源文件的子文件夹中还包含CMakeLists.txt文件 ,主目录的CMakeLists.txt通过
add_subdirectory(subdir1)
add_subdirectory(subdir2)
添加子目录即可
这种编译规则适用于项目较大结构复杂的情况,当项目包含多个模块或者子系统,每个模块的编译规则较为复杂时,可以使用这种编译规则。这样可以将项目按模块分解,每个模块有自己独立的 CMakeLists.txt 文件,使得项目结构更加清晰。 - 在包含源文件的子文件夹中未包含CMakeLists.txt文件 ,子目录编译规则体现在主目录的CMakeLists.txt中;
这种编译规则适用于项目结构相对简单,项目所包含的模块数量较少,直接在主目录的 CMakeLists.txt 文件中定义所有的编译规则,简化项目的管理与维护。
编译流程
- 在Windows系统下使用CMake构建C/C++工程的流程
- 手动编写CMakeLists.txt文件,定义编译规则。
- 执行命令cmake PATH 生成Makefile文件(PATH是主目录CMakeList.txt所在的目录。) 如果你的电脑安装了vs,那么此过程可能会调用微软的MSVC编译器,此时便需要使用cmake -G "MinGw Makefiles" PATH 来指定编译器。
- 执行 mingw32-make.exe 命令进行编译。
- 在Linux系统下使用CMakeLists.txt构建C/C++工程的流程
- 手动编写CMakeLists.txt文件,定义编译规则。
- 执行命令cmake PATH 生成Makefile文件(PATH是主目录CMakeList.txt所在的目录。)
- 执行 make 命令 进行编译。
构建方式
- 内部构件
内部构建会在同级目录下产生一大堆的中间文件,这些中间文件不是我们最终所需要的,和工程源文件放在一起会显得杂乱无章。不推荐使用。
bash
## 内部构建
# 在当前目录下,编译本目录的CMakeLists.txt,生成Makefile和其他文件
cmake .
# 执行make命令,生成target
mingw32-make.exe
- 外部构建
将编译输出文件与源文件放到不同目录中
bash
## 外部构建
# 1. 在当前目录下,创建build文件夹
mkdir build
# 2. 进入到build文件夹
cd build
# 3. 编译上级目录的CMakeLists.txt,生成Makefile和其他文件
cmake [-G "MinGW Makefiles"] ..
# 4. 执行make命令,生成target
mingw32-make.exe