You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

构建调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 20:01:33