【问题标题】:How to trace the need of a library when linking?链接时如何跟踪库的需求?
【发布时间】:2019-06-26 21:36:26
【问题描述】:

快速版本:为什么 gcc 要求一个特定的库?执行 gcc 时如何追踪其依赖关系?

长版:我正在尝试编译使用 opencv 的 c++ 代码,该代码使用 ffmpeg。编译时出现错误:

//usr/lib/x86_64-linux-gnu/libavcodec.so.57: referencia a `swr_alloc@LIBSWRESAMPLE_2' sin definir
//usr/lib/x86_64-linux-gnu/libavcodec.so.57: referencia a `swr_free@LIBSWRESAMPLE_2' sin definir
//usr/lib/x86_64-linux-gnu/libavcodec.so.57: referencia a `swr_is_initialized@LIBSWRESAMPLE_2' sin definir
//usr/lib/x86_64-linux-gnu/libavcodec.so.57: referencia a `swr_close@LIBSWRESAMPLE_2' sin definir
//usr/lib/x86_64-linux-gnu/libavcodec.so.57: referencia a `swr_init@LIBSWRESAMPLE_2' sin definir
//usr/lib/x86_64-linux-gnu/libavcodec.so.57: referencia a `swr_convert@LIBSWRESAMPLE_2' sin definir

我了解 libavcodec.so 需要 libswresample.so,但我希望链接到 libavcodec.so.58,而不是 57。我想跟踪这种依赖关系:我想知道 gcc 为什么要求该文件。

我知道系统中只有 libavcodec.so 会更好,但现在我无法摆脱 libavcodec.so.57。在我的系统中:

$ ldconfig -p | grep libavcodec
libavcodec.so.58 (libc6,x86-64) => /usr/local/lib/libavcodec.so.58
libavcodec.so.57 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libavcodec.so.57
libavcodec.so (libc6,x86-64) => /usr/local/lib/libavcodec.so  <== This is a link to 58)

如果你想知道,gcc命令行是这样的,注意那里没有-lavcodec:

g++ -Wl,--trace-symbol=libavcodec -L/usr/local/lib -L"/home/alejandro/Desarrollo eclipse/os1/Thirdparty" -o "os1"  ./src/Converter.o ./src/Frame.o ./src/FrameDrawer.o ./src/Initializer.o ./src/KeyFrame.o ./src/KeyFrameDatabase.o ./src/KeyFrameTriangulacion.o ./src/LocalMapping.o ./src/LoopClosing.o ./src/Map.o ./src/MapDrawer.o ./src/MapPoint.o ./src/ORBextractor.o ./src/ORBmatcher.o ./src/Optimizer.o ./src/PnPsolver.o ./src/PuntoLejano.o ./src/PuntosLejanosDB.o ./src/Sim3Solver.o ./src/System.o ./src/Tracking.o ./src/Video.o ./src/Viewer.o ./src/main.o ./src/osmap.o ./src/osmap.pb.o   -lopencv_core -lopencv_features2d -lopencv_highgui -lopencv_videoio -lopencv_imgcodecs -lopencv_imgproc -lopencv_calib3d -lpthread -lpangolin -lGL -lGLU -lDBoW2 -lg2o -lprotobuf

此命令要求 libopencv_videoio.so,而后者又应查找 libavcodec.so.58。扫描所有opencv共享对象:

& ldd -r /usr/local/lib/libopencv_*.so | grep libavcodec
libavcodec.so.58 => /usr/local/lib/libavcodec.so.58 (0x00007f0f03c11000)
libavcodec.so.58 => /usr/local/lib/libavcodec.so.58 (0x00007fb00e3fa000)
libavcodec.so.58 => /usr/local/lib/libavcodec.so.58 (0x00007f916be48000)

奖励:为什么我不能删除 libavcodec.so.57

使用 Synaptic,此文件属于 libavcodec-extra57 包。当我删除它时,Synaptic 会自动安装 libavcodec57 包。如果我删除它,则重新安装第一个。因为很多依赖需要这个库。如果有人想分享一个快速修复它的方法,我将不胜感激。

感谢您的宝贵时间。

如果您想知道,这里是 gcc --trace 的长输出。我有另一个更长的 -v -Wl,-v ,与此非常相似,但没有任何新的 libavcodec 提及。

$ g++ -Wl,--trace -L/usr/local/lib -L"/home/alejandro/Desarrollo eclipse/os1/Thirdparty" -o "os1"  ./src/Converter.o ./src/Frame.o ./src/FrameDrawer.o ./src/Initializer.o ./src/KeyFrame.o ./src/KeyFrameDatabase.o ./src/KeyFrameTriangulacion.o ./src/LocalMapping.o ./src/LoopClosing.o ./src/Map.o ./src/MapDrawer.o ./src/MapPoint.o ./src/ORBextractor.o ./src/ORBmatcher.o ./src/Optimizer.o ./src/PnPsolver.o ./src/PuntoLejano.o ./src/PuntosLejanosDB.o ./src/Sim3Solver.o ./src/System.o ./src/Tracking.o ./src/Video.o ./src/Viewer.o ./src/main.o ./src/osmap.o ./src/osmap.pb.o   -lopencv_core -lopencv_features2d -lopencv_highgui -lopencv_videoio -lopencv_imgcodecs -lopencv_imgproc -lopencv_calib3d -lpthread -lpangolin -lGL -lGLU -lDBoW2 -lg2o -lprotobuf
/usr/bin/ld: modo elf_x86_64
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crti.o
/usr/lib/gcc/x86_64-linux-gnu/7/crtbeginS.o
./src/Converter.o
./src/Frame.o
./src/FrameDrawer.o
./src/Initializer.o
./src/KeyFrame.o
./src/KeyFrameDatabase.o
./src/KeyFrameTriangulacion.o
./src/LocalMapping.o
./src/LoopClosing.o
./src/Map.o
./src/MapDrawer.o
./src/MapPoint.o
./src/ORBextractor.o
./src/ORBmatcher.o
./src/Optimizer.o
./src/PnPsolver.o
./src/PuntoLejano.o
./src/PuntosLejanosDB.o
./src/Sim3Solver.o
./src/System.o
./src/Tracking.o
./src/Video.o
./src/Viewer.o
./src/main.o
./src/osmap.o
./src/osmap.pb.o
-lopencv_core (/usr/local/lib/libopencv_core.so)
-lopencv_features2d (/usr/local/lib/libopencv_features2d.so)
-lopencv_highgui (/usr/local/lib/libopencv_highgui.so)
-lopencv_videoio (/usr/local/lib/libopencv_videoio.so)
-lopencv_imgcodecs (/usr/local/lib/libopencv_imgcodecs.so)
-lopencv_imgproc (/usr/local/lib/libopencv_imgproc.so)
-lopencv_calib3d (/usr/local/lib/libopencv_calib3d.so)
/lib/x86_64-linux-gnu/libpthread.so.0
-lpangolin (/usr/local/lib/libpangolin.so)
-lGL (/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libGL.so)
-lGLU (/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libGLU.so)
-lDBoW2 (/home/alejandro/Desarrollo eclipse/os1/Thirdparty/libDBoW2.so)
-lg2o (/home/alejandro/Desarrollo eclipse/os1/Thirdparty/libg2o.so)
-lprotobuf (/usr/local/lib/libprotobuf.so)
-lstdc++ (/usr/lib/gcc/x86_64-linux-gnu/7/libstdc++.so)
/lib/x86_64-linux-gnu/libm.so.6
/lib/x86_64-linux-gnu/libmvec.so.1
/lib/x86_64-linux-gnu/libmvec.so.1
libgcc_s.so.1 (/usr/lib/gcc/x86_64-linux-gnu/7/libgcc_s.so.1)
/lib/x86_64-linux-gnu/libc.so.6
(/usr/lib/x86_64-linux-gnu/libc_nonshared.a)elf-init.oS
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
libgcc_s.so.1 (/usr/lib/gcc/x86_64-linux-gnu/7/libgcc_s.so.1)
/usr/lib/gcc/x86_64-linux-gnu/7/crtendS.o
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crtn.o
//usr/lib/x86_64-linux-gnu/libavcodec.so.57: referencia a `swr_alloc@LIBSWRESAMPLE_2' sin definir
//usr/lib/x86_64-linux-gnu/libavcodec.so.57: referencia a `swr_free@LIBSWRESAMPLE_2' sin definir
//usr/lib/x86_64-linux-gnu/libavcodec.so.57: referencia a `swr_is_initialized@LIBSWRESAMPLE_2' sin definir
//usr/lib/x86_64-linux-gnu/libavcodec.so.57: referencia a `swr_close@LIBSWRESAMPLE_2' sin definir
//usr/lib/x86_64-linux-gnu/libavcodec.so.57: referencia a `swr_init@LIBSWRESAMPLE_2' sin definir
//usr/lib/x86_64-linux-gnu/libavcodec.so.57: referencia a `swr_convert@LIBSWRESAMPLE_2' sin definir
/usr/bin/ld: se encontraron errores de enlace, se borra el ejecutable `os1'
collect2: error: ld returned 1 exit status

【问题讨论】:

标签: c++ linux opencv gcc ld


【解决方案1】:

在@TrentP 回答之后,很明显没有简单的方法可以做到这一点,所以我按照他的建议做了,困难的方法是,我循环遍历所有共享对象以递归方式查找依赖项。我使用 ldd -r 而不是 readelf。 ldd -r 递归地列出依赖项(直接和间接)。

在一个文本文件中,我放置了 gcc 输出中出现的共享对象的完整路径列表。然后运行:

while read -r line; do echo "Library $line has these dependencies:\n $(ldd -r $line)"; done <textfile.txt

我在列出的输出中找到了 libavcodec.so.57,并检测到哪个共享对象需要它。

【讨论】:

  • ldd -r 的递归功能在工作时非常方便,但是可能会遇到一些问题。首先,在交叉编译时不能使用它,因为库需要是可以由系统的动态加载器实际加载的东西。另一个是 ldd 在查找库时使用的搜索路径与 ld 在尝试链接时使用的搜索路径不同。因此,ldd 找到的内容(右侧,与左侧寻找的内容)可能不正确,因此递归找到的内容也可能不正确。
【解决方案2】:

几乎可以肯定的是,您正在轮流加载的一个共享库需要另一个共享库。这被编码到 ELF 标头中的共享库本身中。在共享库上使用readelf -d 可以看到这一点。寻找NEEDED 行。 ld 将处理它以这种方式找到的库,但它们不会出现在 --trace 的输出中。

我不知道自动查找源代码的方法,但是在出现在您的跟踪中的库上尝试 readelf,您应该会找到需要 libavcodec 的库,或者需要一个需要 libavcodec 的库等。

当您找到 NEEDED 行时,请仔细注意其中的具体内容。是libavcodec.so,还是libavcodec.so.57?它只是一个文件名还是有一个绝对路径?这会影响链接器在搜索时会找到什么。

对于链接器搜索路径,请查看有关 ld 的 rpath-link 选项的文档。该路径中名为libavcodec.so 的第一个文件(可能是符号链接)是什么?请记住链接器搜索出现在 NEEDED 行中的内容。它不会将libavcodec.so.57 缩短为libavcodec.so 并搜索后者。

【讨论】:

    【解决方案3】:

    有两种方法可以解决这个问题:

    • 阅读手册;总是个好主意。
    • 安装依赖管理器。我使用 MacPorts,但有一些 那里有不同的。他们有一个图书馆数据库 他们管理,当您安装或构建他们的一个 库管理器还将安装或构建所有库 您正在安装的那个取决于它们是否还没有存在,以及它们是否存在 取决于等。

    【讨论】:

    • 感谢您的奉献,我认为它并不能真正回答我的问题。我想调试ld进程。
    猜你喜欢
    • 2018-11-19
    • 2020-11-19
    • 1970-01-01
    • 1970-01-01
    • 2020-03-17
    • 1970-01-01
    • 2021-12-16
    • 1970-01-01
    相关资源
    最近更新 更多