librt和对`mq_unlink'和朋友的未定义引用

时间:2018-12-06 21:37:27

标签: c++ linux ubuntu-16.04

我有一个用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的链接器之间可能会导致这些问题的区别吗?


更新

所引用的文章确实很好地解释了编译和链接过程,并指出了可能的原因,但均不适用于我的问题。我已经涵盖了所有建议。

  1. 我正在链接正确的库。具体来说,Linux Message Queue函数是在librt.so中实现的(或者至少应该如此),并且我的链接器命令中包含-lrt。

  2. 这些是Linux系统提供的功能,因此“已声明但未定义变量或函数”不适用。没有编译器错误,因此功能原型可以从SUSE Linux匹配到Ubuntu Linux。

  3. 我正在调用提供C函数原型的Linux系统函数。 “纯虚拟”不适用

  4. “必须实现或定义为纯方法的虚拟方法”不适用。参见3。

  5. “非虚拟班级成员”不适用。参见3。

  6. “常见错误是忘记限定名称”不适用。参见3。

  7. “静态数据成员必须在类之外以单个翻译单元定义”不适用。参见3。

  8. “模板实现不可见”不适用。参见3。

  9. “符号在C程序中定义,并在C ++代码中使用”。不适用。 mqueue.h确实具有“外部“ C”包装函数原型。

  10. 跨模块/ dll(特定于编译器)的错误导入/导出方法/类不适用。我正在使用Linux

  11. “如果其他所有方法均失败,请重新编译。”做了很多次。

  12. “正在添加模板...”。参见3。

  13. “不一致的UNICODE定义”。不适用。

  14. “当您的包含路径不同时”。参见2。

  15. “您的链接在引用它们的对象文件之前先使用了库”。并非如此。命令行显示了事物的加载顺序。我也尝试过更改顺序。

  16. “在const变量声明/定义中缺少“ extern”(仅C ++)”。参见2。

  17. “库的不同版本”。我没有链接任何不在该系统上构建的文件。由于我正在针对系统库进行编译和链接,因此这不是问题。

  18. “在链接共享库时,请确保未隐藏使用的符号”。我不在任何地方使用“ -fvisibility = hidden”。

唯一有用的帖子是@Lawrence建议的帖子。使用-v -Wl,-verbose。它验证了链接器正在找到librt.so并正在加载它。现在,如果有人建议为什么链接程序找不到mq_ *符号。

1 个答案:

答案 0 :(得分:2)

  

“您的链接先消耗了引用它们的对象文件的库”。并非如此。命令行显示了事物的加载顺序。我也尝试过更改订单。

这可能仍然是您的问题。取决于系统库的是您的库而不是目标文件,这使您的情况变得复杂。

您可能需要在链接器命令行中的多个地方提及-lrt