gcc编译流程
gcc
编译器在编译一个C语言程序时需要经过以下4步:
- 将C语言源程序预处理,生成
.i
文件; - 预处理后的
.i
文件编译成为汇编语言,生成.s
文件; - 将汇编语言文件经过汇编,生成目标文件
.o
文件; - 将各个模块的
.o
文件链接起来生成一个可执行程序文件。
gcc的帮助信息
我们可以使用gcc --help
查看gcc
的帮助信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| gcc --help
Usage: gcc-4.9 [options] file...
Options:
-pass-exit-codes Exit with highest error code from a phase
--help Display this information
--target-help Display target specific command line options
--help={common|optimizers|params|target|warnings|[^]{joined|separate|undocumented}}[,...]
Display specific types of command line options
-Wa,<options> Pass comma-separated <options> on to the assembler
-Wp,<options> Pass comma-separated <options> on to the preprocessor
-Wl,<options> Pass comma-separated <options> on to the linker
-Xassembler <arg> Pass <arg> on to the assembler
-Xpreprocessor <arg> Pass <arg> on to the preprocessor
-pipe Use pipes rather than intermediate files
-time Time the execution of each subprocess
-specs=<file> Override built-in specs with the contents of <file>
-std=<standard> Assume that the input sources are for <standard>
--sysroot=<directory> Use <directory> as the root directory for headers
and libraries
...... ......
-B <directory> Add <directory> to the compiler's search paths
-v Display the programs invoked by the compiler
-### Like -v but options quoted and commands not executed
-E Preprocess only; do not compile, assemble or link
-S Compile only; do not assemble or link
-c Compile and assemble, but do not link
-o <file> Place the output into <file>
-pie Create a position independent executable
-shared Create a shared library
Options starting with -g, -f, -m, -O, -W, or --param are automatically
passed on to the various sub-processes invoked by gcc-4.9. In order to pass
other options on to these processes the -W<letter> options must be used.
|
重要的gcc编译选项
gcc -v
选项
我们可以使用gcc -v
参数查看编译过程中的的一些详细信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| $ gcc -v -DDEBUG gdb_finish.c -std=c99
Using built-in specs.
COLLECT_GCC=/usr/local/Cellar/gcc49/4.9.3/bin/gcc-4.9
COLLECT_LTO_WRAPPER=/usr/local/Cellar/gcc@4.9/4.9.3/bin/../libexec/gcc/x86_64-apple-darwin15.2.0/4.9.3/lto-wrapper
Target: x86_64-apple-darwin15.2.0
Configured with: ../configure --build=x86_64-apple-darwin15.2.0
--prefix=/usr/local/Cellar/gcc49/4.9.3
--libdir=/usr/local/Cellar/gcc49/4.9.3/lib/gcc/4.9
--enable-languages=c,c++,objc,obj-c++
--program-suffix=-4.9
......
--enable-stage1-checking
--enable-checking=release
--with-build-config=bootstrap-debug
--disable-werror
--with-pkgversion='Homebrew gcc49 4.9.3'
Thread model: posix
gcc version 4.9.3 (Homebrew gcc49 4.9.3)
COLLECT_GCC_OPTIONS='-mmacosx-version-min=10.12.7' '-v' '-D' 'DEBUG' '-std=c99' '-mtune=core2'
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
#include "..." search starts here:
#include <...> search starts here:
/usr/local/Cellar/gcc@4.9/4.9.3/bin/../lib/gcc/4.9/gcc/x86_64-apple-darwin15.2.0/4.9.3/include
/usr/local/Cellar/gcc@4.9/4.9.3/bin/../lib/gcc/4.9/gcc/x86_64-apple-darwin15.2.0/4.9.3/include-fixed
/usr/local/include
/usr/local/Cellar/gcc@4.9/4.9.3/bin/../lib/gcc/4.9/gcc/../../../../include
/usr/include
/System/Library/Frameworks
/Library/Frameworks
as -arch x86_64 -force_cpusubtype_ALL -o /var/folders/yz/kwcrlzrn6yzdjy4_h_zfpqqc0000gn/T//ccHrUOR3.o /var/folders/yz/kwcrlzrn6yzdjy4_h_zfpqqc0000gn/T//ccjNRfjo.s
|
通过COLLECT_GCC_OPTIONS='-mmacosx-version-min=10.12.7' '-v' '-D' 'DEBUG' '-std=c99' '-mtune=core2
看出gcc
会切分出编译参数;通过#include
可以看出gcc
的搜索头文件的路径。
gcc -Wall
选项
使用man gcc
可以查看-Wall
选项:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| -Wall
This enables all the warnings about constructions that some users consider
questionable, and that are easy to avoid (or modify to prevent the warning), even in
conjunction with macros. This also enables some language-specific warnings
described in C++ Dialect Options and Objective-C and Objective-C++ Dialect Options.
-Wall turns on the following warning flags:
-Waddress
-Warray-bounds=1 (only with -O2)
-Wformat
-Wimplicit-int
-Wimplicit-function-declaration
-Wunknown-pragmas
-Wunused-function
......
-Wunused-label
-Wunused-value
-Wunused-variable
Note that some warning flags are not implied by -Wall. Some of them warn about
constructions that users generally do not consider questionable, but which
occasionally you might wish to check for; others warn about constructions that are
necessary or hard to avoid in some cases, and there is no simple way to modify the
code to suppress the warning. Some of them are enabled by -Wextra but many of them
must be enabled individually.
|
使用gcc --help=warning
可以进一步查看-Wall
选项:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| $ gcc --help=warning
The following options control compiler warning messages:
-Wabi Warn about things that will change when compiling
with an ABI-compliant compiler
-Wabi-tag Warn if a subobject has an abi_tag attribute that
the complete object type does not have
-Waddress Warn about suspicious uses of memory addresses
-Waggregate-return Warn about returning structures, unions or arrays
-Waliasing Warn about possible aliasing of dummy arguments
-Walign-commons Warn about alignment of COMMON blocks
-Wall Enable most warning messages
......
-Warray-bounds Warn if an array is accessed out of bounds
-Wunused-value Warn when an expression value is unused
-Wunused-variable Warn when a variable is unused
|
需要注意的是,各警告选项既然能使之生效,当然也能使之关闭。比如假设我们想要使用-Wall
来启用个选项,同时又要关闭unused
警告,可以通过新增类似Wno-*
的选项来达到目的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| $ cat gcc_warning.c
#include <stdio.h>
#include <stdlib.h>
int main() {
char ch = 'a';
int num = 2028;
printf("num = %d\n", num);
return 0;
}
$ gcc -g -Wall gcc_warning.c -o gcc_warning
gcc_warning.c: In function 'main':
gcc_warning.c:5:10: warning: unused variable 'ch' [-Wunused-variable]
char ch = 'a';
^
$ gcc -g -Wall -Wno-unused gcc_warning.c -o gcc_warning
|
gcc -Werror
选项
1
| -Werror Make all warnings into errors.
|
例如给上述的程序新增-Werror
编译选项:
1
2
3
4
5
6
| $ gcc -Wall -Werror gcc_warning.c
gcc_warning.c: In function 'main':
gcc_warning.c:5:10: error: unused variable 'ch' [-Werror=unused-variable]
char ch = 'a';
^
cc1: all warnings being treated as errors
|
gcc -E
选项
C语言代码在交给编译器之前,会先由预处理器进行一些文本替换方面的操作,例如宏展开、文件包含、删除部分代码等。在正常的情况下,gcc
不会保留预处理阶段的输出文件,也即.i
文件。可以利用-E
选项保留预处理器的输出文件,以用于诊断代码。-E
选项指示gcc在预处理完毕之后即可停止。默认情况下,预处理器的输出会被导入到标准输出流。
1
| $ gcc -E gcc_warning.c -o gcc_warning.i
|
因为头文件可能相当大,如果源文件包括了多个头文件,那么它的预处理器输出可能会庞杂难读。使用-C
选项会很有帮助,这个选项可以阻止预处理器删除源文件和头文件中的注释:
1
| gcc -E -C gcc_warning.c -o gcc_warning.i
|
gcc -S
选项
通常情况下,gcc
把汇编语言输出存储到临时文件中,并且在汇编器执行完后立刻删除它们。但是可以使用-S
选项,让编译程序在生成汇编语言输出之后立刻停止。如果没有指定输出文件名,那么采用-S
选项的编译过程会为每个被编译的输入文件生成以.s
作为后缀的汇编语言文件。如下例所示:
如果想把C语言变量的名称作为汇编语言语句中的注释,可以加上-fverbose-asm
选项:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
| -fverbose-asm
Put extra commentary information in the generated assembly code to make it more
readable. This option is generally only of use to those who actually need to read
the generated assembly code (perhaps while debugging the compiler itself).
$ gcc -S -fverbose-asm gcc_warning.c
$ cat gcc_warning.s
# GNU C (Homebrew gcc49 4.9.3) version 4.9.3 (x86_64-apple-darwin15.2.0)
# compiled by GNU C version 4.9.3, GMP version 4.3.2, MPFR version 2.4.2, MPC version 0.8.1
# GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
# options passed:
# -iprefix /usr/local/Cellar/gcc@4.9/4.9.3/bin/../lib/gcc/4.9/gcc/x86_64-apple-darwin15.2.0/4.9.3/
# -D__DYNAMIC__ gcc_warning.c -fPIC -mmacosx-version-min=10.12.7
# -mtune=core2 -fverbose-asm
# options enabled: -Wnonportable-cfstrings -fPIC
# -faggressive-loop-optimizations -fasynchronous-unwind-tables
# -fauto-inc-dec -fcommon -fdelete-null-pointer-checks -fearly-inlining
# -feliminate-unused-debug-types -ffunction-cse -fgcse-lm -fgnu-unique
# -fident -finline-atomics -fira-hoist-pressure -fira-share-save-slots
# -fira-share-spill-slots -fivopts -fkeep-static-consts
# -fleading-underscore -flifetime-dse -fmath-errno -fmerge-debug-strings
# -fnext-runtime -fobjc-abi-version= -fpeephole -fprefetch-loop-arrays
# -freg-struct-return -fsched-critical-path-heuristic
# -fsched-dep-count-heuristic -fsched-group-heuristic -fsched-interblock
# -fsched-last-insn-heuristic -fsched-rank-heuristic -fsched-spec
# -fsched-spec-insn-heuristic -fsched-stalled-insns-dep -fshow-column
# -fsigned-zeros -fsplit-ivs-in-unroller -fstrict-volatile-bitfields
# -fsync-libcalls -ftrapping-math -ftree-coalesce-vars -ftree-cselim
# -ftree-forwprop -ftree-loop-if-convert -ftree-loop-im -ftree-loop-ivcanon
# -ftree-loop-optimize -ftree-parallelize-loops= -ftree-phiprop
# -ftree-reassoc -ftree-scev-cprop -funit-at-a-time -funwind-tables
# -fverbose-asm -fzero-initialized-in-bss -gstrict-dwarf
# -m128bit-long-double -m64 -m80387 -malign-stringops -matt-stubs
# -mconstant-cfstrings -mfancy-math-387 -mfp-ret-in-387 -mfxsr -mieee-fp
# -mlong-double-80 -mmmx -mno-sse4 -mpush-args -mred-zone -msse -msse2
# -msse3
.cstring
LC0:
.ascii "num = %d\12\0"
.text
.globl _main
_main:
LFB4:
pushq %rbp #
LCFI0:
movq %rsp, %rbp #,
# 汇编中的ch, num变量就是上文程序中的变量
LCFI1:
subq $16, %rsp #,
movb $97, -1(%rbp) #, ch
movl $2028, -8(%rbp) #, num
movl -8(%rbp), %eax # num, tmp85
movl %eax, %esi # tmp85,
leaq LC0(%rip), %rdi #,
movl $0, %eax #,
call _printf #
movl $0, %eax #, D.3126
leave
LCFI2:
ret
|
PS: 这个选项是非常有用,可以在学习gcc
生成的汇编时辅助理解汇编代码。
gcc -ggdb3
选项
通过man gcc
查看-ggdb
选项的用途:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| -ggdb
Produce debugging information for use by GDB. This means to use the most
expressive format available (DWARF, stabs, or the native format if neither of
those are supported), including GDB extensions if at all possible.
-ggdblevel
Request debugging information and also use level to specify how much
information. The default level is 2.
Level 0 produces no debug information at all. Thus, -g0 negates -g.
Level 1 produces minimal information, enough for making backtraces in parts of
the program that you don't plan to debug. This includes descriptions of
functions and external variables, and line number tables, but no information
about local variables.
Level 3 includes extra information, such as all the macro definitions present
in the program. Some debuggers support macro expansion when you use -g3.
|
PS:后续建议在linux平台下使用-ggdb3
替换-g
选项。
gcc -D
选项
使用gcc --help=separate
可以查看-D
选项的含义:
1
2
| -D<macro>[=<val>] Define a <macro> with <val> as its value. If
just <macro> is given, <val> is taken to be 1
|
-D
选项是用来在使用gcc/g++
编译的时候定义宏的。gcc -DDEBUG
中的-D
后面直接跟宏命,相当于定义这个宏,默认这个宏的内容是1。gcc -DKEY=VALUE
表示定义KEY
这个宏,它的内容是VALUE
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| $ cat gcc_def_macro.c
#include <stdio.h>
#include <stdlib.h>
int main() {
#ifdef DEBUG
printf("Defined DEBUG(%d) macro\n", DEBUG);
#else
printf("Not defined DEBUG\n");
#endif
return 0;
}
$ gcc -ggdb3 -Wall gcc_def_macro.c -o gcc_def_macro
$ ./gcc_def_macro
Not defined DEBUG
$ gcc -ggdb3 -Wall -DDEBUG gcc_def_macro.c -o gcc_def_macro
$ ./gcc_def_macro
Defined DEBUG(1) macro
$ gcc -ggdb3 -Wall -DDEBUG=128 gcc_def_macro.c -o gcc_def_macro
$ ./gcc_def_macro
Defined DEBUG(128) macro
|
PS:-Dprivate=public -Dprotected=public
可以用于测试环境,把private
与protected
全替换为public
。比如我们使用gtest
去写单元测试,直接测试目标类的成员函数,但是目标类的成员函它可能是private
或者protected
,所以我们使用这个宏把它们全变成public
。
gcc -U
选项
gcc -U
用于取消宏(用于取消使用-D
选项定义的宏,而不是源码中定义的宏)。
1
2
3
4
5
6
7
8
| -U<macro> Undefine <macro>
$ gcc -ggdb3 -Wall -DDEBUG=512 gcc_def_macro.c -o gcc_def_macro
$ ./gcc_def_macro
Defined DEBUG(512) macro
$ gcc -ggdb3 -Wall -DDEBUG=512 -UDEBUG gcc_def_macro.c -o gcc_def_macro
$ ./gcc_def_macro
Not defined DEBUG
|
gcc -O
选项
使用man gcc
然后搜索--help=optimizers
即可查看优化的选项:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| $ gcc -Q --help=optimizers
The following options control optimizations:
-O<number>
-Ofast
-Og
-Os
-faggressive-loop-optimizations [enabled]
-falign-functions [disabled]
-falign-jumps [disabled]
-falign-labels [disabled]
-falign-loops [disabled]
......
-fasynchronous-unwind-tables [enabled]
-fbranch-count-reg [disabled]
-fbranch-probabilities [disabled]
-fbranch-target-load-optimize [disabled]
-fbranch-target-load-optimize2 [disabled]
-fbtr-bb-exclusive [disabled]
|
根据man gcc
的手册,可以使用如下方式查看-O2
和-O3
的优化区别:
1
2
3
| gcc -c -Q -O3 --help=optimizers > /tmp/O3-opts
gcc -c -Q -O2 --help=optimizers > /tmp/O2-opts
diff /tmp/O2-opts /tmp/O3-opts | grep enabled
|