当前位置: 首页 > news >正文

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优化选项。

三、编译部分

编译分为三部分,

ReleaseASANDebug
发布文件检测内存可调式文件

一、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。

四 总结

未完待续


http://www.mrgr.cn/news/78619.html

相关文章:

  • 在内网工作时,如何使用 vscode remote ssh 去连接内网服务器?
  • LCR 151.彩灯装饰记录III
  • docker 通过Dockerfile自定义的镜像部署Springboot项目
  • 130. 被围绕的区域【 力扣(LeetCode) 】
  • typescript 实践记录
  • Unity3d C# 摄像头检测敌方单位(目标层级)并在画面中标注(含源码)
  • 如何在Spark中使用gbdt模型分布式预测
  • HTML飞舞的爱心(完整代码)
  • HarmonyOS Next 模拟器安装与探索
  • 十四(AJAX)、AJAX、axios、常用请求方法(GET POST...)、HTTP协议、接口文档、form-serialize
  • 基于vite创建一个脚手架(快速入门)
  • 【Gitlab】CICD使用minio作为分布式缓存
  • 【OJ】前K个高频单词和单词识别和两个数组的交集
  • PyG教程:MessagePassing基类
  • Java ConcurrentHashMap
  • HTTP 1
  • Java Collection
  • uniapp连接mqtt频繁断开原因和解决方法
  • 【组成原理】计算机硬件设计——ALU
  • Maven 配置
  • yolov8的深度学习环境安装(cuda12.4、ubuntu22.04)
  • Spring Boot使用JDK 21虚拟线程
  • 在shardingsphere执行存储过程
  • 机器学习实战:泰坦尼克号乘客生存率预测(数据处理+特征工程+建模预测)
  • vulnhub靶场之hackableⅡ
  • 【C语言】字符串左旋的三种解题方法详细分析