9

我的编译器有问题,告诉我有一个“未定义的引用”我想在库中使用的函数。让我分享一些关于这个问题的信息:

  • 我正在使用 gcc for C 进行交叉编译。
  • 我正在调用一个库函数,该函数通过包含的标头访问,该标头包含另一个包含原型的标头。
  • 我已经使用 -I 包含了 headers 目录,并且我确定它已被找到。
  • 我首先创建 .o 文件,然后将它们链接到单独的命令中。

所以我的想法是这可能是我包含库文件的顺序,但我不确定订购它们的正确方法是什么。我尝试在 .o 文件之前和之后包含 headers 文件夹。

一些建议会很棒,也许还有对链接器如何做事的解释。

谢谢!


对答案的回应

  • 没有 .a 库文件,只有 .h 和 .c 在库中,所以 -l 不合适
  • 我对库文件的理解是它只是头文件和源文件的集合,但也许它是从源创建的 .o 文件的集合?!
  • 没有创建库目标文件,也许应该有?是的,似乎我不明白包含和库之间的区别......我会努力的:-)

感谢所有的回复!我学到了很多关于图书馆的知识。我想把所有的回复都作为接受的答案:-)

4

6 回答 6

6

标头提供函数声明和函数定义。要允许链接器找到函数的实现(并摆脱未定义的引用),您需要使用 -l 标志要求编译器驱动程序 (gcc) 链接函数所在的特定库。例如,-lm 将链接数学库。函数的手册页通常会指定必须指定哪个库(如果有)才能找到该函数。

如果链接器找不到指定的库,您可以使用 -L 开关添加库搜索路径(例如,-L/usr/local/lib)。您还可以通过 LIBRARY_PATH 环境变量永久影响库路径。

这里有一些额外的细节可以帮助你调试你的问题。按照惯例,库文件的名称以 lib 为前缀,并且(以其静态形式)具有 .a 扩展名。因此,系统默认数学库的静态链接版本(您使用 -lm 链接的那个)通常位于 /usr/lib/libm.a 中。要查看给定库定义的符号,您可以在库文件上运行 nm --defined-only。在我的系统上,在 libm.a 上运行命令会得到如下输出。

e_atan2.o:
00000000 T atan2

e_asinf.o:
00000000 T asinf

e_asin.o:
00000000 T asin

要查看编​​译器使用的库路径以及默认加载的库,您可以使用 -v 选项调用 gcc。再次在我的系统上,这给出了以下输出。

GNU assembler version 2.15 [FreeBSD] 2004-05-23 (i386-obrien-freebsd) 
using BFD version 2.15 [FreeBSD] 2004-05-23
/usr/bin/ld -V -dynamic-linker /libexec/ld-elf.so.1 /usr/lib/crt1.o 
/usr/lib/crti.o /usr/lib/crtbegin.o -L/usr/lib /var/tmp//ccIxJczl.o -lgcc -lc 
-lgcc /usr/lib/crtend.o /usr/lib/crtn.o
于 2008-09-27T12:23:51.040 回答
5

听起来您没有编译库中的 .c 文件来生成 .o 文件。链接器将在编译库生成的 .o 文件中查找原型的实现

您的构建过程是否编译库 .c 文件?

如果它实际上只是源代码,为什么称它为“库”?

于 2008-09-27T12:38:57.777 回答
2

我担心您将库和标头概念混为一谈。假设您有一个库libmylib.a,其中包含函数和定义其原型myfunc()的相应标头。mylib.h在您的源文件myapp.c中,您包含标题,直接或包含包含它的另一个标题。例如:

/* myapp.h
** Here I will include and define my stuff
*/
...
#include "mylib.h"
...

您的源文件如下所示:

/* myapp.c
** Here is my real code
*/
...
#include "myapp.h"
...
/* Here I can use the function */
myfunc(3,"XYZ");

现在您可以编译它以获得myapp.o

gcc -c -I../mylib/includes myapp.c

请注意, -I 只是告诉 gcc 头文件在哪里,它们与库本身无关!

现在您可以将您的应用程序与真实库链接:

gcc -o myapp -L../mylib/libs myapp.o -lmylib

请注意,-L开关告诉 gcc 库在哪里,并告诉 gcc-l将您的代码链接到库。

如果您不执行此最后一步,则可能会遇到您描述的问题。

可能还有其他更复杂的情况,但从您的问题来看,我希望这足以解决您的问题。

于 2008-09-27T12:33:28.757 回答
1

发布您的makefile,以及您尝试调用的库函数。即使是简单的 gcc makefiles 通常也有这样的一行:

LIBFLAGS =-lc -lpthread -lrt -lstdc++ -lShared -L../shared

在这种情况下,这意味着链接标准 C 库等

于 2008-09-27T13:21:04.663 回答
0

我想你必须添加链接器可以找到图书馆的路径。在 gcc/ld 中,您可以使用 -L 和使用 -l 的库来执行此操作。

-Ldir,--库路径=目录

在标准搜索目录之前搜索目录 dir(此选项必须位于搜索该目录的 -l 选项之前)。

-落叶松,--library=存档

在要链接的文件列表中包含存档文件 arch。


对答案的响应 - 库中没有 .a 库文件,只有 .h 和 .c,所以 -l 不合适

那么您可能必须先创建库?

gcc -c mylib.c -o mylib.o
ar  rcs libmylib.a      mylib.o
于 2008-09-27T12:22:50.560 回答
0

我在使用新版本的 gcc 构建程序时遇到了这个问题。通过使用 -std=gnu89 选项调用 gcc 解决了该问题。显然这是由于内联函数声明。我在https://gcc.gnu.org/gcc-5/porting_to.html找到了这个解决方案

于 2016-10-11T16:43:59.923 回答