构建调用FFmpeg的C++程序时出现链接错误,求调试方案
问题描述
C++代码实现
#include <iostream> extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> } namespace hrean::ffmpeg { namespace detail { }//namespace detail void testFFmpeg() { AVFormatContext *avFormatContext = avformat_alloc_context(); //I can comment out the rest of the function, the error is the same } //testFFmpeg() } //namespace hrean::ffmpeg int main(int argc, char **argv) { try { hrean::ffmpeg::testFFmpeg(); } catch(const std::runtime_error& e) { std::cerr << "Error! " << e.what() << '\n'; return -1; } catch(...) { std::cerr << "Unknown error\n"; return -1; } return 0; }
CMake配置
主项目CMakeLists.txt
cmake_minimum_required(VERSION 3.13) project(hrean) add_subdirectory(lib/ffmpeg-module) message("[temp] FFMPEG_INCLUDE_DIRS = ${FFMPEG_INCLUDE_DIRS}") message("[temp] FFMPEG_LIBRARIES = ${FFMPEG_LIBRARIES}") add_executable(hrean-app src/main.cpp) target_include_directories(hrean-app PUBLIC ${FFMPEG_INCLUDE_DIRS}) target_link_libraries(hrean-app PUBLIC ${FFMPEG_LIBRARIES})
lib/ffmpeg-module/CMakeLists.txt
find_package(FFmpeg REQUIRED MODULE)
CMake检测输出
-- The C compiler identification is GNU 11.3.0 -- The CXX compiler identification is GNU 11.3.0 -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working C compiler: /usr/bin/cc - skipped -- Detecting C compile features -- Detecting C compile features - done -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: /usr/bin/c++ - skipped -- Detecting CXX compile features -- Detecting CXX compile features - done -- Found PkgConfig: /usr/bin/pkg-config (found version "0.29.2") -- Checking for module 'libavcodec' -- Found libavcodec, version 60.2.100 -- Checking for module 'libavformat' -- Found libavformat, version 60.2.100 -- Checking for module 'libavdevice' -- Found libavdevice, version 60.0.100 -- Checking for module 'libavutil' -- Found libavutil, version 58.1.100 -- Checking for module 'libavfilter' -- Found libavfilter, version 9.1.100 -- Checking for module 'libswscale' -- Found libswscale, version 7.0.100 -- Checking for module 'libpostproc' -- Found libpostproc, version 57.0.100 -- Checking for module 'libswresample' -- Found libswresample, version 4.9.100 -- Found FFmpeg: /home/serban/ffmpeg_build/lib/libavcodec.a;/home/serban/ffmpeg_build/lib/libavformat.a;/home/serban/ffmpeg_build/lib/libavutil.a [temp] FFMPEG_INCLUDE_DIRS = /home/serban/ffmpeg_build/include [temp] FFMPEG_LIBRARIES = /home/serban/ffmpeg_build/lib/libavcodec.a;/home/serban/ffmpeg_build/lib/libavformat.a;/home/serban/ffmpeg_build/lib/libavutil.a -- Configuring done -- Generating done -- Build files have been written to: /home/serban/Work/hrean/build
链接错误信息
初始链接错误(未调整顺序)
[ 50%] Building CXX object CMakeFiles/hrean-app.dir/src/main.cpp.o [100%] Linking CXX executable hrean-app /usr/bin/ld: /home/serban/ffmpeg_build/lib/libavformat.a(amvenc.o): in function `amv_write_packet': /home/serban/ffmpeg/libavformat/amvenc.c:356: undefined reference to `av_packet_unref' /usr/bin/ld: /home/serban/ffmpeg/libavformat/amvenc.c:357: undefined reference to `av_packet_ref' /usr/bin/ld: /home/serban/ffmpeg_build/lib/libavformat.a(amvenc.o): in function `amv_deinit': /home/serban/ffmpeg/libavformat/amvenc.c:209: undefined reference to `av_packet_free' /usr/bin/ld: /home/serban/ffmpeg_build/lib/libavformat.a(amvenc.o): in function `amv_init': /home/serban/ffmpeg/libavformat/amvenc.c:111: undefined reference to `avcodec_get_name' /usr/bin/ld: /home/serban/ffmpeg/libavformat/amvenc.c:117: undefined reference to `avcodec_get_name' /usr/bin/ld: /home/serban/ffmpeg/libavformat/amvenc.c:188: undefined reference to `av_new_packet' /usr/bin/ld: /home/serban/ffmpeg/libavformat/amvenc.c:196: undefined reference to `av_packet_alloc' /usr/bin/ld: /home/serban/ffmpeg_build/lib/libavformat.a(asfdec_o.o): in function `asf_read_close': /home/serban/ffmpeg/libavformat/asfdec_o.c:1413: undefined reference to `av_packet_free' /usr/bin/ld: /home/serban/ffmpeg_build/lib/libavformat.a(asfdec_o.o): in function `asf_read_single_payload': /home/serban/ffmpeg/libavformat/asfdec_o.c:1119: undefined reference to `av_new_packet' /usr/bin/ld: /home/serban/ffmpeg_build/lib/libavformat.a(asfdec_o.o): in function `asf_read_packet': /home/serban/ffmpeg/libavformat/asfdec_o.c:1388: undefined reference to `av_packet_move_ref' /usr/bin/ld: /home/serban/ffmpeg_build/lib/libavformat.a(asfdec_o.o): in function `reset_packet': /home/serban/ffmpeg/libavformat/asfdec_o.c:1030: undefined reference to `av_packet_unref' /usr/bin/ld: /home/serban/ffmpeg_build/lib/libavformat.a(asfdec_o.o): in function `asf_deinterleave': /home/serban/ffmpeg/libavformat/asfdec_o.c:1313: undefined reference to `av_packet_unref' /usr/bin/ld: /home/serban/ffmpeg/libavformat/asfdec_o.c:1314: undefined reference to `av_packet_from_data' /usr/bin/ld: /home/serban/ffmpeg_build/lib/libavformat.a(asfdec_o.o): in function `asf_read_replicated_data': /home/serban/ffmpeg/libavformat/asfdec_o.c:1043: undefined reference to `av_new_packet' /usr/bin/ld: /home/serban/ffmpeg_build/lib/libavformat.a(asfdec_o.o): in function `asf_read_timestamp': /home/serban/ffmpeg/libavformat/asfdec_o.c:1463: undefined reference to `av_packet_alloc' /usr/bin/ld: /home/serban/ffmpeg_build/lib/libavformat.a(asfdec_o.o): in function `reset_packet': /home/serban/ffmpeg/libavformat/asfdec_o.c:1030: undefined reference to `av_packet_unref' /usr/bin/ld: /home/serban/ffmpeg_build/lib/libavformat.a(asfdec_o.o): in function `asf_read_timestamp': /home/serban/ffmpeg/libavformat/asfdec_o.c:1512: undefined reference to `av_packet_unref'
调整链接顺序后的错误(zlib未定义)
[100%] Linking CXX executable hrean-app /usr/bin/ld: /home/serban/ffmpeg_build/lib/libavformat.a(mov.o): in function `mov_read_cmov': /home/serban/ffmpeg/libavformat/mov.c:5578: undefined reference to `uncompress' /usr/bin/ld: /home/serban/ffmpeg_build/lib/libavformat.a(swfdec.o): in function `swf_read_packet': /home/serban/ffmpeg/libavformat/swfdec.c:393: undefined reference to `uncompress' /usr/bin/ld: /home/serban/ffmpeg_build/lib/libavformat.a(swfdec.o): in function `swf_read_header': /home/serban/ffmpeg/libavformat/swfdec.c:161: undefined reference to `inflateInit_' /usr/bin/ld: /home/serban/ffmpeg_build/lib/libavformat.a(swfdec.o): in function `zlib_refill': /home/serban/ffmpeg/libavformat/swfdec.c:134: undefined reference to `inflate' /usr/bin/ld: /home/serban/ffmpeg_build/lib/libavformat.a(swfdec.o): in function `swf_read_close': /home/serban/ffmpeg/libavformat/swfdec.c:557: undefined reference to `inflateEnd'
解决方案
1. 链接FFmpeg的完整依赖库
你使用的是静态编译的FFmpeg库,这类库不会自动链接其依赖的系统库(比如zlib、lzma、bz2等),需要手动添加这些依赖:
- 首先添加zlib的链接,修改主CMakeLists.txt,加入
find_package(ZLIB REQUIRED),然后将ZLIB_LIBRARIES加入链接列表。 - 如果后续还有其他未定义引用(比如lzma相关),需要继续添加对应的库(比如
find_package(LZMA REQUIRED)并链接LZMA_LIBRARIES)。
2. 调整链接顺序(GCC链接器要求)
GCC链接器的规则是:被依赖的库要放在依赖它的库之后。正确的FFmpeg库链接顺序应该是从高层到底层:avformat → avcodec → avutil → 系统依赖库(zlib等)
修改后的CMakeLists.txt示例:
cmake_minimum_required(VERSION 3.13) project(hrean) add_subdirectory(lib/ffmpeg-module) find_package(ZLIB REQUIRED) # 定义正确的链接顺序 set(FFMPEG_LINK_ORDER ${AVFORMAT_LIBRARIES} ${AVCODEC_LIBRARIES} ${AVUTIL_LIBRARIES} ${ZLIB_LIBRARIES} ) add_executable(hrean-app src/main.cpp) target_include_directories(hrean-app PUBLIC ${FFMPEG_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS}) target_link_libraries(hrean-app PUBLIC ${FFMPEG_LINK_ORDER})
3. 用pkg-config自动获取完整链接参数
如果FindFFmpeg模块没有正确导出所有依赖,可以直接使用pkg-config来获取FFmpeg的编译和链接参数,这会自动包含所有依赖库:
修改lib/ffmpeg-module/CMakeLists.txt:
find_package(PkgConfig REQUIRED) pkg_check_modules(FFMPEG REQUIRED IMPORTED_TARGET libavformat libavcodec libavutil )
然后主CMakeLists.txt中链接PkgConfig的目标:
add_executable(hrean-app src/main.cpp) target_link_libraries(hrean-app PUBLIC PkgConfig::FFMPEG)
这种方式会自动处理所有依赖库和链接顺序,避免手动维护的麻烦。
调试方法
- 增加CMake的链接日志:在主CMakeLists.txt中加入
set(CMAKE_VERBOSE_MAKEFILE ON),这样make时会输出完整的链接命令,你可以检查是否遗漏了某些库。 - 查看FFmpeg编译时的配置:进入你的
ffmpeg_build目录,运行pkg-config --libs libavformat命令,输出的内容就是完整的链接参数,对比CMake使用的参数是否一致。 - 检查静态库的依赖:使用
nm -D /home/serban/ffmpeg_build/lib/libavformat.a | grep undefined命令,查看该库中未定义的符号,对应查找需要链接的依赖库。
内容的提问来源于stack exchange,提问作者Serban Stoenescu
相关产品推荐
相关产品推荐

