[TOC]
原文:[15 Most Frequently Used GCC Compiler Command Line Options](https://www.thegeekstuff.com/2012/10/gcc-compiler-options/)以及评论中的一些参数。
> GCC编译器是一个日常流行的 C 编译器, 很多Linux的发布版本中都带有这个编译器。这篇文章列举了一些最常用的编译参数。
本文中使用下面的C语言实现的例子:
```
#include<stdio.h>
int main(void)
{
printf("\n The Geek Stuff\n");
return 0;
}
```
### 1.指定编译输出的名字
gcc编译器最常用的使用格式是:
```
gcc main.c
```
上面的命令执行完整的编译过程,并且生成一个`a.out`文件。
使用参数`-o`, 可以指定输出的文件名。
```
gcc main.c -o main
```
上面的命令会产生输出文件`main`。
为了理解GCC编译器的完整的编译过程,可以阅读[Journey of a C Program to Linux Executable in 4 Stages](https://www.thegeekstuff.com/2011/10/c-program-to-an-executable/)。
### 2.通过`-Wall`参数启用所有警告
这个参数可以启用所有警告。
```
#include<stdio.h>
int main(void)
{
int i;
printf("\n The Geek Stuff [%d]\n", i);
return 0;
}
```
上面的代码编译时,会出现`未初始化的i`类似的警告。
```
$ gcc - Wall main.c - o main
main.c: In function ‘main’ :
main.c : 6 : 10 : warning : ‘i’ is used uninitialized in this function[-Wuninitialized]
```
### 3.使用`-E`参数只产生预处理输出
`-E`参数是产生预处理阶段的输出。
```
$ gcc -E main.c > main.i
```
gcc命令将结果输出在`stdout`中,所以你可以把它重定向到任意的文件中,在上面的例子中,重定向到`main.i`文件中。
### 4.使用`-S`参数只产生汇编代码
`-S`参数产生汇编级别的代码。
```
gcc -S main.c > main.s
```
文件`main.s`包含汇编代码。
### 5.使用`-C`参数只产生编译的代码
`-C`参数只产生编译的代码(没有链接link)。
1gcc -C main.c
上面的代码产生`main.o`, 包含机器级别的代码或者编译的代码。
### 6.使用`-save-temps`参数产生所有的中间步骤的文件
`-save-temps`可以做4,5,6步骤的工作。通过这个参数,所有中间阶段的文件都会存储在当前文件夹中,注意它也会产生可执行文件。
```
gcc -save-temps main.c
ls
a.out main.c main.i main.o main.s
```
从例子中我们可以看到各个中间文件以及可执行文件。
### 7.使用`-l`参数链接共享库
`-l`可以用作链接共享库,例如:
1gcc -Wall main.c -o main -lCPPfile
上面的代码会链接`libCPPfile.so`,产生可执行文件`main`。
### 8.使用`-fPIC`产生位置无关的代码
当产生共享库的时候,应该创建位置无关的代码,这会让共享库使用任意的地址而不是固定的地址,要实现这个功能,需要使用`-fPIC`参数。
下面的例子产生`libCfile.so`动态库。
```
gcc -c -Wall -Werror -fPIC Cfile.c
gcc -shared -o libCfile.so Cfile.o
```
产生共享库的时候使用了`-fPIC`参数。
注意`-shared`产生共享库。
### 9.使用`-V`打印所有的执行命令
参数`-V`提供详细的信息,打印出gcc编译一个文件的时候所有的步骤。
例如:
```
$ gcc -Wall -v main.c -o main
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-linux-gnu/4.6/lto-wrapper
Target: i686-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.3-1ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=i686-linux-gnu --host=i686-linux-gnu --target=i686-linux-gnu
Thread model: posix
gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
.........
```
这样我们可以看到所有的细节。
### 10. 使用`-ansi`参数支持 ISO C89程序
使用`-ansi`参数可以支持 ISO C89风格。
比如下面的代码:
```
#include<stdio.h>
int main(void){
// Print the string
printf("\n The Geek Stuff\n");
return 0;
}
```
使用`-ansi`参数编译上面的代码会出错,因为ISO C89不支持C++风格的注释。
下面是输出结果:
```
12main.c: In function ‘main’:
main.c:5:3: error: expected expression before ‘/’ token
```
我们可以看待上面编译的时候抛出一个注释错误。
### 11.使用`-funsigned-char`将char解释为符号的char
通过这个参数, char类型被看作为 unsigned char类型。
例子:
```
#include<stdio.h>
int main(void)
{
char c = -10;
// Print the string
printf("\n The Geek Stuff [%d]\n", c);
return 0;
}
```
上面的代码通过这个参数编译后,输出结果为:
```
gcc -Wall -funsigned-char main.c -o main
./main
The Geek Stuff [246]
```
可以看到char是无符号的字节。
### 12.使用`-fsigned-char`将char解释为有符号的char
和上面的功能相反, 使用这个参数, char类型被看作是有符号的:
```
gcc -Wall -fsigned-char main.c -o main
$ ./main
The Geek Stuff [-10]
```
结果输出为负数。
### 13. 使用`-D`参数可以使用编译时的宏
参数`D`可以用作定义编译时的宏。
例子:
```
#include<stdio.h>
int main(void)
{
#ifdef MY_MACRO
printf("\n Macro defined \n");
#endif
char c = -10;
// Print the string
printf("\n The Geek Stuff [%d]\n", c);
return 0;
}
```
`-D`可以用作从命令行定义宏`MY_MACRO`。
```
$ gcc -Wall -DMY_MACRO main.c -o main
$ ./main
Macro defined The Geek Stuff [-10]
```
可以看到宏被定义了,并打印出了结果。
tput confirms that the macro was defined.
### 14.使用`-Werror`将警告升级为错误
通过这个参数,gcc会将所有的警告转换成错误信息。
例子:
```
#include<stdio.h>
int main(void)
{
char c;
// Print the string
printf("\n The Geek Stuff [%d]\n", c);
return 0;
}
```
上面的代码编译的时候会有一个`undefined variable c`警告,`-Werror`会把这个警告升级成错误。
```
$ gcc - Wall - Werror main.c - o main
main.c: In function ‘main’ :
main.c : 7 : 10 : error : ‘c’ is used uninitialized in this function[-Werror = uninitialized]
cc1 : all warnings being treated as errors
```
### 15.使用`@`参数从文件中读取参数
gcc参数可以从文件中读取,通过`@`后跟文件名的方式提供, 多个参数可以使用空格区隔。
例子:
```
cat opt_file
-Wall -omain
```
`opt_file`包含编译参数。
使用`@`参数:
```
$ gcc main.c @opt_file
main.c: In function ‘main’ :
main.c : 6 : 11 : warning : ‘i’ is used uninitialized in this function[-Wuninitialized]
$ ls main
main
```
输出结果表明参数的确从文件中读取了,并且正确的应用到编译过程中。
> 以下是附加的一些编译参数
### 16.使用参数`-I`指定头文件的文件夹
```
gcc -I/home/codeman/include input-file.c
```
`-I-`取消前一个参数功能,一般用在`-Idir`之后。
### 17.使用参数`-std`指定支持的c++/c的标准
```
gcc -std=c++11 hello-world.cpp
```
标准如`c++11, c++14, c90, c89`等。
### 18.使用`-static`生成静态链接的文件
静态编译文件(把动态库的函数和其它依赖都编译进最终文件)
```
gcc main.c -static -o main -lpthread
```
相反的使用`-shared`使用动态库链接。
### 19.使用`-static-libstdc++`静态链接libstdc++
如果没有使用`-static`,默认使用libstdc++共享库,而`-static-libstdc++`可以指定使用libstdc++静态库。
### 20.使用`-M`生成文件关联的信息
```
gcc - M main.c
main.o: main.c / usr / include / stdc - predef.h / usr / include / stdio.h \
/ usr / include / features.h / usr / include / sys / cdefs.h \
/ usr / include / bits / wordsize.h / usr / include / gnu / stubs.h \
/ usr / include / gnu / stubs - 64.h \
/ usr / lib / gcc / x86_64 - redhat - linux / 4.8.5 / include / stddef.h \
/ usr / include / bits / types.h / usr / include / bits / typesizes.h \
/ usr / include / libio.h / usr / include / _G_config.h / usr / include / wchar.h \
/ usr / lib / gcc / x86_64 - redhat - linux / 4.8.5 / include / stdarg.h \
/ usr / include / bits / stdio_lim.h / usr / include / bits / sys_errlist.h
```
### 全部参数介绍
[https://gcc.gnu.org/onlinedocs/gcc/Option-Summary.html](https://gcc.gnu.org/onlinedocs/gcc/Option-Summary.html)
- 前言
- 服务器开发设计
- Reactor模式
- 一种心跳,两种设计
- 聊聊 TCP 长连接和心跳那些事
- 学习TCP三次握手和四次挥手
- Linux基础
- Linux的inode的理解
- 异步IO模型介绍
- 20个最常用的GCC编译器参数
- epoll
- epoll精髓
- epoll原理详解及epoll反应堆模型
- epoll的坑
- epoll的本质
- socket的SO_REUSEADDR参数全面分析
- 服务器网络
- Protobuf
- Protobuf2 语法指南
- 一种自动反射消息类型的 Protobuf 网络传输方案
- 微服务
- RPC框架
- 什么是RPC
- 如何科学的解释RPC
- RPC 消息协议
- 实现一个极简版的RPC
- 一个基于protobuf的极简RPC
- 如何基于protobuf实现一个极简版的RPC
- 开源RPC框架
- thrift
- grpc
- brpc
- Dubbo
- 服务注册,发现,治理
- Redis
- Redis发布订阅
- Redis分布式锁
- 一致性哈希算法
- Redis常见问题
- Redis数据类型
- 缓存一致性
- LevelDB
- 高可用
- keepalived基本理解
- keepalived操做
- LVS 学习
- 性能优化
- Linux服务器程序性能优化方法
- SRS性能(CPU)、内存优化工具用法
- centos6的性能分析工具集合
- CentOS系统性能工具 sar 示例!
- Linux性能监控工具集sysstat
- gdb相关
- Linux 下如何产生core文件(core dump设置)