未定义引用:怎么了?
undefined reference to : what's wrong?
我正在尝试将自制软件从 AIX 移植到“Red Hat Enterprise Linux 7.8”
我在 link 时遇到“未定义引用”错误,现在我找不到我搞砸的地方。
目标是从 2 个自制共享库(msi 和 atmi)生成一个可执行文件,一些先前编译的对象(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
错误出现 link 次:
/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 命令)上,一切都编译并且 link 很好。
我还尝试更改 linking 命令的库顺序,但没有成功。
我想 linux/gcc 有一些特定的东西,但我还没有找到它。
当您编译 pingsrv.c 时,您尝试使用 -l link msi。你有没有把libmsi.so放在库路径里,这样-l就可以找到了?
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++ 重整,有助于将重载函数分开。
这意味着 extern "C"
在编译 MsiScheduler.cpp 时不适用于函数定义。确保它包含 MsiScheduler.h,并且 header 的那部分不会被任何 #if
跳过。如果这不是问题,请仔细检查 MsiScheduler.h 声明和 MsiScheduler.cpp 定义中的函数参数类型是否完全相同,尽管它们看起来是。
我正在尝试将自制软件从 AIX 移植到“Red Hat Enterprise Linux 7.8”
我在 link 时遇到“未定义引用”错误,现在我找不到我搞砸的地方。
目标是从 2 个自制共享库(msi 和 atmi)生成一个可执行文件,一些先前编译的对象(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
错误出现 link 次:
/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 命令)上,一切都编译并且 link 很好。
我还尝试更改 linking 命令的库顺序,但没有成功。
我想 linux/gcc 有一些特定的东西,但我还没有找到它。
当您编译 pingsrv.c 时,您尝试使用 -l link msi。你有没有把libmsi.so放在库路径里,这样-l就可以找到了?
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++ 重整,有助于将重载函数分开。
这意味着 extern "C"
在编译 MsiScheduler.cpp 时不适用于函数定义。确保它包含 MsiScheduler.h,并且 header 的那部分不会被任何 #if
跳过。如果这不是问题,请仔细检查 MsiScheduler.h 声明和 MsiScheduler.cpp 定义中的函数参数类型是否完全相同,尽管它们看起来是。