/usr/bin/ld: warning libopencvxxx.so.a.b,needed by xxx, may conflict with libopencvxxx.so.c.d

  • Post author:
  • Post category:其他



参考



https://zhuanlan.zhihu.com/p/400316912



0.前提描述



0.1.环境

Ubuntu18.04 + ros-melodic

ROS安装的OpenCV3.2.0,安装在根目录,比较分散,比如头文件在

/usr/include

,库文件在

/usr/lib/x86_64-gnu

下。

自己安装的OpenCV3.4.5, 路径是

/usr/local/OpenCV3.4.5

自己安装的OpenCV4.5.1,路径是

/usr/local/OpenCV4.5.1



0.2.使用的工程


  • uav-get-get

    :ROS功能包,使用OpenCV4

  • yn

    :ROS功能包,使用OpenCV3,并且用到

    uav-get-get

    这个功能包。因此为了方便,一开始把

    uav-get-get

    这个功能包的source环境变量语句加到了

    ~/.zshrc


  • r2live

    :港大Mars实验室的SLAM项目,也是ROS工程,使用OpenCV3



1.问题描述

编译港大

r2live

工程,编译的时候出现这个问题,虽然只是警告,但是运行的时候直接报错。

在这里插入图片描述
因为链接库有问题,使用gdb调试发现如下结果,有一部分库链接到了OpenCV4.5的库上,而我cmake指定的是3.4.5的版本。
在这里插入图片描述

这个确实是一个很隐晦的问题。问题就在于ROS工程中用到OpenCV的话,基本上都会用到ROS中的

cv_bridge

用来转换ros和opencv的图片格式。ros安装的opencv是3.2.0版本的,而如果我在cmakelist中指定使用其他版本的OpenCV,很可能就会造成cv_bridge依赖的库出错。从上面的警告来看,都是警告某些OpenCV3的库和Opencv4的库冲突。并且从最后一张图片来看我确实是链接到了OpenCV4的库上,导致程序编译的时候只是给了一个警告,在运行的时候就出错了。后来我把安装的opencv4删除了,然后就没有警告了。实际我的电脑上还有OpenCV3.4.5,和ros版本不同。我觉得此时程序可能仍然错误地连接到了opencv3.4.5的库上,只不过他和cv_bridge用的3.2.0的库主版本号一样,相差不大,所以没有报警告,应该运行也没问题。


不是

!实际测试是全部连接到了OpenCV的3.2.0上,如下图所示。

在这里插入图片描述

根据参考博客中的讲解,我指定查找OpenCV 的路径是ros安装的Opencv路径,即3.2.0版本,编译之后报警告如下图。

在这里插入图片描述

然后对

feature_tracker

这个可执行文件依赖的库进行了查看,发现确实一部分链接到了

OpenCV 4.5.1

的库上,一部分链接到了

OpenCV 3.2.0

上。

在这里插入图片描述


最大的问题

:为什么我在cmakelists.txt中制定了OpenCV的版本是3.4.5,还是会错误的连接到OpenCV4.5.1的库上呢?



2.问题分析过程

  1. 查看自己安装的OpencV 4.5.1的

    OpenCVConfig.cmake

    文件,它的位置也比较奇怪,竟然在lib文件夹下。

    在这里插入图片描述
  2. 在实验室电脑上编译feature_tracker包,其中在cmakelists.txt中明确指明了要使用的OpenCV版本是3.2.0:
find_package(OpenCV 3.2.0 REQUIRED)

但是结果却没有优先找到系统的OpenCV版本上,而是找到了自己安装的3.4.5版本上(说明这台电脑上的ROS自带的OpenCV版本

可能

出了点问题):

在这里插入图片描述

  1. 用EXACT关键字强制指定确定版本,而不是兼容版本:
find_package(OpenCV 3.2.0 EXACT  REQUIRED)

但是这么写结果还是找到了OpenCV3.4.5的版本,所以我感觉写法应该是有点问题,所以把REQUIRED参数去掉了,写成:

find_package(OpenCV 3.2.0 EXACT)

这次确实是找到了正确的版本,但是链接的问题仍然存在:

在这里插入图片描述

  1. 把实验室电脑上的OpenCV4.5.1删除,这下一切正常了。feature_tracker正常链接到了3.2.0的库上,如下图。并且最后编译整个r2live成功,最后也成功运行起来没有任何错误。
    在这里插入图片描述
  2. 在宿舍电脑上再次实验,结果也是也可正常编译整个r2live成功,最后也成功运行起来没有任何错误。但是一个比较奇怪的问题是,如果到编译到feature_tracker为止的话,按理说已经编译出来了feature_tracker这个功能包,但是单独运行它报错,按理说ros的分布式的,编译出来这个功能包应该就可以运行了啊?。可能这个功能包有传入的参数?需要回头看看源码。初步猜测和launch文件中有参数有关:

    在这里插入图片描述
  3. 再次测试,宿舍的电脑上删除了OpenCV4.5.1版本,保留了自己安装的opencv3.4.5,然后在cmakelists.txt中指定链接的版本是3.4.5。
find_package(OpenCV 3.4.5 REQUIRED)

然后编译还是有警告。

在这里插入图片描述

有点明白了,感觉像是库会自动链接到比他高版本的库上。但是为什么上面指定OpenCV3.2.0的时候,没有链接到高版本上呢?


新的想法

:并不是会自动链接到比他高版本的库上!

  1. 在6后面,继续编译r2live包,没有警告,而且程序可以正常跑,没有feature_tracker process has died的错误。

  2. 到实验室电脑上也改成3.4.5版本,结果和宿舍电脑上一样如下图所示。

    在这里插入图片描述

  3. 再次安装opencv4.5.1,目录仍然是/usr/local/opencv4.5.1,但是此时再次编译r2live链接不会链接到4.5.1的库上。

  4. 编译另一个使用opencv4工程uav-target-get。然后再来编译r2live,这个时候就链接到4.5.1了,好像是使用了一次之后系统知道了这个目录。



3. 破案了!破案了!破案了!

问题恰恰出在我的另一个使用opencv4.5.1的工程

uav-target-get

上!因为这个ros包被其他包使用,为了方便使用,就把这个ros包的source环境变量语句加到了~/.zshrc中。也就是每次打开一个shell窗口,都会有这个包的环境变量,比如看

echo $ROS_PACKAGE_PATH

环境变量:

在这里插入图片描述

由于ros是用catkin_make编译的,底层也是cmake,所以

ROS_PACKAGE_PATH

的位置也会在cmake编译查找的变量

CMAKE_PREFIX_PATH

中。

在这里插入图片描述

如果我把source使用opencv4的工程

uav-target-get

环境变量语句在

~/.zshrc

中删掉之后,在重开窗口,这时候查看环境变量中就没有使用opencv4这个工程的路径了。

然后再次编译r2live,就不会再链接到OpenCV4.5.1上了!如果把这个路径再加到环境变量中,再编译r2live,那么又会链接到OPenCV4.5.1上。

所以问题应该就出现在

CMAKE_PREFIX_PATH

环境变量这里!



4.再分析原因?


cmake简明使用指南

:这里面就讲了CMake的语法,好像也没有说上面的原因是什么。

加入

uav-target-get

的环境变量路径,在链接到opencv4.5.1的工程中打开catkin_make编译生成的build 和 devel两个文件夹,用vscode搜索其中的opencv版本4.5.1,结果发现果真有很多和4.5.1有关的内容:

在这里插入图片描述
把上面uav-target-get包的环境变量删掉,再来编译看看,这里结果显示链接不到OpenCV4.5.1了。

在这里插入图片描述
这个时候再用vscode看,只有一个opencv4.5.1了,而且这个只是OpenCV4.5.1版本config.cake路径,说明此时确实没有链接到OpenCV4.5.1上。

在这里插入图片描述


到底这样是为什么不清楚

,因为cmake生成的文件太多太复杂了。

但是猜测一下应该是这样:


由于在

CMAKE_PREFIX_PATH



uav-target-get

的路径,而这个工程使用了OpenCV4.5.1。那么这个工程的build文件夹下的文件中就会存在很多和OpenCV4.5.1有关的内容。而

CMAKE_PREFIX_PATH

是cmake查找的路径,这样cmake在查找库的时候就会把opencv4.5.1的库也链接到,从而造成了有些库的版本被错误链接的情况!



5.使用OpenCV3.4.5还会链接到OpenCV3.2.0上的问题

我现在删掉

uav-target-get

工程的环境变量路径,此时电脑上存在自己安装的OpenCV3.4.5和OpenCV4.5.1,CMakeLists.txt制定使用OpenCV3.4.5,然后此时编译结果:

在这里插入图片描述
看链接的库:

在这里插入图片描述

根据上面的解释,很容易想到这个很有可能是因为用到了

cv_bridge

这个库,因为为了在ros中为了方便处理经常要把图像在ros格式和cv格式互转。查看

cv_bridge

这个库到底依赖了那些库:

cd /opt/ros/melodic/lib/
ldd libcv_bridge.so | grep opencv

结果如下,猜测正确!

这三个库文件恰好就是上面的feature_tracker警告所链接到的OpenCV3.2.0版本的库文件!


在这里插入图片描述

这里虽然同样链接到库出问题了,但是最后编译完整个r2live运行并没有出错。原因应该是3.4.5版本和3.2.0版本的这几个库差别不大,毕竟他们版本号非常相近。但是如果后面使用的OpenCV版本很高,可能这几个库和3.2.0版本的库差别很大呢?此时就只能卸载原来的ros安装的cv_bridge,然后下载github下载源码编译自己匹配的版本的cv_bridge。具体再搜索即可。(但感觉应该不会有人写程序这么搞吧?这不是给自己找麻烦吗?)



6.有使用OpenCV3的工程用到uav-target-get怎么办?

因为

uav-target-get

是一个使用

OpenCV 4.5.1

的ROS工程包,然后另一个使用

OpenCV 3

的ROS功能包

yn

会使用

uav-target-get

这个功能包。那么为了在编译

yn

的时候能够找到

uav-target-get

功能包,就必须source它的环境变量。

这样就带来了上面的问题:现在的yn工程使用OpenCV3,同时还用了

uav-target-get

功能包又必须source它的功能包,由于source了环境变量之后会链接到OpenCV4.5的版本上,这样就会导致库链接冲突的问题。

之前看了编译后

uav-target-get

工程在

build


devel

文件夹下有很多和

OpenCV4.5.1

版本相关的内容,这里想把

build

删掉,是不是尽管source了环境变量,也不会链接到

OpenCV4.5.1

上了?结果没用,还是会链接到上面。因为

uav-target-get

工程的

devel

文件夹下还是有和

OpenCV4.5.1

版本相关的内容。如下图

在这里插入图片描述

看CMakeCache.txt,结果像是大部分链接到了OpenCV4.5.1上,而少部分链接到OpenCV3.2.0上。迷惑?

在这里插入图片描述

但是这个程序运行好像问题不大。

现在想想如果要彻底解决这个链接库的问题,可以怎么做?

  • 现在唯一可以想到的就是自己在CMakeLists.txt中用

    find_library

    手动把OpenCV库写成一个自己的变量,比如

    MY_OpenCV_LIB

    ,然后

    target_link_libraries

    的时候链接

    ${MY_OpenCV_LIB

    ,而不链接

    ${OpenCV_LIBS}

    。但是面对别人的程序很难知道链接了哪些OpenCV库(或许什么都不改先链接,然后ldd看可执行文件就知道链接了哪些库了,但还是比较麻烦),这样就只能在Cmakellist中链接所有的库。OpenCV库又很多,这样导致每个cmakelists文件都要加一大堆内容,太麻烦。

  • 所以想到另一个解决办法就是写一个

    FindOpenCV-3.4.5.cmake

    这种文件放到

    ModulePath

    文件夹下,因为find_package会优先查找Module模式的库,即

    Findxxx.cmake

    这种。然后在

    FindOpenCV-3.4.5.cmake

    中定义头文件和库文件路径,同理这样我们的库名就变成了

    OpenCV-3.4.5

    而非

    OpenCV

    ,链接库的时候也就成了

    ${OpenCV-3.4.5_LIBS}

    ,甚至这个库的名称我们可以在

    FindOpenCV-3.4.5.cmake

    文件中任意定义,保证一定不会和

    ${OpenCV_LIBS}

    重复。



版权声明:本文为qq_42731705原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。