LV020-编译器选项
一、基本选项
1. 基础编译选项
在 GCC 编译的四个步骤中,我们单独进行每一步的时候都需要使用相应的参数选项:
| 选项 | 说明 |
| -E | 只激活预处理,不生成文件,需要把它重定向到一个输出文件里面。 例如,gcc -E test.c > test.txt |
| -S | 只激活预处理和编译,就是指把文件编译成为汇编代码。 例如,gcc -S test.c # 将生成.s 的汇编代码 |
| -c | 只激活预处理,编译,和汇编,也就是他只把程序做成 obj 文件。 例如,gcc -c test.c # 将生成.o 的 obj 文件 |
| -o | 指定目标名称,缺省的时候,gcc 编译出来的文件默认名称是 a.out。 例如,gcc test.c -o test |
| -v | 显示制作 GCC 工具自身时的配置命令;同时显示编译器驱动程序、预处理器、 编译器的版本号。 例如:gcc -E test.c -o test.i -v |
使用 GCC 编译器编译 C 或者 C++ 程序,必须要经历这 4 个过程,就是预处理,编译,汇编和链接。但考虑在实际使用中,用户可能并不关心程序的执行结果,只想快速得到最终的可执行程序,因此 gcc 和 g++ 都对此需求做了支持。所以我们可以通过 gcc 命令一步直接得到可执行文件:
gcc -c test.c # 将会生成 test.o 文件
gcc test.o -o test # 生成可执行文件,并且指定生成文件名为 test
# 或者直接省略 -c
gcc test.c # 将会直接生成 a.out 可执行文件
gcc test.c -o test # 直接生成可执行文件,并且指定生成文件名为 test2. 警告选项(Warning Option)-Wall
这个选项基本打开了所有需要注意的警告信息,比如没有指定类型的声明、在声明之前就使用的函数、局部变量除了声明就没再使用等。
有时候有的警告虽然对程序没有坏的影响,但是有些警告需要加以关注,比如类型匹配的警告等。
3. -Werror
默认情况下,GCC 在编译代码时,如果遇到警告,仍然会继续编译并生成目标文件或可执行文件。使用 -Werror 后,只要编译器产生任何警告,编译就会立即停止,并返回错误状态。这意味着 代码必须没有任何警告才能编译通过。
在实际的大型项目中,可能不想把所有警告都变成错误,或者只想把特定的警告变成错误。GCC 提供了更灵活的子选项,例如可以通过 -Werror=<warning-name> 将特定的警告升级为错误。
我们想把“未使用的变量”这个警告变成错误,但其他警告保持原样的话,可以用下面的命令:
gcc -Werror=unused-variable main.c
4. 调试选项(Debugging Option)-g
以操作系统的本地格式(stabs, COFF, XCOFF,或 DWARF)产生调试信息,GDB 能够使用这些调试信息。在大多数使用 stabs 格式的系统上, -g 选项加入只有 GDB 才使用的额外调试信息。可以使用下面的选项来生成额外的信息: -gstabs+, -gstabs, -gxcoff+, -gxcoff, -gdwarf+ 或 -gdwarf,具体用法可以参考 GCC 手册。
5. 优化选项(Optimization Option)
gcc 提供了为了满足用户不同程度的的优化需要,提供了近百种优化选项,用来对 编译时间,目标文件长度,执行效率 这个三维模型进行不同的取舍和平衡。优化的方法不一而足,总体上将有以下几类:
- (1)精简操作指令;
- (2)尽量满足 cpu 的流水操作;
- (3)通过对程序行为地猜测,重新调整代码的执行顺序;
- (4)充分使用寄存器;
- (5)对简单的调用进行展开等等。
如果指定了多个-O 选项,不管带不带数字,生效的是最后一个选项。在一般应用中,经常使用 -O2 选项。
| 选项 | 说明 |
|---|---|
| -O0 | 不做任何优化,这是默认的编译选项。 |
| -O 或 -O1 | 优化:对于大函数,优化编译的过程将占用稍微多的时间和相当大的内存。不使用 -O 或 -O1 选项的目的是减少编译的开销,使编译结果能够调试、语句是独立的:如果在两条语句之间用断点中止程序,可以对任何变量重新赋值,或者在函数体内把程序计数器指到其他语句,以及从源程序中精确地获取我们所期待的结果。 不使用 -O 或 -O1 选项时,只有声明了 register 的变量才分配使用寄存器。 使用了 -O 或 -O1 选项,编译器会试图减少目标码的大小和执行时间。如果指定了 -O 或 -O1 选项,-fthread-jumps 和 -fdefer-pop 选项将被打开。在有 delay slot 的机器上,-fdelayed-branch 选项将被打开。在即使没有帧指针 (frame pointer) 也支持调试的机器上,-fomit-framepointer 选项将被打开。某些机器上还可能会打开其他选项。 |
| -O2 | 多优化一些。除了涉及空间和速度交换的优化选项,执行几乎所有的优化工作。例如不进行循环展开(loop unrolling)和函数内嵌(inlining)。 和 -O 或 -O1 选项比较,这个选项增加了编译时间,也提高了生成代码的运行效果。 |
| -O3 | 优化的更多。除了打开 -O2 所做的一切,它还打开了 -finline-functions 选项。 |
二、链接器选项(Linker Option)
这一部分的选项是用于链接 OBJ 文件,输出可执行文件或库文件。
1. object-file-name
如果某些文件没有特别明确的后缀(a special recognized suffix),GCC 就认为他们是 OBJ 文件或库文件(根据文件内容, 链接器能够区分 OBJ 文件和库文件)。
如果 GCC 执行链接操作,这些 OBJ 文件将成为链接器的输入文件。比如
gcc func.o main.o -o main其中的 main.o、 func.o 就是输入的文件。
2. -llibrary(小写的 L)
链接名为 library 的库文件。链接器在标准搜索目录中寻找这个库文件,库文件的真正名字是 liblibrary.a。搜索目录除了一些系统标准目录外,还包括用户以 -L 选项指定的路径。
一般说来用这个方法找到的文件是库文件 ── 即由 OBJ 文件组成的归档文件(archive file)。链接器处理归档文件的方法是:扫描归档文件,寻找某些成员,这些成员的符号目前已被引用,不过还没有被定义。但是,如果链接器找到普通的 OBJ 文件,而不是库文件,就把这个 OBJ 文件按平常方式链接进来。
指定 -l 选项和指定文件名的唯一区别是, -l 选项用 lib 和 .a 把 library 包裹起来,而且搜索一些目录。
2.1 链接库
链接器把多个二进制的目标文件(object file)链接成一个单独的可执行文件。在链接过程中,它必须把符号(变量名、函数名等一些列标识符)用对应的数据的内存地址(变量地址、函数地址等)替代,以完成程序中多个模块的外部引用。
标准库的大部分函数通常放在 静态链接库 libc.a 中(文件名后缀 .a 代表“achieve”,译为“获取”),或者放在用于共享的 动态链接 库 libc.so 中(文件名后缀 .so 代表“share object”,译为“共享对象”)。这些链接库一般位于 /lib/ 或 /usr/lib/,或者位于 GCC 默认搜索的其他目录。
当使用 GCC 编译和链接程序时,GCC 默认会链接 libc.a 或者 libc.so,但是对于其他的库(例如非标准库、第三方库等),就需要手动添加。
2.2 基本格式
-l (小写的 L)参数,用来指定程序要链接的库(库文件在/lib、/usr/lib 和/usr/local/lib 下),-l 参数紧接着就是库名,一般使用格式如下:
gcc -l<lib_name>- lib_name :表示要链接的库名称(不包括库的前缀和后缀)。
【注意】 这个是 小写的 L。
2.3 使用实例
我们在使用 math.h 中的数学函数的时候,会产生函数未定义错误,标准头文件 < math.h > 对应的数学库默认不会被链接,如果没有手动将它添加进来,就会发生函数未定义错误。数学库的文件名是 libm.a。前缀 lib 和后缀 .a 是标准的,m 是库名称,GCC 会在 -l 选项后紧跟着的基本名称的基础上自动添加这些前缀、后缀。如下程序 LV01_GCC_COMPILE/00_compile/05_option_linker,调用了 math.h 中的 cos 函数
#include <stdio.h>
#include <math.h> /* cos */
#define PI 3.14159265
int main(int argc, const char *argv[])
{
double param;
double result;
param = 60.0;
result = cos ( param * PI / 180.0 );
printf ("The cosine of %f degrees is %f.\n", param, result );
return 0;
}然后我们在终端执行以下命令,我们先不加 -l 选项,编译程序,输入以下命令:
gcc main.c不出意外我们会看到以下打印信息:
/usr/bin/ld: /tmp/ccb61up1.o: in function `main':
main.c:(.text+0x3e): undefined reference to `cos'
collect2: error: ld returned 1 exit status会发现有上边的报错信息出现,当我们加上 -l 选项的时候,再编译:
gcc main.c -lm这个时候就不会有信息输出,因为我们的程序编译没有任何问题了。我们用 ldd 命令看一下这个文件的依赖库:
ldd a.out
2.4 默认链接库?
即使不明显地使用-llibrary 选项,一些默认的库也被链接进去,可以使用 -v 选项看到这点,还是使用刚才带有数学库的这个程序 LV01_GCC_COMPILE/00_compile/05_option_linker:
gcc -v main.c -lm我们将会看到以下信息:
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:hsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.4.0-1ubuntu1~20.04.2' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-9-9QDOt0/gcc-9-9.4.0/debian/tmp-nvptx/usr,hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.2)
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-linux-gnu/9/cc1 -quiet -v -imultiarch x86_64-linux-gnu main.c -quiet -dumpbase main.c -mtune=generic -march=x86-64 -auxbase main -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o /tmp/ccf6qxWl.s
GNU C17 (Ubuntu 9.4.0-1ubuntu1~20.04.2) version 9.4.0 (x86_64-linux-gnu)
compiled by GNU C version 9.4.0, GMP version 6.2.0, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.22.1-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-linux-gnu/9/include
/usr/local/include
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
GNU C17 (Ubuntu 9.4.0-1ubuntu1~20.04.2) version 9.4.0 (x86_64-linux-gnu)
compiled by GNU C version 9.4.0, GMP version 6.2.0, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.22.1-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 01da938ff5dc2163489aa33cb3b747a7
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
as -v --64 -o /tmp/ccfeejDk.o /tmp/ccf6qxWl.s
GNU汇编版本 2.34 (x86_64-linux-gnu) 使用BFD版本 (GNU Binutils for Ubuntu) 2.34
COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-linux-gnu/9/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/9/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper -plugin-opt=-fresolution=/tmp/ccoTvGJk.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/9 -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/9/../../.. /tmp/ccfeejDk.o -lm -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'可以看见,还链接了启动文件 Scrt1.o、 crti.o、crtend.o 、 crtn.o,还有一些库文件(-lgcc -lgcc_s -lc)。
3. -nostartfiles
不链接系统标准启动文件,而标准库文件仍然正常使用,还是这个实例 LV01_GCC_COMPILE/00_compile/05_option_linker:
gcc -v -nostartfiles main.c -lm我们将会看到以下打印信息:
# ......
/usr/lib/gcc/x86_64-linux-gnu/9/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/9/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper -plugin-opt=-fresolution=/tmp/cc8zjNED.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -L/usr/lib/gcc/x86_64-linux-gnu/9 -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/9/../../.. /tmp/ccgRZiNF.o -lm -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state
/usr/bin/ld: 警告: 无法找到项目符号 _start; 缺省为 0000000000001050
COLLECT_GCC_OPTIONS='-v' '-nostartfiles' '-mtune=generic' '-march=x86-64'可以看见启动文件 Scrt1.o、 crti.o、 crtend.o 、 crtn.o 没有被链接进去。但是最终还是会生成 a.out 文件。需要说明的是,对于一般应用程序,这些启动文件是必需的,这里仅是作为例子(这样编译出来的 a.out 文件无法执行)。在编译 bootloader、内核时,将用到这个选项。
4. -nostdlib
不链接系统标准启动文件和标准库文件,只把指定的文件传递给链接器。这个选项常用于编译内核、 bootloader 等程序,它们不需要启动文件、标准库文件。 还是以 LV01_GCC_COMPILE/00_compile/05_option_linker 这个文件为例:
gcc -v -nostdlib main.c -lm将会看到以下信息:
#......
/usr/lib/gcc/x86_64-linux-gnu/9/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/9/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper -plugin-opt=-fresolution=/tmp/ccWOd8Ds.res --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -L/usr/lib/gcc/x86_64-linux-gnu/9 -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/9/../../.. /tmp/ccmtDNcr.o -lm
/usr/bin/ld: /tmp/ccmtDNcr.o: undefined reference to symbol 'printf@@GLIBC_2.2.5'
/usr/bin/ld: /lib/x86_64-linux-gnu/libc.so.6: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status出现了一大堆错误,因为 printf 等函数是在库文件中实现的。在编译 bootloader、内核时,用到这个选项 ── 它们用到的很多函数是自包含的。
5. -static
在支持动态链接(dynamic linking)的系统上,阻止链接共享库。仍以 程序为例,是否使用-static 选项编译出来的可执行程序大小相差很大,我们以这个为例 LV01_GCC_COMPILE/00_compile/05_option_linker:
gcc -static main.c -o a_static.out -lm
gcc main.c -o a_no_static.out -lm
du -sh *
当不使用-static 编译文件时,程序执行前要链接共享库文件,所以还需要将共享库文件放入文件系统中。
6. -shared
生成一个共享 OBJ 文件,它可以和其他 OBJ 文件链接产生可执行文件。只有部分系统支持该选项。当不想以源代码发布程序时,可以使用-shared 选项生成库文件。这个就是链接库的制作方法啦,后面还会详细去学习。
7. -Xlinker option
把选项 option 传递给链接器。可以用来传递系统特定的链接选项, GCC 无法识别这些选项。如果需要传递携带参数的选项,必须使用两次 -Xlinker,一次传递选项,另一次传递其参数。例如,如果传递 -assert definitions,这样写:
-Xlinker -assert -Xlinker definitions而不能写成
-Xlinker "-assert definitions"因为这样会把整个字符串当做一个参数传递,显然这不是链接器期待的。
8. -Wl, option
把选项 option 传递给链接器。如果 option 中含有逗号,就在逗号处分割成多个选项。链接器通常是通过 gcc、 arm-linux-gcc 等命令间接启动的,要向它传入参数时,参数前面加上 -Wl,。 例如想要生成 map 文件的话,我们可以用下面的命令:
gcc -o main main.c -lm -Wl,-Map,main.map我们还是可以用 LV01_GCC_COMPILE/00_compile/05_option_linker 这个实例,试一下:

三、目录选项(Directory Option)
下列选项指定搜索路径,用于查找头文件,库文件,或编译器的某些成员。 Directory Options (Using the GNU Compiler Collection (GCC))
1. -ldir
1.1 基本格式
-I (大写的 i )选项用于将指定头文件路径添加到 GCC 的头文件搜索路径中,一般使用格式如下:
-Idir # 单个路径
-Idir1 -Idir2 ... # 多个路径,每个路径都要有 -I ,不同的 -I 之间用空格分隔开在头文件的搜索路径列表中添加 dir 目录。头文件的搜索方法为:如果以 #include < > 包含文件,则只在标准库目录开始搜索(包括使用-Idir 选项定义的目录);如果以 #include " " 包含文件,则先从用户的工作目录开始搜索,再搜索标准库目录。
【注意】
(1)-I 和 dir 直接可以有空格,也可以没有空格.
(2)这个参数是 大写的 i ,有些字体下,看着比较容易与另一个字母混淆。
1.2 使用实例
使用这个实例:LV01_GCC_COMPILE/00_compile/06_option_directory-I,目录结构如下:
.
├── dir1
│ └── func1.h
├── dir2
│ └── func2.h
├── func1.c
├── func2.c
├── main.c我们直接使用如下命令编译:
gcc func1.c func2.c main.c -o main这样会直接报错:

我们加上 -I 选项:
gcc func1.c func2.c main.c -o main -I dir1 -I dir2这个时候就可以正常编译啦,编译完成后会生成 main 可执行文件,我们直接在终端执行 ./main,则会看到如下输出:
This is main file!
This is func1.c file
This is func2.c file2. -I-
分割包含路径。此选项已弃用。下面这段是资料上写的,反正我也没看懂,平时编程也没见过,就简单了解下吧:
任何在 -I- 前面用 -I 选项指定的搜索路径只适用于 #include "file" 这种情况;它们不能用来搜索 #include <file> 包含的头文件。如果用 -I 选项指定的搜索路径位于 -I- 选项后面,就可以在这些路径中搜索所有的 #include 指令(一般说来-I 选项就是这么用的)。还有, -I- 选项能够阻止当前目录(存放当前输入文件的地方)成为搜索 #include "file" 的第一选择。
-I- 不影响使用系统标准目录,因此, -I- 和 -nostdinc 是不同的选项。
3. -Ldir
放在 /lib 和 /usr/lib 和 /usr/local/lib 里的库直接用 -l (小写 L)参数就能链接了,但如果库文件没放在这三个目录里,而是放在其他目录里,这时我们只用-l 参数的话,链接还是会出错,GCC 在链接的时候并不知道除了这些地方的库外要链接的库在哪里。
3.3.1 基本格式
-L 选项可以为 GCC 增加一个搜索链接库的目录,当我们生成了自己的链接库的时候,我们可以用这个参数将其添加到 GCC 的搜索路径下:
# 单个路径
gcc -L<dir>
# 多个路径
gcc -L<dir1> -L<dir2> ...
gcc -L<dir1>:<dir2>: ...- dir :这就是我们要添加的链接库的目录。
【注意】 要是有多个链接库的目录要添加的话,可以使用多个 -L 选项,或者就是在一个-L 选项中用冒号分隔不同的路径。
3.2 使用实例
3.2.1 文件准备
我们先进行一个文件的准备(LV01_GCC_COMPILE/00_compile/06_option_directory-L), 准备完成后,所有文件目录结构如下:
.
├── include
│ ├── func1.h
│ └── func2.h
├── lib
├── main.c
└── src
├── func1.c
└── func2.c3.2.2 制作静态库
由于要链接库,所以要先只做静态库,后边有笔记专门记录静态库和动态库的制作,这里就是记录一个过程。
cd src/ # 进入 func1.c 和 func2.c 源文件所在目录
gcc -c func1.c -o func1.o # 编译 func1.c,生成 func1.o
gcc -c func2.c -o func2.o # 编译 func2.c,生成 func2.o
ar -rsv libfunc.a func1.o func2.o # 打包成静态库
mv libfunc.a ../lib/ # 拷贝到库文件目录下3.2.3 编译主函数源文件
此时我们开始编译主函数,需要注意的是,我们即便做了静态链接库,但是还是需要指定头文件的位置:
gcc main.c -o main -I include/
我们发现是在 ld 的时候出现问题,这说明我们没有链接相应的库,我们加上 -l 选项:
gcc main.c -o main -I include -lfunc此时提示,找不到链接库:

这时候我们为 GCC 指条明路:
gcc main.c -o main -I include -Llib -lfunc这个时候,就会发现,没有报错,正常生成了可执行文件。
4. -Bprefix
这个选项指出在何处寻找可执行文件,库文件,以及编译器自己的数据文件。
编译器驱动程序需要使用某些工具,比如: cpp, cc1 (或 C++的 cc1plus),as 和 ld。它把 prefix 当作欲执行的工具的前缀,这个前缀可以用来指定目录,也可以用来修改工具名字。
对于要运行的工具,编译器驱动程序首先试着加上 -B 前缀(如果存在),如果没有找到文件,或没有指定 -B 选项,编译器接着会试验两个标准前缀 /usr/lib/gcc/ 和 /usr/local/lib/gcc-lib/。如果仍然没能够找到所需文件,编译器就在 PATH 环境变量指定的路径中寻找没加任何前缀的文件名。如果有需要,运行时(run-time)支持文件 libgcc.a 也在 -B 前缀的搜索范围之内。如果这里没有找到,就在上面提到的两个标准前缀中寻找,仅此而已。如果上述方法没有找到这个文件,就不链接它了。多数情况的多数机器上,libgcc.a 并非必不可少。
可以通过环境变量 GCC_EXEC_PREFIX 获得近似的效果;如果定义了这个变量 , 其值就和上面说的一样被用作前缀。如果同时指定了 -B 选 项 和 GCC_EXEC_PREFIX 变量,编译器首先使用 -B 选项,然后才尝试环境变量值。
四、预处理器选项(Preprocessor Options)
可以参考 gcc9.5 的文档:Preprocessor Options (Using the GNU Compiler Collection (GCC))
1. -D
有时候我们想在 c 源文件中使用 Makefile 中定义的某些变量,根据变量的取值做出不同的处理,比如 debug 开关、版本信息等,这时候我们可以通过 gcc 的 -D 选项来满足这一需求,它等同于在 C 文件中通过 #define 语句定义一个宏。
常用的场景就是用 -DDEBUG 定义 DEBUG 宏,然后文件中有 DEBUG 宏部分的相关信息,用个 -DDEBUG 在编译的时候来选择开启或关闭 DEBUG 。
1.1 基本格式
GCC 的 -D 选项就相当于是在 C 语言中定义了一个 #define 宏,一般格式如下:
gcc -D name[=definition]- name:就是表示定义 name 这个宏,可以与-D 之间没有空格
- [= definition] :表示定义的宏的值,这个是可选的,如果不写的话,宏的值 默认是 1。
【注意】 要是需要给宏一个值的话, 等号两端不能有空格。
1.1 GCC 实例
我们可以写一个简单的实例:
#include <stdio.h>
int main(int argc, const char *argv[])
{
printf("This is main file!\n");
#ifdef TEST
printf("TEST=%d\n", TEST);
#else
printf("TEST is not defined!\n");
#endif
return 0;
}我们在终端执行以下命令编译程序,然后执行,会看到如下信息:
gcc main.c
./a.out可以看到如下打印信息:
# 以下为执行可执行程序的输出信息
This is main file!
TEST is not defined!然后我们加上 -D 选项,定义一个宏:
gcc main.c -D TEST
./a.out可以看到如下打印信息:
# 以下为执行可执行程序的输出信息
This is main file!
TEST=1然后我们加上 -D 选项,定义一个带有值的宏:
sumu@virtual-machine:~/1sharedfiles/test$ gcc main.c -D TEST=5
sumu@virtual-machine:~/1sharedfiles/test$ ./a.out
# 以下为执行可执行程序的输出信息
This is main file!
TEST=51.2 Makefile 实例
这部分是后来新加的,make 相关知识可以看后边的笔记。下面的实例可以看 LV01_GCC_COMPILE/00_compile/07_option_preprocessor-D
#include <stdio.h>
int main(int argc, const char *argv[])
{
printf("This is main file!\n");
#ifdef TEST
printf("TEST=%d\n", TEST);
#else
printf("TEST is not defined!\n");
#endif
return 0;
}我们编写一个 Makefile 文件,内容如下:
TEST = 8
all:
gcc main.c -Wall -o main -D TEST=$(TEST)我们编译,并执行可执行文件,结果如下:

参考资料: