简介

Linux 下最常用的 C 编译器是 GCC,大多数发行版本都默认安装了 GCC。我们可以用以下 GCC 命令,把 test.c 编译成可执行文件 testgcc -g test.c -o test

如果大家习惯了 Visual Studio 等集成开发环境的话,会觉得上述的命令很费解。但掌握 GCC 等工具的用法,是一个程序员所必备的技能。

回到上面的 GCC 命令,它的作用是编译源文件 test.c 并生成可执行文件。其中 -o 表示生成的可执行文件名为 test-g 表明要在可执行文件中添加调试信息。如果要使用 GDB 单步调试程序,必须使用 -g 参数。

可以看到,GCC 的行为是通过命令行参数进行指定的。所以,要掌握 GCC,重点在于熟悉 GCC 的各种参数上。但 GCC 的参数实在太多了,所以更普遍的做法是掌握其常用参数,并在遇到不认识的参数时多查资料进行学习。

GCC 的常用参数

-c

作用:只对源文件进行编译操作。

例子: gcc -c test.c

说明:这将生成目标文件(object file)test.o。

-E

作用:只对源文件进行预处理操作。

例子: gcc -E test.c > test.pre

-o

作用:指定输出文件(目标文件或者可执行文件)的文件名。

例子:gcc test.c -o test

说明:指定可执行文件的文件名为 test,否则默认为 a.out

-D

作用:定义一个宏。

例子:gcc test.c -o test –DBIG_ENDIAN

说明:这和我们在源代码中加入语句 #define BIG_ENDIAN 的效果是一样的。

-M

作用:生成目标文件的依赖信息。

例子:执行 gcc -M test.c,输出结果如下所示。这表明要编译出目标文件 test.o,必须依赖源文件 test.c以及一堆的头文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
test.o: test.c/usr/include/stdio.h/usr/include/features.h \

/usr/include/sys/cdefs.h/usr/include/gnu/stubs.h \

/usr/lib/gcc/i386-redhat-linux/3.4.3/include/stddef.h \

/usr/include/bits/types.h/usr/include/bits/wordsize.h \

/usr/include/bits/typesizes.h/usr/include/libio.h \

/usr/include/_G_config.h \

/usr/include/wchar.h/usr/include/bits/wchar.h \

/usr/include/gconv.h \

/usr/lib/gcc/i386-redhat-linux/3.4.3/include/stdarg.h \

/usr/include/bits/stdio_lim.h/usr/include/bits/sys_errlist.h

说明:大家要记住 “依赖(dependency)” 这个新名词。在学习 Makefile 时,这个名词还会不断出现。

-O0/-O1/-O2/-O3

作用:O 是大写的英文字母 o,对应 Optimization。它指定编译器的优化选项,-O0 表示没有优化,-O1 为缺省值,-O3 优化级别最高。

例子:无

说明:只有对代码进行反汇编,我们才能看到这四个编译选项之间的差异。比如内联函数,在 -O0 作用下和普通函数无任何区别,仍需要显示调用;但在其他优化级别下,内联函数就会被直接嵌入被调用处。

-g

作用:-g 表明要在可执行文件中添加调试信息。如果要使用 GDB 单步调试程序,必须使用 -g 参数。

例子:无

说明:无

小结:上面只是列举了 gcc 的一小部分参数。如果在实际工作中遇到你不认识的参数,多使用 man gcc 命令学习。

ld、objdump、strip

以下简单介绍其他常用的编译、链接工具。在实际工作中,接触它们的机会相对较少,这里只作简单介绍。

ld:负责链接工作。较常用。

objdump:对目标文件和可执行文件进行反汇编。较常用。

例子:objdump –D test > test.S

strip:含义为 symbol table rip,它会删除目标文件或可执行文件中的符号表,在精简可执行文件的体积时会用到。

readelf:读取 elf 文件,并列出其详细信息,较少使用。

库依赖

有时候我们的代码要依赖标准库以外的库函数,如果库文件不在默认路径下,要显式地指明头文件/库文件的路径:

头文件用 -I

库文件用 -L,用 -l 指明要寻找的库,例如引用 libcurl.so,则加上 -lcurl

例如:

1
2
3
gcc test.c -I /home/curl/include -o test.o

gcc test.c -L /home/curl/lib -lcurl o test.o