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

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

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

有些建议会很棒,也许还可以解释链接器如何完成其​​工作。

谢谢!


对答案的回应

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

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

有帮助吗?

解决方案

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

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

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

其他提示

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

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

以下是一些可帮助您调试问题的其他详细信息。按照惯例,库文件的名称以 lib 为前缀,并且(以静态形式)具有 .a 扩展名。因此,系统默认数学库的静态链接版本(使用 -lm 链接的那个)通常驻留在 /usr/lib/libm.a 中。要查看给定库定义了哪些符号,可以在库文件上运行 nm --define-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

我担心您混淆了库和标头概念。假设你有一个图书馆 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 switch 告诉 gcc 库在哪里,以及 -l 告诉它将您的代码链接到库。

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

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

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

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

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

我想你必须添加链接器可以找到库的路径。在 gcc/ld 中,您可以使用 -L 来完成此操作,而在 libraray 中可以使用 -l 来完成此操作。

-Ldir, --library-path=dir

在标准搜索目录之前进行搜索目录DIR(此选项必须先于搜索该目录的-L选项)。

-larch, --library=存档

在要链接的文件列表中包括存档文件拱。


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

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

gcc -c mylib.c -o mylib.o
ar  rcs libmylib.a      mylib.o

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top