gcc编译
提示:文章
文章目录
- 前言
- 一、背景
- 二、gcc编译选项
- 2.1 -wall
- 2.2 -Werror
- 三、cmakelist
- 一、set语句
- 二、CMAKE_C_FLAGS和CMAKE_CXX_FLAGS
- 三、编译部分
- 一、Release编译语句
- 1、-D_FORTIFY_SOURCE=2选项
- 使用方法
- 原理
- 2、-o2、-o3选项
- 3、-DNDEBUG选项
- 4、-s选项
- 二、ASAN编译
- 1、-D_ASAN选项
- 三、Debug编译语句
- 1、-D_DEBUG选项
- 2、-g选项
- 四、cmakelist常用系统变量
- 五、对于cmakelist的个人理解
- 六、TARGET_LINK_LIBRARIES
- 四 总结
前言
前期疑问:
本文目标:
一、背景
最近又在看gcc编译选项相关知识点,在整理gcc编译选项的时候又整理了cmakelist的相关知识点
二、gcc编译选项
2.1 -wall
打开所有关键告警开关
源于题目如下:
1、gcc编译选项中,-wall的作用是什么?
A、打开所有关键告警开关
B、保留所有调试符号
C、把告警当做错误来对待
D、屏蔽所有告警
正确答案A
2.2 -Werror
编译器会将编译告警视为错误
源于题目如下:
以下哪个选项开启后,编译器会将编译告警视为错误?
A、-Werror
B、-Wformat
C、-Wextra
D、-Wall
正确答案A
三、cmakelist
解析工程cmakelist编译选项
编译语句如下
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pthread -fPIC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -pthread -fPIC")if (CMAKE_BUILD_TYPE STREQUAL Release)set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_FORTIFY_SOURCE=2 -O3 -DNDEBUG -s")
elseif (CMAKE_BUILD_TYPE STREQUAL Asan)set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -D_ASAN -fsanitize=address -fsanitize-recover=address,all -fsanitize=leak -fsanitize-coverage=trace-pc")set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftest-coverage -fprofile-arcs -fdump-rtl-expand -lgcov")
else ()set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -D_DEBUG")
endif ()
下面逐个分解含义,主要分为以下几个方面
一、set语句
CMakeLists.txt中的set命令主要用于设置普通变量、缓存条目和环境变量。
下面自己验证了下set的功能
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -pthread -fPIC")
message(${CMAKE_CXX_FLAGS})set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -D_DEBUG")
message(${CMAKE_CXX_FLAGS})
打印信息为
-std=c++11 -Wall -pthread -fPIC-std=c++11 -Wall -pthread -fPIC -g -D_DEBUG
由此可见连续两次使用set是将CMAKE_CXX_FLAGS变量赋值,并且通过两次赋值,拼成一个长字符串
二、CMAKE_C_FLAGS和CMAKE_CXX_FLAGS
这两个变量应该是系统变量
这两个变量可以在CMakeLists.txt文件中使用set命令来设置,也可以在命令行中使用-D选项来设置。例如,要将CMAKE_C_FLAGS设置为-O2,可以使用以下命令:
在CMakeLists.txt文件中:
set(CMAKE_C_FLAGS “-O2”)
在命令行中:
cmake -DCMAKE_C_FLAGS=-O2
这些编译器选项会被添加到所有使用C或C++编译器的目标的编译命令中。
例如,假设我们有一个名为mylib的库目标,它包含一个名为foo.c的C文件,要为这个文件使用-O2优化选项,可以这样写:
set(CMAKE_C_FLAGS “-O2”)
add_library(mylib foo.c)
这会导致在编译mylib时使用-O2优化选项。
三、编译部分
编译分为三部分,
Release | ASAN | Debug |
---|---|---|
发布文件 | 检测内存 | 可调式文件 |
一、Release编译语句
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_FORTIFY_SOURCE=2 -O3 -DNDEBUG -s")
1、-D_FORTIFY_SOURCE=2选项
[D_FORTIFY_SOURCE=2]编译器的一个安全特性,用于增强C和C++程序的安全性,主要目的是检测和防止缓冲区溢出、格式化字符串漏洞等内存操作相关的安全问题。通过在编译时插入额外的检查,FORTIFY_SOURCE可以替换标准库函数调用为带有额外检查的安全版本,确保操作的边界和输入的有效性。
使用方法
要启用D_FORTIFY_SOURCE=2选项,需要在编译时使用以下GCC编译选项:
-D_FORTIFY_SOURCE=2
:启用更严格的检查。-O2
:优化等级至少为2,以确保FORTIFY_SOURCE机制有效。原理
FORTIFY_SOURCE通过在编译时静态分析源代码,替换标准库函数调用为带有额外检查的安全版本。这些安全版本在进行某些操作之前会执行一些额外的检查,以确保操作的边界和输入的有效性。例如,对于字符串复制操作,它会检查源字符串的长度是否超过了目标缓冲区的大小,从而防止缓冲区溢出。
2、-o2、-o3选项
gcc编译优化选项支持五种,分别是-O0、-O1、-O2、-Os和-O3。
-O0表示无优化,是默认选项。
-O1和-O2选项可以对程序进行部分编译优化,其中-O1选项尝试减小目标文件大小和缩短执行时间,而不显著增加编译时间;-O2选项增加了更多的优化选项,包括循环展开、内联函数等,会提高程序的执行性能。
-Os选项专门针对目标文件大小进行优化,执行所有不增加目标文件大小的-O2优化选项,并执行专门减小目标文件大小的优化选项。
-O3选项打开所有-O2的优化选项,并增加了循环展开、函数内联等更多的优化选项,以提高程序执行性能。
此外,还可以使用-fdefer-pop选项来延迟栈的弹出时间,以提高函数的调用速度。
3、-DNDEBUG选项
gcc -DNDEUG 是 GCC 编译器的一个编译选项,用于定义 NDEBUG 宏。NDEBUG 是许多C/C++程序中用来控制断言(assert)的行为的宏。当使用 -DNDEBUG
选项时,它告诉编译器在编译过程中不要包括assert语句。
这个选项通常在你不想在程序中包含调试代码,或者在发布版本中不想包含断言时使用。
例如,如果你有以下的C++代码:
#include <cassert>int main() {assert(1 == 1);return 0;
}
如果你使用 g++ -DNDEBUG -o program program.cpp
来编译这段代码,assert 语句就不会被编译器处理。
4、-s选项
gcc -s选项
gcc
编译器的 -s
选项用于表示产生静态链接的可执行文件。这个选项告诉链接器产生一个静态链接的可执行文件,而不是动态链接的可执行文件。
例如,如果你有一个源文件 hello.c
,你可以使用以下命令来编译并产生一个静态链接的可执行文件:
gcc -s -o hello hello.c
在这个例子中,-o hello
指定了输出文件的名字为 hello
,-s
选项告诉编译器生成静态链接的可执行文件。
注意,-s
选项通常用于创建不需要运行时动态链接库的可执行文件,这通常用于创建可移植的可执行文件,因为它们不依赖于特定系统上的动态库。
二、ASAN编译
1、-D_ASAN选项
D_ASAN 是一个用于开启 AddressSanitizer (ASan) 的编译选项,它是一个用于检测 C/C++ 程序中内存错误的工具。在 GCC 中使用 ASan 需要在编译时添加 -fsanitize=address
选项。
如果你想在 GCC 中使用 D_ASAN
选项,你可能需要定义这个宏,并且添加 ASan 的编译选项。这可以通过以下命令行实现:
gcc -D_D_ASAN -fsanitize=address your_program.c -o your_program
在这个命令中,-D_D_ASAN
告诉 GCC 预处理器定义 _D_ASAN
宏,your_program.c
是你的源代码文件,-o your_program
指示 GCC 生成一个名为 your_program
的可执行文件。
请注意,ASan 可能会增加额外的开销,并且在某些平台上可能不完全稳定,但它是检测内存错误的强大工具。
三、Debug编译语句
1、-D_DEBUG选项
gcc -D_DEBUG
是 GCC 编译器的一个选项,它的作用是定义一个名为 _DEBUG
的预处理宏。这个宏在源代码中可以用来开启调试代码,通常与条件编译结合使用。
例如,你可以在源代码中这样使用:
#ifdef _DEBUG
// 调试代码
#endif
这段代码中的调试代码只有在使用 -D_DEBUG
选项编译时才会被编译进程序。这样你就可以在开发过程中打开这个宏来进行调试,而在发布版本时不编译这部分代码,从而减小最终的可执行文件大小。
2、-g选项
gcc -g
选项是GCC编译器的一个常用选项,它的作用是在编译过程中生成调试信息。调试信息可以帮助开发者理解程序的执行流程,调试过程中的各种状态,以及程序中的各种变量。
调试信息通常以下面几种形式存在:
- 行信息:编译器会在生成的目标文件中记录程序的每一行源代码对应的行号。
- 非局部信息:编译器会记录函数的开始和结束以及程序的入口点。
- 符号信息:编译器会为每个变量和函数生成一个符号,并在链接时用于解析外部引用。
- 优化信息:编译器可以在调试信息中插入额外的信息来帮助优化调试过程。
使用-g
选项的一般形式是-glevel
,其中level
是调试信息级别,可以是1,2或3。默认情况下,使用-g3
。
例如,以下是一个简单的C语言程序,它使用了-g
选项进行编译:
// test.c
#include <stdio.h>int main() {int a = 10;int b = 20;int sum = a + b;printf("The sum is: %d\n", sum);return 0;
}
编译命令:
gcc -g test.c -o test
这条命令会生成一个带有调试信息的可执行文件test
。你可以使用gdb
等调试器来调试这个程序。
四、cmakelist常用系统变量
见该文章,CMake中的常用变量的命令
五、对于cmakelist的个人理解
之前一直疑惑cmake、cmakelist等几个关键词的意思。之前整理过关于cmakelist和cmake之类的关系的文章:cmakelist、cmake、makefile、make以及gcc的关系和区别
这次我根据个人理解再整理一下,以我编译工程代码为例,首先我是使用cmake指令去编译cmakliet.txt文件,生成makefile文件,再执行make -j 32去编译Makefile文件,实现对工程代码的编译。
所以上述几个关键词的区别在于,一开始是编写makefile文件,利用make工具依据makefile编译代码。然后发现makefile不好写,就创造了cmake工具,cmake工具依据cmakelist.txt文件编译代码。所以要写cmakelist.txt文件。
想起来之前看的一篇介绍cmakelist的文章,说cmakelist文件也越来越难写。本来为了解决makefile难写的问题发明了cmake工具,但是现在cmakelist也很难写。屠龙者终成恶龙。哈哈哈,有点道理。
六、TARGET_LINK_LIBRARIES
工程语句
TARGET_LINK_LIBRARIES(testDataStatistics protobuf protoc)
TARGET_LINK_LIBRARIES(testDataStatistics cryptopp)
TARGET_LINK_LIBRARIES(testDataStatistics boost_filesystem boost_serialization boost_program_options)
TARGET_LINK_LIBRARIES链接库
这边这个变量我是难以理解的,查到的资料也不全。我所疑惑的是为什么括号里会写好几个库名。我一开始认为是因为一个库可能有多个小名字,那么问题来了,怎么知道这写小名字叫啥呢,在哪里看呢?
然而我现在意识到可能不是我想的这样。里面写的其实是库名,比如protobuf这个库,他可能依赖其他的库,这时候就需要把其他的库也写上去,而且是有顺序的。
target_link_libraries里库文件的顺序符合gcc链接顺序的规则,即被依赖的库放在依赖它的库的后面
参考这篇文章:CMake命令target_link_libraries链接库的顺序
那么问题来了,怎么知道要依赖哪些库呢,这个就比较容易了,在库编译的时候,缺少依赖库的话,会报错告诉你。这样就对了。知识点+1。
四 总结
未完待续