2020-08-14 10:27:14 +08:00
# GCC 编译连接参数
2021-09-02 21:22:27 +08:00
## 1. 编译参数
2020-08-14 10:27:14 +08:00
2022-06-22 16:06:35 +08:00
GCC 编译程序的一般格式为:
```bash
gcc -o < target > < source files > [other parameters]
```
2021-10-16 17:50:51 +08:00
### 1.1. 常用参数
2020-08-14 10:27:14 +08:00
2021-10-16 17:50:51 +08:00
* -c: 只编译不链接: 产生 .o 文件(就是 obj 文件),不产生执行文件
* -o: 指定输出文件名
* -g: 可执行程序包含调试信息
* -O\<n\>:设置优化级别
* -static: 链接静态库, 禁止使用动态库
* -shared: 进行动态库编译, 链接动态库
2022-06-22 16:06:35 +08:00
* -I\<dir\>:在头文件的搜索路径中增加 dir 目录
2021-10-16 17:50:51 +08:00
* -L\<dir\>:在动态库的搜索路径中增加 dir 目录
* -l\<name\>: 链接静态库( libname.a) 或动态库( libname.so) 的库文件
* -fPIC(或 fpic):生成使用相对地址无关的目标代码
### 1.2. 编译警告控制参数
#### 1.2.1. -Werror
2020-08-14 11:33:10 +08:00
2020-08-14 10:52:23 +08:00
-Werror: 将所有的警告当成错误进行处理。
2020-08-14 10:27:14 +08:00
2021-10-16 17:50:51 +08:00
#### 1.2.2. -Wall
2020-08-14 11:33:10 +08:00
2020-08-14 10:52:23 +08:00
-Wall: 打开 gcc 的所有警告,主要包括以下部分:
2020-08-14 10:27:14 +08:00
2020-08-14 10:52:23 +08:00
```blk
-Waddress
2020-08-14 11:33:10 +08:00
-Warray-bounds=1 (only with -O2)
-Wbool-compare
-Wbool-operation
-Wc++11-compat-Wc++14-compat
-Wcatch-value (C++ and Objective-C++ only)
-Wchar-subscripts: 警告如果数组下标有char类型。 这是错误的常见原因,因为程序员经常忘记这种类型是在某些机器上签名的。
-Wcomment
2020-08-14 10:52:23 +08:00
-Wduplicate-decl-specifier (C and Objective-C only)
-Wenum-compare (in C/ObjC; this is on by default in C++)
-Wformat
-Wformat-security: 开启类型不匹配警告。
2020-08-14 11:33:10 +08:00
-Wint-in-bool-context
2020-08-14 10:52:23 +08:00
-Wimplicit (C and Objective-C only)
-Wimplicit-int (C and Objective-C only)
-Wimplicit-function-declaration (C and Objective-C only)
-Winit-self (only for C++)
-Wlogical-not-parentheses
2020-08-14 11:33:10 +08:00
-Wmain (only for C/ObjC and unless -ffreestanding)
2020-08-14 10:52:23 +08:00
-Wmaybe-uninitialized
-Wmemset-elt-size
-Wmemset-transposed-args
-Wmisleading-indentation (only for C/C++)
-Wmissing-attributes
-Wmissing-braces (only for C/ObjC)
2020-08-14 11:33:10 +08:00
-Wmultistatement-macros
-Wnarrowing (only for C++)
-Wnonnull
-Wnonnull-compare
2020-08-14 10:52:23 +08:00
-Wopenmp-simd
2020-08-14 11:33:10 +08:00
-Wparentheses
-Wpointer-sign
2020-08-14 10:52:23 +08:00
-Wreorder
-Wrestrict
2020-08-14 11:33:10 +08:00
-Wreturn-type
-Wsequence-point
2020-08-14 10:52:23 +08:00
-Wsizeof-pointer-div
-Wsizeof-pointer-memaccess
2020-08-14 11:33:10 +08:00
-Wstrict-aliasing
-Wstrict-overflow=1
-Wswitch
-Wtautological-compare
-Wtrigraphs
-Wuninitialized
-Wunknown-pragmas
2020-08-14 10:52:23 +08:00
-Wunused-function: 开启未使用的函数警告。
-Wunused-label
-Wunused-value
2020-08-14 11:33:10 +08:00
-Wunused-variable
2020-08-14 10:52:23 +08:00
-Wvolatile-register-var
```
2020-08-14 10:27:14 +08:00
2020-08-14 10:52:23 +08:00
每个警告参数都有对应的“-Wno-”参数实现相反的控制,例如:
2020-08-14 10:27:14 +08:00
2020-08-14 10:52:23 +08:00
```blk
-Wno-unused-parameter: 关闭未使用的参数警告。
2020-08-14 10:27:14 +08:00
-Wno-unused-function: 关闭未使用的函数警告。
-Wno-format-security: 关闭类型不匹配警告。
-Wno-sign-compare: 关闭有符号数和无符号数比较警告。
2020-08-14 10:52:23 +08:00
```
2020-08-14 10:27:14 +08:00
在同时开启 -Wall 和 -Werror 时将使编译警告变为编译错误,此时语法检查非常严格,如需放开某些限制,可结合“-Wno-”类参数使用,例如:-Wall -Werror -Wno-unused-parameter -Wno-unused-function。
2020-08-14 11:33:10 +08:00
2021-10-16 17:50:51 +08:00
#### 1.2.3. -Wextra
2020-08-14 11:33:10 +08:00
-Wextra: 启用一些未由-Wall启用的额外警告标志。 (此选项过去称为-W ,旧名称仍然受支持,但更新的名称更具描述性。)
```blk
-Wclobbered
-Wcast-function-type
-Wempty-body
-Wignored-qualifiers
-Wimplicit-fallthrough=3
-Wmissing-field-initializers
-Wmissing-parameter-type (C only)
-Wold-style-declaration (C only)
-Woverride-init
-Wsign-compare (C only):开启有符号数和无符号数比较警告。
-Wtype-limits
-Wuninitialized
-Wshift-negative-value (in C++03 and in C99 and newer)
-Wunused-parameter (only with -Wunused or -Wall):开启未使用的参数警告。
-Wunused-but-set-parameter (only with -Wunused or -Wall)
```
选项 -Wextra 还会打印以下情况的警告消息:
指针与整数零与< , < = , >或>= 。
( 仅限C ++)枚举器和非枚举器都出现在条件表达式中。
( 仅限C ++)不明确的虚拟基础。
( 仅限C ++) 为已声明为register的数组下标。
( 仅限C ++) 取得已声明register的变量的地址。
( 仅限C ++)基类不在派生类的复制构造函数中初始化。
2021-10-16 17:50:51 +08:00
### 1.3. -fomit-frame-pointer
2021-01-14 10:49:46 +08:00
2021-09-02 21:22:27 +08:00
GCC 会在汇编时加入一些堆栈跟踪信息,以便调试系统能够获取堆栈及调用信息如 call trace 等, 称为“stack frame pointer(SFP)”,通过 -fomit-frame-pointer 参数可关闭之。
## 2. 连接参数
### 2.1. rpath/rpath-link
2021-01-14 10:49:46 +08:00
2021-10-16 17:50:51 +08:00
* -rpath-link: 用于“链接”的时候的, 例如你显式指定的需要 FOO.so, 但是 FOO.so 本身是需要 BAR.so 的,后者你并没有指定,而是 FOO.so 引用到它,这个时候,会先从 -rpath-link 给的路径里找。
* -rpath: 用于“运行”的时候。运行的时候,如果要找 FOO.so 文件,会从这个选项里指定的地方去找。对于交叉编译,交叉编译链接器需已经配置 --with-sysroot 选项才能起作用。也就是说,-rpath 指定的路径会被记录在生成的可执行程序中,用于运行时查找需要加载的动态库。
举例如下:
2021-01-14 10:49:46 +08:00
如果 prog 依赖 libfoobar.so, 而 libfoobar.so libfoo.so 和 libbar.so, 按如下方式编译 program 将产生编译错误:
```bash
$ gcc -c -Wall main.c
$ gcc -o prog main.o -L. -lfoobar
/usr/bin/ld: warning: libfoo.so, needed by ./libfoobar.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: warning: libbar.so, needed by ./libfoobar.so, not found (try using -rpath or -rpath-link)
./libfoobar.so: undefined reference to `bar'
./libfoobar.so: undefined reference to `foo'
collect2: error: ld returned 1 exit status
```
此时可在编译 prog 时增加 -rpath/-rpath-link 参数:
```bash
gcc -o prog main.o -L. -lfoobar -Wl,-rpath=$(pwd)
```
即可。此时能够正常编译和运行 prog, 因为相关信息已经被写入到 libfoobar.so 文件中:
```bash
$ readelf -d prog
Dynamic section at offset 0xe08 contains 26 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libfoobar.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000f (RPATH) Library rpath: [/home/imk/develop/so/scrap]
... ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
```
2021-10-16 17:50:51 +08:00
-rpath-link 只用于链接时查找。运行可执行程序时,-rpath-link 指定的路径不再有效,而 -rpath 指定的路径还有效。
The linker uses the following search paths to locate required shared libraries:
1. Any directories specified by -rpath-link options.
2. Any directories specified by -rpath options. The difference between -rpath and -rpath-link is that directories specified by -rpath options are included in the executable and used at runtime, whereas the -rpath-link option is only effective at link time. Searching -rpath in this way is only supported by native linkers and cross linkers which have been configured with the --with-sysroot option.
3. On an ELF system, for native linkers, if the -rpath and -rpath-link options were not used, search the contents of the environment variable "LD_RUN_PATH".
4. On SunOS, if the -rpath option was not used, search any directories specified using -L options.
5. For a native linker, the search the contents of the environment variable "LD_LIBRARY_PATH".
6. For a native ELF linker, the directories in "DT_RUNPATH" or "DT_RPATH" of a shared library are searched for shared libraries needed by it. The "DT_RPATH" entries are ignored if "DT_RUNPATH" entries exist.
7. The default directories, normally /lib and /usr/lib.
8. For a native linker on an ELF system, if the file /etc/ld.so.conf exists, the list of directories found in that file.
If the required shared library is not found, the linker will issue a warning and continue with the link.
2021-09-03 11:08:36 +08:00
2022-06-22 15:15:52 +08:00
在 Makefile 中设置 LD_RUN_PATH/LD_LIBRARY_PATH 的话,需要将环境变量的设置写到具体的编译命令一行中,因为 Makefile 规则中的每一行都在其自己的 shell 实例中运行,如:
```Makefile
CC=LD_LIBRARY_PATH=/my/library/path gcc
foo:
CC $< -o $ @
```
2022-06-22 15:13:55 +08:00
2021-09-02 21:22:27 +08:00
## 3. 外部参考资料
2020-08-14 11:33:10 +08:00
1. [gcc警告选项汇总 ](https://blog.csdn.net/qq_17308321/article/details/79979514 )