将C ++链接到静态库;未定义的引用错误

时间:2018-02-28 10:52:08

标签: c++ static-libraries

我正在尝试将小型C ++测试程序main.o链接到第三方静态库,但会出现一些无法解释的undefined reference错误。

具体做法是:

g++  -o secoTest -lpthread  main.o  libEAPI.a
main.o: In function `main':
main.cpp:(.text+0x29fe): undefined reference to `EApiWDog_SetConfigAndStart(unsigned int, unsigned int, unsigned int, unsigned int, unsigned char, unsigned char, unsigned char)'
main.cpp:(.text+0x33fc): undefined reference to `EApiSetCarrier(unsigned char)'
main.o:main.cpp:(.text+0x3956): more undefined references to `EApiSetCarrier(unsigned char)' follow
main.o: In function `main':
main.cpp:(.text+0x3965): undefined reference to `EApiGPIOGetSerialCfg(unsigned char*)'
main.cpp:(.text+0x3a0a): undefined reference to `EApiSetCarrier(unsigned char)'
main.cpp:(.text+0x3a19): undefined reference to `EApiGPIOSetSerialCfg(unsigned char)'
main.cpp:(.text+0x3adf): undefined reference to `EApiFanEnable(unsigned int, unsigned char)'
main.cpp:(.text+0x3b83): undefined reference to `EApiFanDisable()'
collect2: ld returned 1 exit status

但是,库中似乎存在符号 。例如:

nm --demangle libEAPI.a | grep EApiFanDisable
00003c20 T EApiFanDisable

奇怪的是符号不是完全相同。在main.o中,它是

nm --demangle main.o | grep EApiFanDisable
         U EApiFanDisable()

所以一个人有(),一个没有。

相若方式,

nm --demangle main.o | grep EApiSetCarrier
         U EApiSetCarrier(unsigned char)
nm --demangle libEAPI.a | grep EApiSetCarrier
000015d0 T EApiSetCarrier

如果我从命令行中完全省略了库(例如g++ -o secoTest -lpthread main.o),它会按预期显示许多错误。

main.o引用带有()的外部符号[为什么?]:

     U EApiVgaSetBacklightEnable
     U EApiWDogStart
     U EApiWDogTrigger
     U EApiFanEnable(unsigned int, unsigned char)
     U EApiFanDisable()
     U EApiSetCarrier(unsigned char)

但是图书馆只有没有()的符号[为什么?]:

000020e0 T EApiVgaSetBacklightEnable
000024e0 T EApiWDogStart
000026f0 T EApiWDogTrigger
00003c20 T EApiFanDisable
00003bf0 T EApiFanEnable
000015d0 T EApiSetCarrier

这是未定义引用的原因吗?我该如何解决?不知道下一步该去哪儿......

(我无法修改第三方库,但有头文件。)

修改

正如lisyarus建议的那样,nm没有--demangle。实际上,符号是不同的。 g ++编译器(v4.4.7)仅为某些符号生成一个受损的符号,而库总是有简单符号... [为什么?]

nm libEAPI.a main.o | grep EApiWDogTrigger
000026f0 T EApiWDogTrigger
         U EApiWDogTrigger
nm libEAPI.a main.o | grep EApiSetCarrier
000015d0 T EApiSetCarrier
         U _Z14EApiSetCarrierh

1 个答案:

答案 0 :(得分:6)

libEAPI.a包含在C而不是C++中编译的目标文件。 因此,符号没有被命名,也无法满足 解决由C ++生成的名称错误的函数引用 代码。

执行命令

nm libEAPI.a | grep EApiFanDisable

你会看到没有变化。

执行命令

nm main.o | grep EApiFanDisable

你会看到错位的符号,既不是EApiFanDisable也不是EApiFanDisable() 但更像是_Z14EApiFanDisablev的东西,链接器实际上正在尝试 解决。

要避免这些链接错误,您必须通知C ++编译器 编译libEAPI的头文件,其中包含声明 外部C链接,因此它将发出对声明的符号的未编码引用:如:

<强>的main.cpp

...
extern "C" {
#include "EAPI.h"   // or whatever
}

...

BTW,这个命令行:

g++  -o secoTest -lpthread  main.o  libEAPI.a

无法在基于Debian的发行版上链接libpthread(Ubuntu等) 比Debian 6更新,因为从那时起所有库必须以依赖顺序链接:

g++  -o secoTest main.o  libEAPI.a -lpthread

更好的是,不要使用非便携式-lpthread并传递便携式设备 编译和链接的选项-pthread。这意味着:做任何事情 用Posix Threads支持

进行编译/链接是正确的