背景
近期在做一个音视频项目通过如下方式引入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 ifNO_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
),重载项目即可解决问题。