我有一个用C ++编写的系统,该系统构建了一堆共享库和链接到这些共享库(和系统库)的可执行文件。没有代码使用c ++ 11,仅使用学校的C ++。整个混乱情况都在使用GCC 4.3.4的32位旧SUSE Linux 3.0.13机器上维护。它带有生成所有内容的makefile。我正在将整个系统移至具有gcc 4.8的64位处理器上的Ubuntu 16.04。我有一些编译器问题需要解决,但是我花了很多时间来链接东西。
所有共享库都在构建,但是当我尝试构建可执行文件时,出现了许多“未定义引用”错误。我已经验证了链接命令(-l)中包含的库中确实存在这些错误的方法和typeinfo,并且链接命令(-L)中也包含了这些库的路径。我什至创建了链接器映射,并验证了显示为“未定义”的类和方法确实存在于共享库中。
我设法通过对link命令中的共享库列表进行重新排序来解决一些“未定义的引用”问题,但是我不知道为什么这样做会有所不同,因为相同的makefile在SUSE Linux上可以正常工作而没有任何作用需要担心图书馆的秩序。但是,我仍然停留在几个项目上。这是一个示例:
我有一个可执行文件,该文件使用共享库(称为MQWrapper)为Linux Message Queues提供包装器。该项目有一个.cpp文件,该文件使用以下命令编译:
g++ -DZTRACE -DZDEV -I"." -I"../AppIncludes" -I"../ZediCommon" \
-I"../NetworkManagerCommon" -I"../TelitModemDriver" -I"../MQWrapper" \
-I"../Hardware" -I"../WatchdogLib" -I"../BaseClasses" -O0 -g3 -Wall \
-c -fmessage-length=0 -fPIC -MMD -MP -MF"Debug/NetworkProcess.d" \
-o "Debug/NetworkProcess.o" "NetworkProcess.cpp"
这取决于系统中其他共享库。它们的位置在链接命令中由相对路径指定:
g++ -o Debug/networkmanager.1.2.0-DEV ./Debug/NetworkProcess.o \
-L../sharedlibs/Debug -lZediCommon -lMQWrapper -lBaseClasses \
-lorm -lHardware -lWatchdogLib -llog4cplus-1.1 -lNetworkManagerCommon \
-lpthread -lTelitModemDriver -ldl -lrt
如您所见,命令中有“ -lrt”。但是,当我尝试链接时,出现以下链接器错误:
../sharedlibs/Debug/libMQWrapper.so: undefined reference to `mq_unlink'
../sharedlibs/Debug/libMQWrapper.so: undefined reference to `mq_close'
../sharedlibs/Debug/libMQWrapper.so: undefined reference to `mq_getattr'
../sharedlibs/Debug/libMQWrapper.so: undefined reference to `mq_receive'
../sharedlibs/Debug/libMQWrapper.so: undefined reference to `mq_open'
../sharedlibs/Debug/libMQWrapper.so: undefined reference to `mq_setattr'
../sharedlibs/Debug/libMQWrapper.so: undefined reference to `mq_send'
我已验证librt.so共享库是否存在并且在链接程序的搜索路径中。我什至建立了一个使用这些功能的小型测试程序,对其进行编译和链接,然后运行良好。
正如我所说,这只是一些“未定义参考”错误的一个示例,但我认为我会使用这些错误,因为它们是系统性的,很可能最容易解决。
有人知道为什么会这样吗?有人可以建议一些调试技巧吗? SUSE的链接器和Ubuntu的链接器之间可能会导致这些问题的区别吗?
所引用的文章确实很好地解释了编译和链接过程,并指出了可能的原因,但均不适用于我的问题。我已经涵盖了所有建议。
我正在链接正确的库。具体来说,Linux Message Queue函数是在librt.so中实现的(或者至少应该如此),并且我的链接器命令中包含-lrt。
这些是Linux系统提供的功能,因此“已声明但未定义变量或函数”不适用。没有编译器错误,因此功能原型可以从SUSE Linux匹配到Ubuntu Linux。
我正在调用提供C函数原型的Linux系统函数。 “纯虚拟”不适用
“必须实现或定义为纯方法的虚拟方法”不适用。参见3。
“非虚拟班级成员”不适用。参见3。
“常见错误是忘记限定名称”不适用。参见3。
“静态数据成员必须在类之外以单个翻译单元定义”不适用。参见3。
“模板实现不可见”不适用。参见3。
“符号在C程序中定义,并在C ++代码中使用”。不适用。 mqueue.h确实具有“外部“ C”包装函数原型。
跨模块/ dll(特定于编译器)的错误导入/导出方法/类不适用。我正在使用Linux
“如果其他所有方法均失败,请重新编译。”做了很多次。
“正在添加模板...”。参见3。
“不一致的UNICODE定义”。不适用。
“当您的包含路径不同时”。参见2。
“您的链接在引用它们的对象文件之前先使用了库”。并非如此。命令行显示了事物的加载顺序。我也尝试过更改顺序。
“在const变量声明/定义中缺少“ extern”(仅C ++)”。参见2。
“库的不同版本”。我没有链接任何不在该系统上构建的文件。由于我正在针对系统库进行编译和链接,因此这不是问题。
“在链接共享库时,请确保未隐藏使用的符号”。我不在任何地方使用“ -fvisibility = hidden”。
唯一有用的帖子是@Lawrence建议的帖子。使用-v -Wl,-verbose。它验证了链接器正在找到librt.so并正在加载它。现在,如果有人建议为什么链接程序找不到mq_ *符号。
答案 0 :(得分:2)
“您的链接先消耗了引用它们的对象文件的库”。并非如此。命令行显示了事物的加载顺序。我也尝试过更改订单。
这可能仍然是您的问题。取决于系统库的是您的库而不是目标文件,这使您的情况变得复杂。
您可能需要在链接器命令行中的多个地方提及-lrt
。