【问题标题】:undefined reference to : what's wrong?未定义的参考:怎么了?
【发布时间】:2021-04-23 20:20:54
【问题描述】:

我正在尝试将自制软件从 AIX 移植到“Red Hat Enterprise Linux 7.8”

我在链接时遇到“未定义的引用”错误,现在我找不到哪里搞砸了。

目标是从 2 个自制共享库(msiatmi)、一些先前编译的对象 (MsiServices.o) 和一个 C 程序(pingsrv 。C)。 下面是命令:

gcc -DWall -o bin/pingsrv -DUNIX -I. -g -DUNIX -D_THREAD_SAFE -D_LARGEFILE64_SOURCE -I/home/vgi/git/msi-tools/ping/server/target/msi/include/yaml-cpp -I/home/vgi/git/msi-tools/ping/server/target/msi/include/apr-1 -I/home/vgi/git/msi-tools/ping/server/target/msi/include/activemq-cpp-3.9.4 -I/home/vgi/git/msi-tools/ping/server/target/msi/include /tmp/MsiServices.o ./pingsrv.c -L/home/vgi/git/msi-tools/ping/server/target/msi/lib -lmsi -lactivemq-cpp -llog4cxx -latmi -lapr-1 -laprutil-1 -lexpat -lstdc++ -lyaml-cpp

错误出现链接时间:

/home/vgi/git/msi-tools/ping/server/target/msi/lib/libatmi.so: undefined reference to `Msi_tpreturn'
/home/vgi/git/msi-tools/ping/server/target/msi/lib/libatmi.so: undefined reference to `Msi_tpcall'
/home/vgi/git/msi-tools/ping/server/target/msi/lib/libmsi.so: undefined reference to `msi::service::optarg'
/home/vgi/git/msi-tools/ping/server/target/msi/lib/libatmi.so: undefined reference to `Msi_userlog'

库 atmi 是用 C 编写的,并且能够通过使用包装器调用一些 C++ 实例方法:

...
typedef struct MsiScheduler MsiScheduler ;
extern void Msi_tpreturn(MsiScheduler *,int, long , char *, long, long);
extern void Msi_userlog(MsiScheduler *,char*) ;
extern int Msi_tpcall(MsiScheduler *,char *svc, char *idata, long ilen, char **odata, long *olen, long flags) ;
...
extern void tpreturn(int rval, long rcode, char * data, long len, long flags)
{
    assert(vg_Consumer != NULL) ;
    Msi_tpreturn(vg_Consumer,rval,rcode,data,len,flags) ;

}

此库调用的包装器在另一个名为 msi 的库中定义。包装器在 C++ 源文件 (MsiScheduler.cpp) 中定义:

void Msi_tpreturn(MsiScheduler * c,int ret,long code,char *data,long len,long flags)
{
    TypedBuffer* buffer = NULL ;

    if (data != NULL)
    {
       buffer = TypedBuffer::createBuffer(getType(data),data,len) ; 
    }
    MsiReply * reply = MsiReply::createReply(ret,code,buffer) ;

    c->tpreturn(reply) ;

    if (data != NULL)
    {
       freebuf(data) ;
    }
    delete reply ;
}
int Msi_tpcall(MsiScheduler * c,char *svc, char *idata, long ilen, char **odata, long *olen, long flags)
{
     ...
}
void Msi_userlog(MsiScheduler *c ,char* str)
{
    c->userlog(str) ;
}

头文件(MsiScheduler.h)包含这个片段:

#ifdef __cplusplus
extern "C" {
#endif

#if defined(__STDC__) || defined(__cplusplus)
extern void Msi_tpreturn(MsiScheduler *,int, long , char *, long, long);
extern void Msi_userlog(MsiScheduler *,char*) ;
extern int Msi_tpcall(MsiScheduler *,char *svc, char *idata, long ilen, char **odata, long *olen, long flags) ;
#else
extern void Msi_tpreturn();
extern void Msi_userlog() ;
extern int Msi_tpcall() ;
#endif

#ifdef __cplusplus
}
#endif

图书馆是这样构建的:

g++ -g -fPIC -Wall -I/home/vgi/git/msi/msi-service/target/ext/include/apr-1 -I/home/vgi/git/msi/msi-service/target/ext/include/activemq-cpp-3.9.4 -I/home/vgi/git/msi/msi-service/target/ext/include/yaml-cpp -I/home/vgi/git/msi/msi-service/target/ext/include -I/home/vgi/git/msi/msi-service/target/ext/include -I../lib/inc -I./ -o MsiScheduler.o -c MsiScheduler.cpp
...
g++ -shared MsiUtil.o MsiConfig.o MsiInstrumentation.o MsiMetric.o MsiService.o MsiExceptions.o MsiCharsetConverter.o MsiTypes.o MsiMessage.o MsiMessageUtil.o MsiScheduler.o MsiServer.o -o libmsi.so
...
gcc -g -fPIC -Wall -I/home/vgi/git/msi/msi-service/target/ext/include/apr-1 -I/home/vgi/git/msi/msi-service/target/ext/include/activemq-cpp-3.9.4 -I/home/vgi/git/msi/msi-service/target/ext/include/yaml-cpp -I/home/vgi/git/msi/msi-service/target/ext/include -I/home/vgi/git/msi/msi-service/target/ext/include -I../lib/inc -I./ -o atmi.o -c atmi.c
gcc -shared atmi.o memmngt.o -o libatmi.so

仅供参考,一切都可以在 AIX OS 上很好地编译和链接(使用 xlc、xlC 命令)。

我还尝试更改链接命令的库顺序,但没有成功。

我想有一些特定于 linux/gcc 的东西,但我还没有找到它。

【问题讨论】:

  • 如果我理解正确,调用Msi_tpreturn 的代码在libatmi.so 中,提供Msi_tpreturn 的代码在libmsi.so 中,您必须在@ 之前指定-latmi 987654332@ 在您的链接器命令行中。
  • @Bodo 顺序通常对共享库无关紧要,只有静态库。
  • 请编辑以添加来自:nm -A libmsi.so libatmi.so | grep -E 'Msi_(tpreturn|tpcall|userlog)'的输出
  • 可能不是问题,但是:对于混合了 C 和 C++ 的程序,通常最好 (1) 使用 g++ 而不是 gcc -lstdc++ 链接最终的可执行文件,以及 (2) 定义并在 C++ 中编译 main(如果现有一个是用 C 编写的,只需重命名它并用一个简单的 C++ main 调用它)。
  • @命令的输出下面aschepler:libmsi.so:0000000000034f20Ť_Z10Msi_tpcallPN3msi7service12MsiSchedulerEPcS3_lPS3_Pll libmsi.so:0000000000035138Ť_Z11Msi_userlogPN3msi7service12MsiSchedulerEPc libmsi.so:0000000000034e55Ť_Z12Msi_tpreturnPN3msi7service12MsiSchedulerEilPcll libatmi.so:U Msi_tpcall libatmi.so:U Msi_tpreturn libatmi.so: U Msi_userlog

标签: c++ c linux ld


【解决方案1】:
libmsi.so:0000000000034f20 T _Z10Msi_tpcallPN3msi7service12MsiSchedulerEPcS3_lPS3_Pll
libmsi.so:0000000000035138 T _Z11Msi_userlogPN3msi7service12MsiSchedulerEPc
libmsi.so:0000000000034e55 T _Z12Msi_tpreturnPN3msi7service12MsiSchedulerEilPcll
libatmi.so: U Msi_tpcall
libatmi.so: U Msi_tpreturn
libatmi.so: U Msi_userlog

在您的nm 输出中,T 的意思是右边的符号是在 libmsi.so 中定义的,U 的意思是右边的符号是 libatmi.so 需要的.但显然,这些符号的名称不匹配。 libmsi.so 中的名称具有 C++ 修饰符,有助于将重载函数分开。

这意味着在编译 MsiScheduler.cpp 时,extern "C" 不适用于函数定义。确保它包含 MsiScheduler.h,并且任何#if 都不会跳过该部分标头。如果这不是问题,请仔细检查 MsiScheduler.h 声明和 MsiScheduler.cpp 定义中的函数参数类型是否完全相同,尽管它们似乎是。

【讨论】:

  • 谢谢@aschelper,我将extern "C" 强制到每个函数定义中,它的工作原理!
  • 很高兴你走得更远,但这并不能解释为什么现有的头文件不起作用。
  • 确实,不知道为什么。 Pragma 消息指令向我证实 extern "C" 在头文件中被正确触发。奇怪……
【解决方案2】:

当您编译 pingsrv.c 时,您尝试使用 -l 链接 msi。有没有把 libmsi.so 放到库路径中,让 -l 可以找到?

【讨论】:

  • 是的,我所有的库都位于这个目录中:/home/vgi/git/msi-tools/ping/server/target/msi/lib 此外,这是提供给 gcc 命令行: -L/home/vgi/git/msi-tools/ping/server/target/msi/lib -lmsi
猜你喜欢
  • 2018-11-22
  • 1970-01-01
  • 2011-09-11
  • 2017-10-13
  • 1970-01-01
  • 1970-01-01
  • 2014-12-16
  • 2015-01-14
  • 2023-03-08
相关资源
最近更新 更多