背景

近期在做一个音视频项目通过如下方式引入FFmpeg:

set(FFMPEG_LIBS avformat avcodec avutil swresample swscale)
find_library(FFmpeg_FOUND NAMES ${FFMPEG_LIBS} HINTS "${FFMPEG_PREFIX_PATH}/lib/" REQUIRED)
...
target_link_libraries(${PROJECT_NAME} PRIVATE ${FFmpeg})

然而在链接阶段,链接器提示找不到符号。

原因

根据 cmake 的文档

This command is used to find a library. A cache entry, or a normal variable if NO_CACHE is specified, named by <VAR> is created to store the result of this command.
https://cmake.org/cmake/help/latest/command/find_library.html

意味着find_library一次只能找到一个库,而NAMES是用来指定同一个库可能的名称:

Specify one or more possible names for the library.

因此文章开始的代码只会链接 avformat

解决

一种显然的解决方案是使用foreach循环${FFMPEG_LIBS}依此链接:

set(FFmpeg)
foreach(LIB IN LISTS FFMPEG_LIBS)
    find_library(FFmpeg_FOUND NAMES ${LIB} HINTS "${FFMPEG_PREFIX_PATH}/lib/" REQUIRED)
    list(APPEND FFmpeg "${FFmpeg_FOUND}")
endforeach()
...
target_link_libraries(${PROJECT_NAME} PRIVATE ${FFmpeg})

然而,这种做法并不可行,结果同文章开始的代码结果一致。在不指定NO_CACHE的情况下,cmake并不会每次都去搜索相应的库,而是在第一次搜索之后,后续的find_library直接给变量赋值。为了性能,我们最好不要指定NO_CACHE。一种解决方案是使用不同的变量名:

set(FFmpeg)
foreach(LIB IN LISTS FFMPEG_LIBS)
    find_library(FFmpeg_FOUND_${LIB} NAMES ${LIB} HINTS "${FFMPEG_PREFIX_PATH}/lib/" REQUIRED)
    list(APPEND FFmpeg "${FFmpeg_FOUND_${LIB}}")
endforeach()
...
target_link_libraries(${PROJECT_NAME} PRIVATE ${FFmpeg})

删除cmake的缓存(如果使用clion通常是cmake-build-debug),重载项目即可解决问题。

最后修改:2022 年 04 月 18 日
如果觉得我的文章对你有用,请随意赞赏