CMake项目链接OpenCV失败:libopencv_highgui.so引用FFmpeg符号未解析
问题描述
项目链接OpenCV库时出现未解析符号错误,系统中OpenCV依赖libavcodec-*系列库,已通过target_link_libraries添加这些库的完整路径,且确认库包含所需符号,但仍报错:
/usr/lib/aarch64-linux-gnu/libopencv_highgui.so.2.4.9: undefined reference to `av_malloc@LIBAVUTIL_FFMPEG_54' /usr/lib/aarch64-linux-gnu/libopencv_highgui.so.2.4.9: undefined reference to `av_register_all@LIBAVFORMAT_FFMPEG_56' /usr/lib/aarch64-linux-gnu/libopencv_highgui.so.2.4.9: undefined reference to `avcodec_close@LIBAVCODEC_FFMPEG_56'
通过cmake --build . --verbose查看的链接命令如下:
/usr/bin/c++ \ CMakeFiles/myproject.dir/imgproc.cc.o \ -o \ myproject \ \ /usr/lib/aarch64-linux-gnu/libQt5Widgets.so.5.6.1 \ /usr/lib/aarch64-linux-gnu/libopencv_features2d.so.2.4.9 \ /usr/lib/aarch64-linux-gnu/libopencv_photo.so.2.4.9 \ _deps/oatpp-build/src/liboatpp.a \ /usr/lib/aarch64-linux-gnu/libavcodec-ffmpeg.so \ /usr/lib/aarch64-linux-gnu/libavformat-ffmpeg.so \ /usr/lib/aarch64-linux-gnu/libavutil-ffmpeg.so \ /usr/lib/aarch64-linux-gnu/libswscale-ffmpeg.so \ /usr/lib/aarch64-linux-gnu/libQt5Gui.so.5.6.1 \ /usr/lib/aarch64-linux-gnu/libQt5Core.so.5.6.1 \ /usr/lib/aarch64-linux-gnu/libopencv_flann.so.2.4.9 \ /usr/lib/aarch64-linux-gnu/libopencv_highgui.so.2.4.9 \ /usr/lib/aarch64-linux-gnu/libopencv_imgproc.so.2.4.9 \ /usr/lib/aarch64-linux-gnu/libopencv_core.so.2.4.9 \ -lpthread \ -latomic
更新:已检查库文件信息:
file /usr/lib/aarch64-linux-gnu/libavcodec-ffmpeg.so.56.60.100 /usr/lib/aarch64-linux-gnu/libavcodec-ffmpeg.so.56.60.100: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, BuildID[sha1]=e534adc24d3ba924851e5a11dc9eee87d5008d36, stripped file /usr/lib/aarch64-linux-gnu/libopencv_highgui.so.2.4.9 /usr/lib/aarch64-linux-gnu/libopencv_highgui.so.2.4.9: ELF 64-bit LSB shared object, ARM aarch64, version 1 (GNU/Linux), dynamically linked, BuildID[sha1]=2a6d6bf1318da7a8593b96359b3c8a66008744ee, stripped
咨询问题
version 1 (SYSV)与version 1 (GNU/Linux)是否与链接失败有关?- 如何在CMake构建中保持库的链接顺序?OpenCV库通过
find_package获取,而avcodec-ffmpeg无CMake配置文件,当前用find_library获取,如何在CMake中控制LINK_LIBS的链接顺序?
解答
问题1:ELF版本标识与链接失败的关系
version 1 (SYSV)和version 1 (GNU/Linux)仅为ELF文件的版本标识差异,不会导致链接失败。SYSV是标准ELF格式的版本标记,GNU/Linux是GNU对ELF的扩展标记,两者在aarch64架构下兼容性无问题,链接器可正常处理这两种标识的库文件。当前未解析符号问题的核心原因是链接顺序错误,而非ELF版本标识差异。
问题2:CMake中控制链接顺序的方法
链接器处理库的顺序为从左到右,依赖库必须放在被依赖库的后面。从现有链接命令可见,libavcodec-ffmpeg.so等FFmpeg库位于libopencv_highgui.so之前,而libopencv_highgui.so依赖FFmpeg库,导致链接器处理libopencv_highgui.so时无法找到FFmpeg的符号。
具体解决方法:
直接调整
target_link_libraries的顺序
确保FFmpeg库在OpenCV库之后链接。假设通过以下方式获取库:find_package(OpenCV REQUIRED) find_library(AVCODEC_LIB avcodec-ffmpeg PATHS /usr/lib/aarch64-linux-gnu) find_library(AVFORMAT_LIB avformat-ffmpeg PATHS /usr/lib/aarch64-linux-gnu) find_library(AVUTIL_LIB avutil-ffmpeg PATHS /usr/lib/aarch64-linux-gnu) find_library(SWSCALE_LIB swscale-ffmpeg PATHS /usr/lib/aarch64-linux-gnu) set(FFMPEG_LIBS ${AVCODEC_LIB} ${AVFORMAT_LIB} ${AVUTIL_LIB} ${SWSCALE_LIB})则
target_link_libraries需按如下顺序编写:target_link_libraries(myproject PRIVATE Qt5::Widgets ${OpenCV_LIBS} ${FFMPEG_LIBS} oatpp Qt5::Gui Qt5::Core pthread atomic )修改后生成的链接命令中,FFmpeg库会出现在OpenCV库之后,链接器即可正确找到
libopencv_highgui.so依赖的符号。用INTERFACE库封装FFmpeg依赖(可选)
若需更清晰的依赖管理,可创建INTERFACE库封装FFmpeg依赖,再让OpenCV依赖该库:add_library(ffmpeg INTERFACE) target_link_libraries(ffmpeg INTERFACE ${FFMPEG_LIBS}) target_link_libraries(myproject PRIVATE Qt5::Widgets ${OpenCV_LIBS} ffmpeg oatpp Qt5::Gui Qt5::Core pthread atomic)CMake会自动处理依赖顺序,核心仍是保证被依赖的FFmpeg库在OpenCV之后链接。
验证链接顺序
修改后重新执行cmake --build . --verbose,检查链接命令中libavcodec-ffmpeg.so等库是否位于libopencv_highgui.so之后,确保顺序正确。
内容的提问来源于stack exchange,提问作者Michaelzh

