gcc --as-needed的使用

本文详细介绍了GNU链接器的--as-needed标志的工作原理及其在减少二进制文件依赖和提升性能方面的作用。文章解释了如何正确使用该标志,并讨论了在编译、链接和执行阶段可能遇到的问题及解决方案,包括未识别选项、未定义符号和配置失败等常见错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自https://wiki.gentoo.org/wiki/Project:Quality_Assurance/As-needed 

Project:Quality Assurance/As-needed

Project:Quality Assurance

This guide is meant to explain how the --as-needed LDFLAG works and to provide steps to fix simple cases where --as-needed fails to build a package.

Contents

 [hide] 

Introduction

What is --as-needed?

The --as-needed flag is passed to the GNU linker (GNU ld ). The flag tells the linker to link in the produced binary only the libraries containing symbols actually used by the binary itself. This binary can be either a final executable or another library.

In theory, when linking something, only the needed libraries are passed to the command line used to invoke the linker. But to workaround systems with broken linkers or not using ELF format, many libraries declare some "dependencies" that get pulled in while linking. A simple example can be found by looking at the libraries declared as dependencies by gtk+ 2.0 :

CODE libraries needed to link to gtk+ 2.0

$ pkg-config gtk+-2.0 --libs
-lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lm -lpangocairo-1.0 -lpango-1.0 -lcairo -lgobject-2.0 -lgmodule-2.0 -ldl -lglib-2.0

Of course, if the application is just using functions from gtk+ 2.0, a simple link line with -lgtk-x11-2.0 should make it build fine, but looking at which libraries are needed and which are not from a package point of view is often an impossible task.

How can --as-needed be useful?

The use of the --as-needed flag allows the linker to avoid linking extra libraries in a binary. This not only improves startup times (as the loader does not have to load all the libraries for every step) but might avoid the full initialization of things like KDE's KIO for a binary if it's not using the KIO framework.

More importantly, the use of --as-needed avoids adding dependencies to a binary that are prerequisites of one of its direct or indirect dependencies. This is important because when a library changes SONAME after an ABI change, all the binaries directly linking to it have to be rebuilt. By linking only the libraries that are actually needed, the breakage due to an ABI change is reduced. It is particularly useful when the ABI breakage happens in a library used by some other high level library (like cairo , which is used directly by gtk+-2.0 , and gets linked indirectly in applications using the latter), as it prevents the rebuild of the final binaries and thus of the packages carrying them.

It is also useful to check whether the dependencies stated by the documentation are actually used by a package: it's not impossible that a package checks in a configure script for some library, and then links to it, but without using it at all because the code using it was removed or refactored or has not been written.

How to use --as-needed

If you want to use the --as-needed flag, you must make sure that you do not override the profiles in /etc/portage/make.conf file or instead manually add the flag back; check emerge --info | grep LDFLAGS to ensure that it is there, if not, you'll want to use the below code example to add it.

 Note
LDFLAGS are generally passed not directly to ld but to gcc, so you have to use the -Wl, prefix to pass them back to the linker.

The below code example shows how to enable it by adding a line in case that you start from a LDFLAGS variable different than those from the profiles:

CODE Enabling --as-needed in /etc/portage/make.conf

LDFLAGS="${LDFLAGS} -Wl,--as-needed"

This flag should conditionally work on every Linux platform supported by binutils. It's known not to work on FreeBSD and probably does not work on other non-Linux targets. As --as-needed depends not only on the way the package you're building is linked but also its dependencies, there are quite a few packages that were silently patched and fixed and might require rebuilding. Please make sure to rebuild the dependencies failing to link against before filing a bug.

 Note
If you use more than one -Wl flag, you have to set -Wl,--as-needed separately in LDFLAGS due to libtool deplib reordering.

Forced --as-needed

Using --as-needed through LDFLAGS is the suggested method for standard users and users who don't want to have too many problems with packages failing to build. For developers, power users, and people who want to stress test buildsystems, a different strategy is also available, that forces each and every build to use --as-needed during the linking phase, as long as the gcc frontend is used as linker.

The forced approach is useful to test packages that don't respect the LDFLAGS variable or packages that incorrectly filter the flag (see the next section for details about that), and to work around the libtool reordering bug. A compiler set to force --as-needed is easily reversed so that if a package is needed to be built without the flag a single switch is required.

To force the --as-needed flag on the compiler, GCC spec files are used, creating a new profile for the compiler that always use it during linking phase. For any version of gcc it is possible to build the modified spec file using the following series of commands

root #export SPECSFILE=$(dirname "$(gcc -print-libgcc-file-name)")/asneeded.specs

root #export CURRPROFILE=/etc/env.d/gcc/$(gcc-config -c)

root #gcc -dumpspecs | sed -e '/link:/,+1 s:--eh-frame-hdr:\0 --as-needed:' > "$SPECSFILE"

root #sed "${CURRPROFILE}" -e '1i\GCC_SPECS='$SPECSFILE > "${CURRPROFILE}-asneeded"

root #gcc-config "$(basename "${CURRPROFILE}")-asneeded"

root #source /etc/profile

To switch between the --as-needed and standard compilers, just use gcc-config like they were different compiler versions or hardened and standard compilers.

Properly filtering --as-needed

Sometimes it is needed to filter --as-needed as the software is designed in such a way that it is not fixable to make use of it. Unfortunately just filtering the flag is often not the best choice because LDFLAGS can be tricky (they can be concatenated through commas, making it impossible to filter them out), and because it is possible to set it as a default through GCC's spec files.

If you really need to disable the --as-needed behaviour, because of design choices that conflicts with the way --as-needed works (and thus not just because the package is broken, and fixable, when building with --as-needed ), what you should be doing is something along these lines.

CODE correct filter for --as-needed behaviour

 
inherit flag-o-matic
...

pkg_setup() {
    append-ldflags $(no-as-needed)
}

 Warning
Please consider using this filtering only if you know that the design of the software conflicts with --as-needed . Do not use this construct if your package simply fails to build after enabling this behaviour.

Fixing problems with --as-needed

Identifying the problem

Developers willing to fix failures related to the --as-needed flag should be aware that there are many cases of failures that may fall into one of a few different categories. I'll try to explain here the reasoning behind the failures and ways to fix them; some of them are really simple, others are not.

If you find a package failing when using --as-needed you may file a bug in Gentoo Bugzilla , blocking bug #129413 .

Failure in compile, unrecognized option

This is at the same time the most simple and the most annoying problem that can be found. There might be packages failing with an error like the following after adding -Wl,--as-needed to LDFLAGS:

CODE common error while using --as-needed

ld: unrecognized option '-Wl,--as-needed'
ld: use the --help option for usage information

This is caused by ld being called with the LDFLAGS variable instead of gcc , thus breaking because it doesn't recognize the -Wl, prefix used to tell gcc to pass the option down to the linker. To fix this, one must pass the output of the raw-ldflags function to the make process.

CODE example of raw-ldflags usage

 
inherit flag-o-matic
...

src_compile() {
    emake LDFLAGS="$(raw-ldflags)" || die "emake failed"
}

Failure in final linking, undefined symbols

This is the most common error that happens while using --as-needed . It happens during the final linking stage of an executable (libraries don't create problems, because they are allowed to have undefined symbols). The executable linking stage dies because of an undefined symbol that is present in one of the libraries fed to the command line. However, the library is not used by the executable itself, thus it gets removed by --as-needed .

This usually means that a library was not linked to another library, but was using it, and then relying on the final executable to link them together. This behavior is also an extra encumbrance on developers using that library because they have to check for the requirements.

The fix to this kind of problem is usually simple: just find which library provides the symbols and which one is requiring them (the error message from the linker should contain the name of the latter). Then make sure that when the library is linked from the source files it's also linked to the first. While using autotools, the dependent library has to be checked in the configure (this should already be the case to specify the dependencies in the pkg-config data file or in the script provided) and then the variable carrying this value should be added to the LIBADD variable for the library to be built.

Failure in execution, undefined symbols

Sometimes the undefined symbol errors don't happen while linking, but rather at the execution of an application built with --as-needed. The cause, however, is just the same as for the undefined symbols in linking: a directly-linked library did not link one of its dependencies. It also has the same solution: find which library carries the undefined symbols and make sure that it gets linked to the library providing them.

Failure in ./configure

Albeit less common than other kind of failures, ./configure execution can fail because of --as-needed too. With this kind of failures, though, it's difficult to give a single and simple solution, as there are multiple reasons that might make the script fail.

The most common option between those that we have now is that a library is checked for, but that library wasn't linked to all its prerequisites (and thus required them to be passed afterward). As --as-needed makes the linker ignore all the libraries not needed by the current target, the prerequisites will result missing.

To check a configure.ac or configure.in file for this kind of failures, you can look for the AC_CHECK_LIB macro, and see whether the fifth parameter is used ( other-libraries ). When it is, it often means that those libraries need to be linked in the final binary to satisfy the dependencies of the library to check for. At that point, the library need to be fixed.

CODE example of AC_CHECK_LIB call with fifth-parameter

 
AC_CHECK_LIB([foo], [foo_something],
             [have_foo=yes], [have_foo=no],
             [-ldl -lnsl])

 Note
While applying patches to libraries to fix --as-needed support, it is usually not the case to apply a revision bump: those who don't want to use the flag don't need to rebuild the library. For this reason, those who want to use --as-needed are invited to run an emerge -e world so that libraries are rebuilt.

Another possible failure during ./configure execution happens when the code is going to check for functions or other particular items (symbols, behaviour) and mistakenly pass the dependency libraries through the LDFLAGS variable.

CODE example of mistake in library checks

 
PKG_CHECK_MODULES([FOO], [foo])

...

save_LDFLAGS=$LDFLAGS
LDFLAGS="$LDFLAGS $FOO_LIBS"

AC_CHECK_FUNCS([foo_choice1 foo_choice2 foo_choice3])

LDFLAGS=$save_LDFLAGS

In this case the solution is very quick: just replace LDFLAGS with LIBS in both saving and restoring. This way the libraries will be passed in the correct order (see the following section for more insight about this kind of problem).

Importance of linking order

One thing that might be frustrating when fixing packages for --as-needed is that sometimes, although all the libraries are present in the linking line, they are just ignored and not linked at all. This leads to the same issues as above; missing symbols either during final link or execution. This is because of a behaviour of the GNU linker that's enforced by --as-needed .

Basically, what the linker does is look for the symbols missing in a given file (either an object file, a static archive or a library) only in the files coming after it. When using the normal linking, without --as-needed , this is not a problem, although there might be some internal drawbacks on the linking stage, the files are linked together without considering ordering. But with the flag, the libraries that aren't used for resolving symbols are discarded and thus not linked.

CODE example of wrong and correct linking order

(in this case libm is considered before the object files and discarded independently from the content of the two.)
$ gcc -Wl,--as-needed -lm someunit1.o someunit2.o -o program

(this is the correct linking order to get libm linked only if needed.)
$ gcc -Wl,--as-needed someunit1.o someunit2.o -lm -o program

The fix in this case is to simply fix the linking order so that the libraries given to the linker are all after the object files and the static archives.

While using autotools there are usually small cases where this happens, because usually libs are fed either via the LIBS variable in the configure script or are listed in the LDADD/LIBADD variables for the target which is being built. The only case when this happens to be a problem is when the libraries get fed into LDFLAGS variable (which is incorrect).

Initializers and Deconstructors

There exists a class of applications at the moment that break when using --as-needed . These applications are not at fault, but rather the linker itself. The linker is unable to detect dependencies between the initializers and deconstructors (.init/.fini ELF sections) when working with C++ code. As such, it may discard libraries when none of the symbols are used from it, thus mistakenly changing the initialization and deconstruction code paths.

While this class of applications is small and there are no known applications yet which fall into this category, this is something to keep in mind. The only way to really detect such a thing is by proper source code and runtime analysis.


This page is based on a document formerly found on our main website gentoo.org
The following people contributed to the original document: Diego Pettenò
They are listed here because wiki history does not allow for any external attribution. If you edit the wiki article, please do not add yourself here; your contributions are recorded on each article's associated history page.Category

<think>好的,我现在需要帮助用户分析他们提供的VCS编译命令的问题。用户给出的命令是:vcs -full64 -cpp g++-4.8 -cc gcc-4.8 -LDFLAGS -Wl,--no-as-needed。用户询问这个命令有什么问题。 首先,我应该回忆一下VCS编译器的常用选项和语法。VCS是Synopsys的Verilog仿真工具,用户在使用时可能会遇到各种选项配置的问题。用户的命令中有几个参数,我需要逐一检查是否正确。 第一个参数是“-full64”,这应该是用来指定编译为64位模式的,这是正确的,没有问题。 接下来是“-cpp g++-4.8”和“-cc gcc-4.8”。VCS在编译过程中可能需要指定C++和C编译器。通常,VCS的选项是“-cpp <compiler>”和“-cc <compiler>”,所以这里看起来语法是正确的。但需要注意用户系统中是否安装了g++-4.8和gcc-4.8版本,如果系统默认的编译器版本不同,或者没有安装这些特定版本,可能会导致问题。不过用户的问题可能不在是否存在这些编译器,而是命令中的其他部分。 然后是“-LDFLAGS -Wl,--no-as-needed”。这里可能存在选项传递的问题。在VCS中,链接器选项通常需要通过“-LDFLAGS”传递,但正确的语法可能是在“-LDFLAGS”后面直接跟选项,或者需要使用其他方式。例如,正确的用法可能是“-LDFLAGS '-Wl,--no-as-needed'”或者使用转义符号确保选项被正确传递。用户可能在这里没有正确引用链接器标志,导致选项被错误解析。 另外,需要考虑选项的顺序是否正确。VCS命令的常规结构是:vcs [options] [design_files] [top_module]。用户的命令中没有指定设计文件和顶层模块,这可能是一个大问题。之前的对话历史中,用户遇到的错误是未指定顶层模块,所以在这个命令中,用户可能遗漏了必要的设计文件和顶层模块名称,导致编译失败。 总结可能的问题点: 1. 缺少设计文件和顶层模块,导致VCS无法开始编译。 2. “-LDFLAGS -Wl,--no-as-needed”可能需要正确的引号或转义,否则选项可能被拆分错误。 3. 使用较旧的gcc/g++版本(4.8)可能与当前系统的兼容性有关,尤其是如果系统默认版本较新,或者这些旧版本未安装。 接下来需要验证这些可能性是否正确。首先,用户是否在命令中遗漏了设计文件和顶层模块?根据之前的错误提示,用户之前可能已经解决了顶层模块的问题,但在这个命令中可能又忘记了添加。其次,关于链接器选项的语法,需要确认VCS中如何正确传递这些参数。例如,是否需要用引号将整个选项括起来,或者使用反斜杠转义。 另外,用户可能想将“-Wl,--no-as-needed”传递给链接器,这通常在解决某些库链接问题时使用。但在VCS中,正确的方式可能需要通过LDFLAGS选项正确传递。例如,正确写法应该是“-LDFLAGS "-Wl,--no-as-needed"”或者使用其他方式确保参数作为一个整体传递。 此外,检查用户是否在正确的目录下执行命令,以及相关文件是否存在。如果用户未指定源文件,VCS将无法找到需要编译的内容,导致错误。 可能的解决方案包括: 1. 添加设计文件和顶层模块到命令中。 2. 修正链接器选项的语法,确保正确传递。 3. 确保指定的编译器版本可用。 最后,需要将这些分析以清晰的中文步骤呈现给用户,指出问题所在,并提供修正后的命令示例。</think>--- 你提供的VCS命令存在**语法错误**和**关键参数缺失**,以下是具体分析和修复方法: --- ### **问题分析** #### 1. **缺少设计文件和顶层模块** - **错误表现**:命令中未指定任何设计文件(如`.v`文件)和顶层模块名,导致VCS无法编译。 - **触发报错**: ```bash Error-[NODESIGN] No design object No design objects were found in the command line or the libraries. ``` #### 2. **链接选项语法错误** - **错误写法**:`-LDFLAGS -Wl,--no-as-needed` - **问题根源**:`-Wl,--no-as-needed`是传递给链接器的参数,但VCS要求通过`-LDFLAGS`选项时需用引号包裹,否则会被拆分为多个无效参数。 #### 3. **编译器版本兼容性风险** - **潜在问题**:`-cpp g++-4.8`和`-cc gcc-4.8`显式指定了较旧的编译器(gcc 4.8),可能导致: - 系统未安装该版本编译器 - 与新版本库或VCS工具链不兼容 --- ### **修复后的命令** ```bash vcs -full64 -cpp g++-4.8 -cc gcc-4.8 -LDFLAGS "-Wl,--no-as-needed" [设计文件列表] [顶层模块名] -o [输出文件名] ``` #### **参数说明** - **必填项**: - `[设计文件列表]`:所有Verilog/VHDL文件(如`file1.v file2.v`) - `[顶层模块名]`:设计的入口模块名(如`tb`) - `-o [输出文件名]`:指定仿真可执行文件(默认`simv`) - **选项修正**: - `-LDFLAGS "-Wl,--no-as-needed"`:引号确保参数完整传递至链接器。 --- ### **完整示例** 假设设计文件为`adder.v`和`tb_adder.v`,顶层模块名为`tb_adder`: ```bash vcs -full64 -cpp g++-4.8 -cc gcc-4.8 -LDFLAGS "-Wl,--no-as-needed" adder.v tb_adder.v tb_adder -o sim ``` --- ### **扩展说明** #### 1. **关键选项解析** | 选项 | 作用 | |------|------| | `-full64` | 强制启用64位编译模式 | | `-cpp`/`-cc` | 指定C++/C编译器(需确保路径有效) | | `-LDFLAGS` | 传递参数给链接器(需引号包裹) | #### 2. **兼容性建议** - 检查gcc/g++ 4.8是否已安装: ```bash g++-4.8 --version # 确认编译器存在 ``` - 若需兼容性模式,可尝试替代选项: ```bash vcs -full64 -override_default_cpp g++-4.8 -override_default_cc gcc-4.8 ... ``` #### 3. **调试方法** - 添加`-debug`或`-debug_all`选项生成调试信息: ```bash vcs -full64 -debug ... [其他参数] ``` --- 如果仍有问题,建议提供完整的文件结构和报错日志,以便进一步定位!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值