gcc使用
前言
介绍
GCC(英文全拼:GNU Compiler Collection)是 GNU 工具链的主要组成部分,是一套以 GPL 和 LGPL 许可证发布的程序语言编译器自由软件,由 Richard Stallman 于 1985 年开始开发。
GCC 原名为 GNU C语言编译器,因为它原本只能处理 C 语言,但如今的 GCC ,不仅可以编译 C、C++ 和 Objective-C,还可以通过不同的前端模块支持各种语言,包括 Java、Fortran、Ada、Pascal、Go 和 D 语言等等。
GCC支持多种硬件开发平台,还能进行跨平台交叉编译。此外,GCC是按模块化设计的,可以加入新语言和新CPU架构的支持。
GCC、gcc、g++三者之间的关系
gcc(GUN C Compiler)是GCC中的c编译器,而g++(GUN C++ Compiler)是GCC中的c++编译器。
gcc和g++两者都可以编译c和cpp文件,但存在差异。gcc在编译cpp时语法按照c来编译但默认不能链接到c++的库(gcc默认链接c库,g++默认链接c++库)。g++编译.c和.cpp文件都统一按cpp的语法规则来编译。所以一般编译c用gcc,编译c++用g++。
安装
linux
只需要一行指令
1 | sudo apt install gcc |
windows
可以使用 mingw
来安装 gnuc
的工具
下载压缩包之后,解压到软件的位置,然后再添加系统环境变量
gcc编译指令参数 gcc [option] file
- -o 用于指定编译之后的文件名称
- -g 在可执行文件中加入源码信息供gdb调试使用,但是并不是把整个源文件嵌入到可执行文件中,而是几条机器码对应几行源代码
- -c 只生成目标文件 .o 文件
- -Wall 通常gcc不会提示一些不重要的警告,加上之后会提示所有警告
-O 编译优化等级
gcc 编译有 -O0, -O1, -O2, -O3, -Os, -Ofast, -Og 等几个优化等级,对于前几个来说,随着数字变大,代码的优化程度也越高,但是某种程度上来说是牺牲可调试性能作为代价的,当然有些代码部分是不能进行优化的- -O0 默认优化等级,实质上没有任何优化
- -O1 最基本优化,短时间内生成可执行文件,主要对代码的分支,常量以及表达式进行优化
- -O2 相对于-O1来说,增加了编译时间的基础上,提高了生成代码的执行效率
- -Os 在-O2的基础上,去掉了导致最终可执行程序增大的优化,可以生成执行效率较高并且更小的执行程序
- -O3 延长编译时间,在-O2基础上进行更多的优化,编译成的软件将生成更大体积更耗内存的二进制文件,增加编译失败的机会并且产生不可预知的程序行为,不建议使用
- -Ofast 在-O3基础上添加一些非常规优化,通过打破一些国际标准来实现的,不仅以使用
- -Og 在-O1的基础上去掉了一些影响调试的优化,如果最终为了调试可以使用这种优化方式
-E 只做预处理而不编译
- -S 生成汇编代码
- -l 链接,告诉编译器去哪里寻找头文件,参数后紧跟库的名字告诉编译器要链接的库
- -lpthread 代表使用pthread库实现多线程,代表使用C++11的线程库
- lm 代表使用数学库
- -L 告诉编译器去哪里寻找需要的库文件,但是即使库文件就在当前目录下,编译器也不会去找的,所以必须加此参数,除非你的库在默认的寻找目录里,默认目录可以用gcc -print-search-dirs查看。
- -v 可以详细看到编译的过程
- -share 这个选项将尽量使用动态库,生成文件较小,但是需要动态库
- -static 这个将禁止使用动态库,编译出来的东西很大,不需要动态链接库就可以运行
- static-libgcc 静态链接,编译时使用,用于生成独立的可执行文件
- -f 有点怪没找到,好像是一些配置 ^-^?
- fPIE与-fpie是等价的。这个选项与-fPIC/-fpic大致相同,不同点在于:-fPIC用于生成动态库,-fPIE用与生成可执行文件。再说得直白一点:-fPIE用来生成位置无关的可执行代码。
- fPIC与-fpic都是在编译时加入的选项,用于生成位置无关的代码(Position-Independent-Code),生成动态库。这两个选项都是可以使代码在加载到内存时使用相对地址,所有对固定地址的访问都通过全局偏移表(GOT)来实现。-fPIC和-fpic最大的区别在于是否对GOT的大小有限制。-fPIC对GOT表大小无限制,所以如果在不确定的情况下,使用-fPIC是更好的选择
- openmp 代表使用OpenMP多线程库
- stack-protector-strong 启用栈保护功能
- -M 可以自动分析目标文件和源文件的依赖关系
- -MM 可以自动分析目标文件和源文件的依赖关系,它将忽略由
#include<file>
造成的依赖关系 - std=c++11 代表使用C++11的规范
- -D 代表定义一个宏,例如-DDEBUG
- -U 代表取消一个宏,例如-UDEBUG
- Werror 代表将所有警告视为错误
- Wno-* 代表取消某一类警告,例如-Wno-unused-variable表示取消未使用变量的警告
- Wno-format-nonliteral 忽略对printf格式化字符串的检查
- Wno-unused-parameter 忽略未使用的参数
- Wl,代表将传递给连接器,例如-Wl,-rpath=./指定运行时动态链接库的搜索路径为当前目录
- Wl,—no-as-needed 静态链接,编译时使用,告诉编译器必须链接所有的库
- Wformat=2 检查printf格式化字符串的正确性
- Wconversion 检查隐式类型转换
- Wsign-conversion 检查有符号和无符号类型之间的转换
- -s 从可执行文件中删除所有符号表和重定位信息.
gcc编译过程
预处理
将源文件处理为
.i/.ii
文件,处理各种预处理的指令,例如一些宏定义等编译
将预处理后的
.i/.ii
文件编译为.S/.asm
文件,也就是汇编语言文件汇编
将
.S/.asm
文件处理为.o
文件,也就是把汇编文件处理为机器码链接
将各种依赖的静态库/动态库文件,
.o
文件,启动文件链接成最终可执行文件或者库文件
预处理
1 | gcc -E a.c -o a.i |
编译
1 | gcc -S a.c |
汇编
1 | gcc -c a.c |
第二条处理汇编语言的指令,实际上是使用汇编器 as
将 .s
文件处理为 .o
文件的
1 | as a.s -o a.o |
链接
其中有两个参数 -L
和 -l
用于指定链接的文件的地址和名称,使用 -l
可以省略库文件开头的 lib
和后缀
1 | gcc a.c -Ldir -lname |
查看gcc编译过程
使用 -v
来查看
1 | gcc a.c -v |