zl程序教程

您现在的位置是:首页 >  后端

当前栏目

C/C++生态工具链——gcc/g++编译器使用指南

C++工具编译器 使用指南 生态 gcc ++
2023-06-13 09:17:11 时间

一,关于GCC

GCC的全称是GNU Compiler Collection,是GNU工具链中的一种。GCC不仅支持C/C++语言,还支持Fortran/Ada/Java等语言的编译。

GCC和gcc是两个概念,GCC是工具链的集合,里面除了gcc/g++还包含了ccl,cclplus等组件。gcc/g++只是GCC工具链的一个子集。

二,g++和gcc的区别

gcc可以判断出目标程序所使用编程语言的类别,会把xxx.c文件当作C语言编译,把xxx.cpp文件当作C++语言编译。而g++只把xxx.c和xxx.cpp一律都当作C++语言来编译。

在编译C++文件的时候,g++会自动链接一些标准库或基础库,而gcc不会。当正在编译的C++代码文件依赖STL标准库的时候,为了使用STL,gcc命令需要增加参数–lstdc++。因此,虽然gcc和g++都可以编译C++语言程序,但是使用g++会更方便一些。

三,常见代码文件后缀名

(1)目标文件:

xxx.o, 操作系统:Linux, Mac

xxx.obj, 操作系统:windows

(2)二进制文件:

xxx(没有后缀名), 操作系统:Linux, Mac, FreeBSD,

xxx.exe, 操作系统:windows

xxx.hex,操作系统:嵌入式系统

(3)共享库文件,也叫动态库文件:

xxx.dll, 操作系统:windows

xxx.so, 操作系统:Linux

xxx.dylib, 操作系统:Mac

(4)静态库文件

xxx.a

四,C/C++语言的编译过程

1.预处理

预处理命令声明了编译时需要的各种头文件和宏,比如包含哪些头文件、宏定义的扩展、在哪个代码段做条件编译等。涉及预处理的语法有:#define,#include,#ifdef...#endif等。

2.编译

首先检查代码的规范性和语法错误等,检查完毕后把代码翻译成汇编语言,生成汇编语言文件

3.汇编

基于汇编语言文件生成二进制格式的目标文件

3.链接

将目标代码与所依赖的库文件进行关联或者组装,合成一个可执行文件

具体过程如图:

--用g++举例

样例代码:

#include <iostream>

int main() {
    std::cout << "Hello World!" << std::endl;
    return 0;
}

g++的编译过程:

1.预处理--将xx.cpp源文件预处理成xx.i文件

g++ -E demo.cpp -o demo.i

2.编译--将xx.i文件编译为xx.s的汇编文件。此时只进行编译生成汇编代码,而不对代码以汇编的方式调试

g++ -S demo.i -o demo.s

3.汇编--将xx.s文件汇编成xx.o的二进制目标文件

g++ -c demo.s -o demo.o

4.链接--将xx.o二进制文件进行链接,最终生成可执行程序

g++ demo.o -o demo.out

五,静态链接和动态链接的区别

静态库:

与目标程序合并,成为目标程序的一部分。

创建静态库的时候,需要使用"gcc/g++ -c"先将xxx.c源文件编译为目标文件xxx.o,然后使用ar指令将xxx.o打包成xxxx.a静态库。

目标程序与静态库链接时,目标程序代码调用的任何外部函数的代码都会从静态库中复制到最终的可执行文件中。

GCC在链接时优先使用动态库,只有当动态库不存在时才开始使用静态库,如果要强制使用静态库,编译时加上-static参数。

使用-Wl,-Bstatic告诉链接器优先使用静态库。

动态库:

不包含在目标程序中,但是与目标程序相关联。

创建动态库的时候,可以传-shared和-fPIC参数,-fPIC参数用于编译阶段,用来生成位置无关的代码。使用“gcc -shared -fPIC”可以直接用xxx.c源文件生成xxx.so动态库。

目标程序与动态库链接时,可执行文件仅包含它所需的一个小函数表,而不是来自库文件的完整机器代码。在可执行文件开始运行之前,动态库的代码被操作系统复制到内存中进行共享。

动态库之所以叫共享库,可能是由于动态库的代码副本可以在多个程序之间共享。正因为这种链接方式,共享库每次被更新时,都不需要重新编译正在使用共享库的目标程序。

使用-Wl,-Bdynamic告诉链接器优先使用动态库。

有关的环境变量:

LIBRARY_PATH:使用于编译期间,目标程序链接时搜索动态库的路径。

LD_LIBRARY_PATH:使用于目标程序生成后,目标程序运行时搜索动态库的路径。

静态库链接时,搜索库文件路径的顺序:

1. ld会去找GCC命令中的参数-L

2. gcc的环境变量LIBRARY_PATH

3. /lib,/usr/lib,/usr/local/lib等写在程序内的路径

动态库链接时,搜索库文件路径的顺序:

1. 编译目标代码时指定的动态库搜索路径

2. gcc的环境变量LD_LIBRARY_PATH

3. 配置文件/etc/ld.so.conf中指定的动态库搜索路径

4. 默认的动态库搜索路径/lib

5. 默认的动态库搜索路径/usr/lib

实用程序:ldd 和 nm

ldd:列出依赖的动态库

nm:查看动态库/静态库中的函数

六,gcc/g++命令常见参数

命令格式

       gcc [-c|-S|-E] [-std=standard]
           [-g] [-pg] [-Olevel]
           [-Wwarn...] [-pedantic]
           [-Idir...] [-Ldir...]
           [-Dmacro[=defn]...] [-Umacro]
           [-foption...] [-mmachine-option...]
           [-o outfile] [@file] infile...

常见参数如下(注意大小写):

-o
#输出到指定文件。如果不指定,默认输出到a.out

-E
#仅进行预处理,不进行编译、汇编和链接

-S
#将代码转换为文件格式为xxx.s的汇编语言文件,但不进行汇编

-c
#仅进行编译和汇编,不进行链接操作,常用于编译不包含main程序的子程序代码

-v
#打印gcc编译时的详细步骤信息

编译和路径参数

-l[basic library]
#编译时指定要使用的基础库,样例:-lpthread,针对Posix线程共享库进行编译

-L[shared-library path]      
#共享库的路径添加到搜索的范围,路径为包含xxx.dll/xxx.so/xxx.dlyb文件的目录

-I[include header-file path]          
#将头文件的路径添加到搜索的范围,路径为包含xxx.h/xxx.hpp文件的目录

-shared
#生成共享库,库文件格式为xxx.dll/xxx.so/xxx.dlyb格式的文件

-static
#生成静态库,库文件格式为xxx.a格式的文件

-Wl
#告诉编译器将后面的参数传递给链接器

-Wl,-Bstatic
#-Bstatic选项用于对指定的库静态连接

-Wl,-Bdynamic
#-Bdynamic搜索共享库(默认)

-Wa,option
#此选项传递option给汇编程序;如果option中间有逗号,就将option分成多个选项,然后传递给会汇编程序

-Wl,option
#此选项传递option给连接程序;如果option中间有逗号,就将option分成多个选项,然后传递给会连接程序

预处理参数

#使用形式:-D[FLAG] 或-D[FLAG]=VALUE          

-Dmacro
#在命令行里定义宏,相当于C语言中的"#define macro"

-Umacro
#相当于C语言中的"#undef macro"

-undef
#取消对任何非标准宏的定义

警告与报错参数

-Wall
#发出gcc提供的所有有用的报警信息

-Werror
#将警告升级为编译报错


-Wextra / -W
#启用-Wall未启用的额外警告位,对合法但值得怀疑的代码发出警告  例如 -Wsign-compare


-pendantic / -Wpendantic
#发出ISO C和ISO C++标准列出的所有警告,用于语法检查,-pedantic-erros的用法也类似

-fsyntax-only
#仅做语法检查

调试参数

-g
#产生带有调试信息的目标代码

-gstabs
#此选项以stabs格式声称调试信息,但是不包括gdb调试信息

-gstabs+
#此选项以stabs格式声称调试信息,并且包含仅供gdb使用的额外调试信息

-ggdb
#生成gdb专用的调试信息

-glevel
#请求生成调试信息,同时用level指出需要多少信息,默认的level值是2

编码配置参数

-fno-exceptions
#屏蔽掉C++的异常,常用于于嵌入式或无法接受异常的系统

-fno-rtti
#禁用RTTI,常用于嵌入式或游戏开发

-fno-asm
#不要识别asm,inline或typeof作为关键字,以便代码可以使用这些词作为标识符。您可以使用关键字__asm__,__inline__来__typeof__ 代替。-ansi暗示-fno-asm

-fPIC / -fpic
#让编译器的代码和位置无关,让代码逻辑不使用绝对地址,只用相对地址,方便文件加载

-nostdinc
#使编译器不再系统默认的头文件目录里面找头文件, 一般和 -I 联合使用,明确限定头文件的位置

-nostdin C++
#规定不在g++指定的标准路经中搜索,但仍在其他路径中搜索,.此选项在创建libg++库使用

优化参数

-O0  
#不优化

-O1  / -O
#尝试优化编译时间和可执行文件大小

-O2
#尝试所有的优化选项,但不会进行“空间换时间”的优化方式

-Os
#尝试所有的优化选项时,优先优化可执行文件大小

七,参考阅读

https://gcc.gnu.org/onlinedocs/gcc/

https://subscription.packtpub.com/book/programming/

https://linuxhint.com/what-is-ld-library-path/