海湾合作委员会中 -lm 的含义是什么?



当我用gcc编译一些C代码时,它需要添加-lm。 例如,当我想在程序中使用fmax时,必须使用以下命令:

gcc myprogram.c -lm

添加-lm对我的程序会发生什么?-lm是什么意思?

TLDNR:math.h 不是标准 C 库的一部分,所以你必须链接到它!

-l 库在链接时搜索库m代表libm,即包含的库。有关详细信息,请参阅这些情侣链接。

@luantkow的回答真的很好,但很长!如果您不想阅读,这里有一个简短的版本!¯\_(ツ)_/¯

假设你有main.c文件:

#include <math.h>
#include <stdio.h>
float my_foo(float a, float b)
{
return fmax(a, b);
}
int main()
{
printf("%fn", my_foo(4.5, 3.1));
return 0;
}

如果您尝试在没有-lm标志的情况下编译它,您将收到未定义的引用错误:

main.o: In function `my_foo':
main.c:(.text+0x1d): undefined reference to `fmax'
collect2: error: ld returned 1 exit status

这是因为链接器不知道fmax函数的任何实现。你必须提供它。

在 gcc man 中,您可以找到以下对-llibrary标志的描述:

链接时搜索名为库的库。 (将库作为单独参数的第二种替代方法仅用于 POSIX 合规性,不建议使用。

命令中编写此选项的位置会有所不同;链接器按指定的顺序搜索和处理库和对象文件。因此,foo.o -lz bar.o 在文件 foo.o 之后但在 bar.o 之前搜索库 z。如果 bar.o 引用 z 中的函数,则可能不会加载这些函数。

链接器搜索库的标准目录列表,该库实际上是一个名为 liblibrary.a 的文件。然后,链接器使用此文件,就像它已按名称精确指定一样。

搜索的目录包括几个标准系统目录以及使用 -L 指定的任何目录。

通常,以这种方式找到的文件是库文件---存档文件,其成员是目标文件。链接器通过扫描存档文件以查找定义到目前为止已引用但尚未定义的符号的成员来处理存档文件。但是,如果找到的文件是普通对象文件,则以通常的方式链接该文件。使用 -l选项和指定文件名之间的唯一区别是 -l 用 lib 和 .a 将库括起来并搜索多个目录。

看起来我有存储在/usr/lib/x86_64-linux-gnu/libm.alibm.a文件:

$ find /usr/lib -iname libm.a
/usr/lib/x86_64-linux-gnu/libm.a

您可以检查libm.a是否包含fmax的定义:

$ nm /usr/lib/x86_64-linux-gnu/libm.a --defined-only | grep fmax
[...]
s_fmax.o:
0000000000000000 W fmax
[...]

如果上面的命令将导致错误,结果如下:

$ nm /usr/lib/x86_64-linux-gnu/libm.a
nm: /usr/lib/x86_64-linux-gnu/libm.a: file format not recognized

这可能是由于您的发行版提供libm.a作为链接器脚本

$ file /usr/lib/x86_64-linux-gnu/libm.a
/usr/lib/x86_64-linux-gnu/libm.a: ASCII text

File/usr/lib/x86_64-linux-gnu/libm.a

/* GNU ld script
*/
OUTPUT_FORMAT(elf64-x86-64)
GROUP ( /usr/lib/x86_64-linux-gnu/libm-2.31.a /usr/lib/x86_64-linux-gnu/libmvec.a )

该脚本基本上通知链接器尝试链接libm-2.31.alibmvec.a。请参阅使用 LD,GNU 链接器中的 GROUP 描述。

因此,您应该能够验证fmax实现是否libm-2.31.a提供:

$ nm /usr/lib/x86_64-linux-gnu/libm-2.31.a --defined-only 2> /dev/null | grep -w fmax
0000000000000000 W fmax

最新更新