gcc / -Wl,--as-needed、 -Wl,--no-as-needed

本文详细介绍了GCC/G++的链接选项-Wl,--as-needed和-Wl,--no-as-needed的用法和影响。通过-Wl,--as-needed,可执行文件只包含必要的库信息,减少启动时加载无关库,提高效率;而-Wl,--no-as-needed则会记录所有指定库,即使未使用。通过实例展示了两个选项在编译和运行时的区别。

一、说明

gcc 提供了 -Wl,--as-needed 和 -Wl,--no-as-needed 两个选项,这两个选项一个是开启特性,一个是取消该特性。

在生成可执行文件的时候,通过 -lxxx 选项指定需要链接的库文件。以动态库为例,如果我们指定了一个需要链接的库,则连接器会在可执行文件的文件头中会记录下该库的信息。而后,在可执行文件运行的时候,动态加载器会读取文件头信息,并加载所有的链接库。在这个过程中,如果用户指定链接了一个毫不相关的库,则这个库在最终的可执行程序运行时也会被加载,如果类似这样的不相关库很多,会明显拖慢程序启动过程。

这时,通过指定 -Wl,--as-needed 选项,链接过程中,链接只会检查所有的依赖库,没有实际被引用的库,不再写入可执行文件头。最终生成的可执行文件头中包含的都是必要的链接库信息。

-Wl,--no-as-needed 选项不会做这样的检查,会把用户指定的链接库完全写入可执行文件中。

二、栗子

#include <iostream>

int main() 
{
    std::cout << "Hello, World" << std::endl;
}

1,使用 -Wl,--no-as-needed 选项,且编译时指定加载不相关的 pthread库。

g++ -Wl,--no-as-needed -lpthread -o main main.cc

(1)查看可执行文件 main 的文件头中是否包含 pthread 库:

        linux-vdso.so.1 (0x00007ffe5d13c000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fe196b88000)
        libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fe196a04000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fe196881000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fe196867000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe1966a6000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fe196bcb000) 

可见可执行文件 main 中包含了不相关的 pthread 库。 

(2)查看运行时是否加载 pthread 库。

strace ./main

...

openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3

...

可见,在程序运行时也加载了 pthread 库。 

2,使用 -Wl,--as-needed 选项,且编译时指定加载不相关的 pthread 库。

g++ -Wl,--as-needed -lpthread -o main main.cc

(1)查看可执行文件 main 的文件头中是否包含 pthread 库:    

 ldd main

         linux-vdso.so.1 (0x00007ffce44b7000)
        libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fd84013f000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd83ff7e000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fd83fdfb000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fd8402e5000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fd83fde1000)

可见即使在命令行中指定了 -lpthread,一旦指定了 -Wl,--as-needed 选项,由于 pthread 库不是必须的,所以不会在可执行文件中记录 pthread 库。 

(2)通过执行 strace ./main 命令,运行结果显示也不会去加载 pthread 库。

三、总结

  1. -Wl,--as-needed 选项指示最终的可执行文件中只包含必要的链接库信息;
  2. -Wl,--no-as-needed 选项指示在命令行中指定加载的所有库都记录到可执行文件头中,并最终由动态加载器去加载。

转载:GCC/G++选项 -Wl,--as-needed_weixin_33832340的博客-优快云博客

(SAW:Game Over!) 

book@100ask:~/openwrt/linux-intelligent-gateway/gateway-240228$ make arm-poky-linux-gnueabi-gcc -Wall -Wextra -I/home/book/openwrt/linux-intelligent-gateway/gateway-240228 --sysroot=/home/book/openwrt/linux-intelligent-gateway/gateway-240228/sysroot -o gateway app/app_router.o app/app_buffer.o app/app_bluetooth.o app/app_runner.o app/app_device.o app/app_mqtt.o app/app_message.o app/app_task.o app/app_serial.o daemon/daemon_process.o daemon/daemon_runner.o thirdparty/log.c/log.o thirdparty/cJSON/cJSON.o main.o -Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed -lpaho-mqtt3c -lcrypto -lpthread -lrt /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: error: gateway uses VFP register arguments, app/app_router.o does not /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: failed to merge target specific data of file app/app_router.o /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: error: gateway uses VFP register arguments, app/app_buffer.o does not /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: failed to merge target specific data of file app/app_buffer.o /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: error: gateway uses VFP register arguments, app/app_bluetooth.o does not /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: failed to merge target specific data of file app/app_bluetooth.o /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: error: gateway uses VFP register arguments, app/app_runner.o does not /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: failed to merge target specific data of file app/app_runner.o /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: error: gateway uses VFP register arguments, app/app_device.o does not /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: failed to merge target specific data of file app/app_device.o /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: error: gateway uses VFP register arguments, app/app_mqtt.o does not /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: failed to merge target specific data of file app/app_mqtt.o /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: error: gateway uses VFP register arguments, app/app_message.o does not /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: failed to merge target specific data of file app/app_message.o /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: error: gateway uses VFP register arguments, app/app_task.o does not /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: failed to merge target specific data of file app/app_task.o /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: error: gateway uses VFP register arguments, app/app_serial.o does not /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: failed to merge target specific data of file app/app_serial.o /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: error: gateway uses VFP register arguments, daemon/daemon_process.o does not /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: failed to merge target specific data of file daemon/daemon_process.o /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: error: gateway uses VFP register arguments, daemon/daemon_runner.o does not /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: failed to merge target specific data of file daemon/daemon_runner.o /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: error: gateway uses VFP register arguments, thirdparty/log.c/log.o does not /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: failed to merge target specific data of file thirdparty/log.c/log.o /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: error: gateway uses VFP register arguments, thirdparty/cJSON/cJSON.o does not /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: failed to merge target specific data of file thirdparty/cJSON/cJSON.o /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: error: gateway uses VFP register arguments, main.o does not /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/libexec/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/real-ld: failed to merge target specific data of file main.o collect2: error: ld returned 1 exit status Makefile:30: recipe for target 'gateway' failed make: *** [gateway] Error 1 这个报错分析一下
最新发布
10-30
<think>好的,用户现在想了解GCC的链接器选项`-Wl,--as-needed`的含义和用法。我需要先回顾一下自己对这个选项的了解。 首先,`-Wl`是GCC用来传递参数给链接器的选项,后面跟着的`--as-needed`是链接器ld的选项。所以`-Wl,--as-needed`实际上是将`--as-needed`传递给链接器。我记得这个选项的作用是让链接器在链接时只链接那些实际用到的库,而不是所有被指定的库。这有助于减少不必要的依赖,减少可执行文件的大小,并可能优化加载时间。 接下来,我需要确认这个选项的具体行为。例如,当使用`-lfoo`链接库时,如果代码中没有使用该库中的任何符号,那么`--as-needed`会忽略这个库。但如果有用到的话,才会链接。不过需要注意,这个选项的位置可能会影响其效果,因为链接器按顺序处理库文件。如果库被放在对象文件之前,可能无法正确识别依赖关系,导致不必要的库被排除,从而引发链接错误。因此,正确的顺序应该是对象文件在前,库文件在后,并使用`--as-needed`。 另外,用户可能关心如何使用这个选项,以及实际应用中的例子。比如,在编译命令中如何正确放置选项的位置。例如:`gcc main.o -Wl,--as-needed -lfoo -Wl,--no-as-needed -lbar`,这里`-lfoo`会应用`--as-needed`,而`-lbar`则恢复到默认行为,确保即使没有使用到`-lbar`中的符号,也会被链接。 还需要注意常见的问题,比如如果库之间有依赖关系,可能需要调整链接顺序,或者使用`--start-group`和`--end-group`来确保循环依赖的解决,但这样可能会影响`--as-needed`的效果。这时候可能需要权衡是否需要强制链接某些库。 用户可能还希望了解这个选项的典型应用场景,比如在项目构建中优化依赖,减少最终生成的可执行文件大小,或者避免不必要的动态库加载,提升运行时性能。同时,可能需要注意与其他编译选项的交互,比如`-Wl,--no-as-needed`可以局部关闭该选项,以处理特殊情况。 最后,我应该检查是否有相关的引用内容需要参考。用户提供的引用中提到了使用`-Wl,`前缀来传递链接器选项,比如在gcc中使用`-Wl,--start-group`和`-Wl,--end-group`。这可能与处理库依赖有关,但和`--as-needed`的用法不同,需要区分开。同时,用户之前的问题是关于编译器警告选项,而这次是链接器选项,但都属于GCC的编译链接参数范畴,可能需要简要说明两者的区别,但重点放在当前问题。 总结,回答的结构应该是:先解释选项的作用和目的,然后说明用法,包括命令行示例,注意事项,常见问题及解决方案,以及典型应用场景。同时,结合用户之前的问题,可能提到与其他警告选项的区别,但此处主要聚焦于链接器选项`--as-needed`。</think>### **-Wl,--as-needed 选项解析** #### **核心作用** `-Wl,--as-needed` 是传递给链接器 (`ld`) 的选项,用于**按需链接动态库**。其核心目的是**减少不必要的库依赖**,仅链接实际被代码调用的动态库,从而优化可执行文件的体积和运行时加载效率[^1]。 --- #### **使用场景与对比** | **场景** | **默认行为** (`--no-as-needed`) | **启用 `--as-needed`** | **示例说明** | |------------------------|--------------------------------|--------------------------------|--------------------------------------------| | **未使用的库** | 强制链接所有指定库 | 自动过滤未调用的库 | `gcc main.c -lfoo`(若未调用 `libfoo` 的函数则不链接)| | **循环依赖** | 可能导致冗余链接 | 仅保留实际依赖的库 | 避免因依赖传递引入多余库 | | **隐式符号需求** | 可能忽略未直接声明的依赖 | 需显式声明必要依赖 | 需确保关键库(如 `libstdc++`)被显式保留 | --- #### **具体用法** 1. **基本语法** 通过 `-Wl,` 前缀将选项传递给链接器: ```bash gcc main.o -Wl,--as-needed -lfoo -lbar -Wl,--no-as-needed -lbaz ``` - `-lfoo` 和 `-lbar` 应用 `--as-needed` 规则 - `-lbaz` 恢复为默认行为(强制链接) 2. **关键注意事项** - **顺序敏感**:链接器按顺序处理库,建议将对象文件 (`*.o`) 放在库之前: ```bash # 正确顺序 gcc main.o -Wl,--as-needed -lfoo -lbar # 错误顺序(可能导致未链接必要库) gcc -Wl,--as-needed -lfoo -lbar main.o ``` - **关键库保护**:对基础库(如 `libc`, `libstdc++`)需显式保留: ```bash gcc main.o -Wl,--as-needed -lfoo -Wl,--no-as-needed -lstdc++ ``` 3. **实际效果验证** 使用 `ldd` 查看动态库依赖: ```bash # 默认行为 gcc main.c -lunused_lib && ldd a.out # 显示 libunused_lib.so # 启用 --as-needed gcc main.c -Wl,--as-needed -lunused_lib && ldd a.out # 不显示 libunused_lib.so ``` --- #### **常见问题与解决** 1. **链接错误**: - **现象**:未链接必要的间接依赖库(如 `libfoo` 依赖 `libbar`,但代码未直接调用 `libbar`)。 - **解决**:显式添加被依赖的库,或调整链接顺序: ```bash gcc main.o -Wl,--as-needed -lfoo -lbar ``` 2. **与静态库混用**: - **现象**:静态库 (`*.a`) 可能被错误过滤(因静态库无动态符号表)。 - **解决**:对静态库使用 `--no-as-needed`: ```bash gcc main.o -Wl,--as-needed -ldynamic_lib -Wl,--no-as-needed -lstatic_lib ``` --- #### **典型应用** - **嵌入式开发**:减少最终二进制体积。 - **动态插件系统**:避免加载未使用的插件依赖。 - **依赖链优化**:清理构建系统中多余的 `-l` 参数。 --- ### **相关问题** 1. 如何通过编译选项强制保留特定库(即使未显式调用)? 2. `--as-needed` 与 `--start-group`/`--end-group` 在解决循环依赖时的优先级关系? 3. 如何结合 `-Wl,--copy-dt-needed-entries` 处理间接依赖? [^1]: GNU linker 文档明确说明 `--as-needed` 会跳过未实际使用的动态库 (`DT_NEEDED` 条目)。 [^2]: 通过 `-Wl,` 传递参数是 GCC 调用链接器的标准方式,需注意参数格式。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值