编译配置的时候,需要依赖的库不一定都在 /usr/local/include 目录下,大部分情况下需要对编译器手动指定 include 目录,同理也可能需要对链接器手动指定 lib 所在目录,而由于不同系统下安装的库所在的目录不一定一致,会导致编译配置难以跨平台执行,可以用 pkg-config 来解决这个问题。
pkg-config 是通过读取目录下的 pc 文件在确定查找结果的,这个目录通常是 libdir/pkgconfig,比如你的 libwebp 安装在 /usr/local/lib 下,那么放 pc 文件就是 /usr/local/lib/pkgconfig 下的 libavcodec.pc 文件。
文件中定义了这个依赖的名称、版本号、在当前环境的目录前缀、编译选项等等。pkg-config的输出就是来自文件
prefix=/usr/local
exec_prefix=${prefix}
libdir=/usr/local/lib
includedir=/usr/local/include
Name: libavcodec
Description: FFmpeg codec library
Version: 58.91.100
Requires: libswresample >= 3.7.100, libavutil >= 56.51.100
Requires.private:
Conflicts:
Libs: -L${libdir} -lavcodec -pthread -lm -llzma -lz -lva
Libs.private:
Cflags: -I${includedir}
外部依赖之间可能也会有依赖关系,库的依赖也是会在 pc 文件中定义的,比如harfbuzz 的 pc 文件:
prefix=/usr/local/Cellar/harfbuzz/2.8.0_1
libdir=${prefix}/lib
includedir=${prefix}/include
Name: harfbuzz
Description: HarfBuzz text shaping library
Version: 2.8.0
Requires.private: freetype2, graphite2, glib-2.0
Libs: -L${libdir} -lharfbuzz
Libs.private: -lm -framework ApplicationServices
Cflags: -I${includedir}/harfbuzz
可以发现这个库同时依赖了 freetype2、graphite2、glib-2.0 这三个库,只要在 pc 文件中有通过 Requires 或者 Requires.private 声明过依赖,在 cflags 或者 libs 的输出结果中也会带有依赖的编译选项:
-I/usr/local/Cellar/harfbuzz/2.8.0_1/include/harfbuzz -I/usr/local/opt/freetype/include/freetype2 -I/usr/local/Cellar/graphite2/1.3.14/include -I/usr/local/Cellar/glib/2.68.1/include/glib-2.0 -I/usr/local/Cellar/glib/2.68.1/lib/glib-2.0/include -I/usr/local/opt/gettext/include -I/usr/local/Cellar/pcre/8.44/include
通常一个 lib 对应一个 pc 文件,有些项目有多个 lib,那么它也会分别定义多个 pc 文(如:ffmpeg)
使用 pkg-config 过程中遇到库找不到的情况,不一定是外部库没有安装,默认情况下 pkg-config 的查找路径为 /usr/lib/pkgconfig 和 /usr/share/pkgconfig,可以通过环境变量 PKG_CONFIG_PATH 在额外指定 pkg-config 的查找路径
export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:${PKG_CONFIG_PATH}"
export PKG_CONFIG_PATH="/usr/local/opt/jpeg-turbo/lib/pkgconfig:${PKG_CONFIG_PATH}"
$ pkg-config libavcodec --cflags
// 输出:
-I/usr/local/include
$ pkg-config libavcodec --libs
// 输出
-L/usr/local/lib -lavcodec -pthread -lm -llzma -lz -lva -lswresample -lm -lavutil -pthread -lva-drm -lva -lm -lva
$ pkg-config libavcodec --version
// 输出
0.29.1
$ gcc -o test test.c `pkg-config --libs --cflags libavcodec`
find_package(PkgConfig REQUIRED)
if (PKG_CONFIG_FOUND)
pkg_check_modules(my_deps REQUIRED IMPORTED_TARGET libpng libwebp)
endif()
首先利用 CMake 的 find_package 机制找到本地的 pkg-config,如果成功找到,则有两种办法查找外部库:
大部分情况下使用 pkg_check_modules,第一个参数为匹配前缀,需要依赖多个外部库时,通过这个前缀,可以一次性的消费结果。也可以指定 REQUIRED 来表示依赖对这次构建是必须的,否则直接失败终止构建。接下来就是应用 pkg-config 的结果了,在 CMake 上下文中可以使用 PkgConfig : : ${prefix} 来消费结果,直接作为 target_link_libraries 的参数即可:
target_link_libraries(${PROJECT_NAME} PkgConfig::my_deps)