我的项目代码链接到一些我没有源代码的库。在链接过程中我得到:
/usr/x86_64-suse-linux/bin/ld:libfoo.a(foo.o): in function `flush':
source/readcfg.c:1234:(.text+0xabc): warning: the use of `tmpnam' is dangerous, better use `mkstemp'
/usr/x86_64-suse-linux/bin/libbar.a(.o): in function `getErmes':
source/bar.c:123:(.text+0x1238): warning: `sys_nerr' is deprecated; use `strerror' or `strerror_r' instead
我可以在不编辑 foo 和 bar 的源文件的情况下抑制这些消息(或这些种类的消息)吗?
(注意:对于编译器错误,我们可以设置
-Wsomething
和 -Wno-something
来启用或抑制。对于某些 GNU ld 警告也是如此,因为它的 man ld
描述了几个 --warn
/--nowarn
选项。)
相关:警告:使用`tmpnam'是危险的,最好使用`mkstemp'讨论如何从一开始就避免错误。
.gnu.warning
部分。 (感谢this question给出提示。)也就是说,“tmpnam.o”包含一个名为.gnu.warning.tmpnam
的特殊部分。当 GNU ld
看到该部分(以及 tmpnam
的使用)时,它会打印警告。
根据 fcambus/gwcheck,
.gnu.warning
逻辑在 GNU ld 和 gold 中实现,但不在 LLVM lld 和 Solaris 上实现。
objcopy --remove-section
的“聪明”事情:基本上“预处理”libc.a 或 libc.so 以供您的项目使用,然后链接到预处理/剥离的 libc。
objcopy --rename-section
。
部分解决方案可能涉及
gcc -Wl,--wrap,tmpnam *.o
。这会导致 ld
将每个未解析的对 tmpnam
的引用视为对 __wrap_tmpnam
的未解析引用。但是,您仍然必须编写自己的 __wrap_tmpnam
实现 - 并且您不能仅通过调用 __real_tmpnam
来实现它,因为这会再次触发警告。
当然,如果您愿意重新实现
tmpnam
,那么您可以将自己的tmpnam.o
添加到您的项目中;你不需要参与--wrap
。
最简单的解决方案实际上可能是“使用 GNU ld 的替代品”,例如
mold
或 lld
。 (但不是 GNU gold
,它与 ld
具有相同的行为。)
或者,将您的
CC
/CXX
环境变量设置为不指向 /usr/bin/gcc
而是指向一个简单的 shell 脚本(感谢 this Question 解释如何仅过滤 stderr):
cat >gcc.sh <<EOF
#!/bin/bash
gcc "$@" 2> >(sed -n -e "/tmpnam' is dangerous/{s/.*//;x;d};x;p" >&2)
EOF
CC=./gcc.sh
(抱歉,我的
sed
-fu 不好。这里的目的是消除包含 tmpnam' is dangerous
的行以及紧邻的前一行。)
不起作用的一件事(截至 2024 年)是为
tmpnam
添加您自己的空警告消息,如下所示:
cat >dummy.c <<EOF
static const char msg[0] __attribute__((section(".gnu.warning.tmpnam")));
EOF
cat >main.c <<EOF
#include <stdio.h>
int main() { char s[100]; tmpnam(s); }
EOF
gcc -c main.c dummy.c
这确实“覆盖”了来自 libc.so 的消息,但它不会导致警告消失 - 它只会导致警告 message 变为空,如下所示:
$ gcc dummy.o main.o
/usr/bin/ld: main.o: in function `main':
main.c:(.text+0x10): warning:
(截至 2024 年)似乎没有简单或单行解决这个问题。