链接器出现问题-未定义参考

时间:2020-03-06 14:49:24  来源:igfitidea点击:

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

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

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

一些建议可能很棒,也许还有关于链接程序如何执行其操作的解释。

谢谢!

对答案的回应

  • 没有.a库文件,库中只有.h和.c,所以-l不适用
  • 我对库文件的理解是,它只是头文件和源文件的集合,但是也许是从源文件创建的.o文件的集合?
  • 没有正在创建的库对象文件,也许应该有??是的,我似乎不了解include和库之间的区别...我会努力解决这一问题的:-)

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

解决方案

我想我们必须添加链接程序可以找到libraray的路径。在gcc / ld中,我们可以使用-L进行此操作,而libraray可以使用-l进行此操作。

-Ldir, --library-path=dir 
  
  Search directory dir before standard
  search directories (this option must
  precede the -l option that searches
  that directory).
  
  -larch, --library=archive 
  
  Include the archive file arch in the
  list of files to link.
Response to answers - there is no .a library file, just .h and .c in the library, so -l isn't approriate

然后,我们可能必须先创建天秤座?

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

标头提供函数声明和函数定义。要允许链接器找到该函数的实现(并摆脱未定义的引用),我们需要使用-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

我担心我们会混合使用库和标头概念。
假设我们有一个库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库在哪里,-l告诉它将代码链接到库。

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

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

听起来我们好像没有在库中编译.c文件来生成.o文件。链接器将在通过编译库而产生的.o文件中寻找原型的实现。

构建过程会编译库.c文件吗?

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

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

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

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