pkg-config 了解

开源库的编译链接参数管理神器

pkg-config是Linux/Unix 系统下用于管理开源库编译和链接参数的命令行工具,核心作用是自动化解析库的元数据(安装路径、依赖关系、编译 / 链接参数),避免开发者手动输入冗长的-I(头文件路径)、-L(库路径)、-l(库名)参数,同时解决库的依赖链传递问题。


pkg-config原理

  1. 查找 .pc 配置文件

而.pc配置文件路径一般位于:

  1. 环境变量PKG_CONFIG_PATH
    用户自定义路径(如手动安装的库放在/usr/local/lib/pkgconfig)
  2. 系统架构相关路径
    如/usr/lib/x86_64-linux-gnu/pkgconfig(Debian/Ubuntu 系)
  3. 系统全局路径
    如/usr/lib/pkgconfig、/usr/share/pkgconfig

可通过pkg-config –variable pc_path pkg-config查看当前的搜索路径

  1. 递归解析 .pc 配置文件

  2. 输出最终的编译/链接参数

pc文件语法规范

  • 变量定义:VAR=value(如prefix=/usr)
  • 变量引用:${VAR}(如includedir=${prefix}/include)
  • 注释:以#开头(无多行注释,需每行加#)
  • 多行内容:行尾加\(如依赖项过长时换行)
  • 依赖版本:库名 >= 版本号(支持>=/<=/=)

举例解释

以gtk+-3.0.pc内容为例,文件路径:/usr/lib/x86_64-linux-gnu/pkgconfig/gtk+-3.0.pc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
prefix=/usr
exec_prefix=${prefix}
libdir=/usr/lib/x86_64-linux-gnu
includedir=${prefix}/include
targets=x11 broadway wayland

gtk_binary_version=3.0.0
gtk_host=x86_64-pc-linux-gnu

Name: GTK+
Description: GTK+ Graphical UI Library
Version: 3.24.33
Requires: gdk-3.0 atk >= 2.32.0 cairo >= 1.14.0 cairo-gobject >= 1.14.0 gdk-pixbuf-2.0 >= 2.30.0 gio-2.0 >= 2.57.2
Requires.private: atk atk-bridge-2.0 wayland-client >= 1.14.91 xkbcommon >= 0.2.0 wayland-cursor >= 1.14.91 wayland-egl epoxy >= 1.4 fribidi >= 0.19.7 pangoft2 gio-unix-2.0 >= 2.57.2
Libs: -L${libdir} -lgtk-3
Cflags: -I${includedir}/gtk-3.0

基础路径

1
2
3
4
5
prefix=/usr
exec_prefix=${prefix}
libdir=/usr/lib/x86_64-linux-gnu
includedir=${prefix}/include
targets=x11 broadway wayland

上述内容描述了gtk安装的一些信息:

  • prefix: 根安装目录前缀为/usr
  • exec_prefix: 可执行文件前缀。通常继承prefix,仅当库的可执行文件和库文件分离时才单独设置(如/usr/local/bin和/usr/local/lib)
  • libdir:库文件路径为/usr/lib/x86_64-linux-gnu
  • includedir: 头文件根路径,后续会通过Cflags追加具体的子目录
  • targets: 支持的窗口系统目标

版本与平台信息

1
2
3
4
5
gtk_binary_version=3.0.0
gtk_host=x86_64-pc-linux-gnu
Name: GTK+
Description: GTK+ Graphical UI Library
Version: 3.24.33
  • gtk_binary_version: GTK + 二进制兼容版本
    即SOVERSION(共享库版本),是 Linux 共享库的核心机制:系统中实际的库文件是libgtk-3.so.0(或libgtk-3.so.3.24.33)3.0.0表示:主版本 3,次版本 0,修订版 0—— 只要主版本不变,共享库就保持二进制兼容(程序编译时链接libgtk-3.so,运行时可加载任何兼容的版本)
  • gtk_host: 构建主机的三元组
    格式为架构-厂商-系统,是 autotools(autoconf/automake) 的标准标识:
    x86_64:CPU 架构
    pc:厂商(pc 表示通用个人计算机)
    linux-gnu:系统(Linux+GNU 工具链)
    用于交叉编译时识别目标平台(如编译 ARM 架构的 GTK + 程序时,该值会变为arm-linux-gnueabihf)
  • Name: pkg-config 查询名
    必须唯一,是pkg-config的核心查询标识(如pkg-config –cflags gtk+-3.0中的gtk+-3.0)
  • Version: 库的发布版本

依赖项配置

公共依赖(Requires):程序必须依赖的库

1
Requires: gdk-3.0 atk >= 2.32.0 cairo >= 1.14.0 cairo-gobject >= 1.14.0 gdk-pixbuf-2.0 >= 2.30.0 gio-2.0 >= 2.57.2

定义:使用 GTK + 的程序在编译和运行时都依赖的库,这些库的符号会被 GTK + 暴露给上层程序,因此程序必须链接这些库
私有依赖(Requires.private):GTK + 内部依赖的库

1
Requires.private: atk atk-bridge-2.0 wayland-client >= 1.14.91 xkbcommon >= 0.2.0 wayland-cursor >= 1.14.91 wayland-egl epoxy >= 1.4 fribidi >= 0.19.7 pangoft2 gio-unix-2.0 >= 2.57.2

定义:GTK + 库自身内部使用的库,这些库的符号不会暴露给上层程序,因此程序不需要直接链接(但静态链接时需要)
核心设计逻辑:
动态链接时:程序只需要链接libgtk-3.so,libgtk-3.so已经内部链接了这些私有依赖库,因此程序无需关心。
静态链接时:需要将这些私有依赖库一起链接(pkg-config 的–static参数会自动处理)。

编译与链接参数

1
2
Libs: -L${libdir} -lgtk-3 
Cflags: -I${includedir}/gtk-3.0

这部分是直接的编译 / 链接参数,但实际使用时 pkg-config 会递归合并所有依赖库的参数
(1) Libs(链接参数)
• 字面含义:-L/usr/lib/x86_64-linux-gnu(指定库路径) + -lgtk-3(链接 libgtk-3.so)。
• 实际输出:执行pkg-config –libs gtk+-3.0时,会递归解析Requires中的所有库(如 gdk-3.0)的 Libs 参数,最终输出的参数包含所有依赖库的链接路径和库名,例如:

1
-L/usr/lib/x86_64-linux-gnu -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -lharfbuzz -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0

(2) Cflags(编译参数)
• 字面含义:-I/usr/include/gtk-3.0(指定 GTK + 头文件路径)。
• 实际输出:执行pkg-config –cflags gtk+-3.0时,会递归解析Requires中的所有库的 Cflags 参数,最终输出的参数包含所有依赖库的头文件路径,例如:

1
-I/usr/include/gtk-3.0 -I/usr/include/at-spi2-atk/2.0 -I/usr/include/at-spi-2.0 -I/usr/include/dbus-1.0

常用命令与示例

以下均以gtk+-3.0为例(对应你提供的.pc文件):

(1) 基础:获取编译 + 链接参数(最常用)

1
2
# 同时输出编译参数和链接参数
pkg-config --cflags --libs gtk+-3.0

(2) 单独获取编译参数(Cflags)

1
2
pkg-config --cflags gtk+-3.0
# 输出:头文件路径(包括所有依赖库的头文件)

(3) 单独获取链接参数(Libs)

1
2
pkg-config --libs gtk+-3.0
# 输出:库路径、库名(包括所有依赖库的链接参数)

(4) 查看库的版本

1
2
3
4
5
6
# 查看当前安装的库版本
pkg-config --modversion gtk+-3.0
# 输出:3.24.33(对应你.pc文件中的Version字段)

# 查看pkg-config自身版本
pkg-config --version

(5) 版本校验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 检查库是否存在(返回0表示存在,非0表示不存在)
pkg-config --exists gtk+-3.0
echo $? # 输出0

# 检查库版本是否≥3.20(返回0表示满足)
pkg-config --atleast-version=3.20 gtk+-3.0
echo $? # 输出0

# 检查库版本是否≤3.25(返回0表示满足)
pkg-config --max-version=3.25 gtk+-3.0
echo $? # 输出0

# 检查库版本是否等于3.24.33(返回0表示满足)
pkg-config --exact-version=3.24.33 gtk+-3.0
echo $? # 输出0

(6) 查看库的元数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查看库的描述信息
pkg-config --describe-package gtk+-3.0
# 输出:GTK+ Graphical UI Library (3.24.33)

# 查看库的所有依赖(公共依赖)
pkg-config --print-requires gtk+-3.0
# 输出:gdk-3.0 atk cairo cairo-gobject gdk-pixbuf-2.0 gio-2.0

# 查看库的私有依赖
pkg-config --print-requires-private gtk+-3.0
# 输出:atk atk-bridge-2.0 wayland-client ...

# 递归查看所有依赖(包括依赖的依赖)
pkg-config --print-requires --recursive gtk+-3.0

(7) 态链接参数(–static)

当需要静态链接库时,需添加--static参数,pkg-config会自动包含私有依赖(Requires.private)的链接参数:

1
pkg-config --cflags --libs --static gtk+-3.0

高级用法

1. 自定义.pc文件路径

如果手动安装的库放在/opt/gtk,其.pc文件在/opt/gtk/lib/pkgconfig,可通过PKG_CONFIG_PATH指定路径:

1
2
3
4
5
6
# 临时生效(当前终端)
export PKG_CONFIG_PATH=/opt/gtk/lib/pkgconfig:$PKG_CONFIG_PATH

# 永久生效(添加到~/.bashrc或/etc/profile)
echo 'export PKG_CONFIG_PATH=/opt/gtk/lib/pkgconfig:$PKG_CONFIG_PATH' >> ~/.bashrc
source ~/.bashrc

2. 交叉编译时的使用

交叉编译(如 x86_64 编译 ARM 架构程序)时,需指定交叉编译的.pc文件路径:

1
2
3
4
5
6
# 假设ARM库的.pc文件在/opt/arm-linux-gnueabihf/lib/pkgconfig
export PKG_CONFIG_PATH=/opt/arm-linux-gnueabihf/lib/pkgconfig
export PKG_CONFIG_LIBDIR=/opt/arm-linux-gnueabihf/lib/pkgconfig # 覆盖系统默认路径(可选)

# 此时pkg-config会解析ARM架构的库参数
pkg-config --cflags --libs gtk+-3.0

3. 与建工具集成

(1) Makefile 中使用

1
2
3
4
5
6
7
# 定义变量
CFLAGS := $(pkg-config --cflags gtk+-3.0)
LDFLAGS := $(pkg-config --libs gtk+-3.0)

# 编译规则
my_gtk_app: main.c
gcc main.c -o my_gtk_app $(CFLAGS) $(LDFLAGS)

(2) CMake 中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 查找pkg-config
find_package(PkgConfig REQUIRED)

# 查找gtk+-3.0库
pkg_check_modules(GTK3 REQUIRED gtk+-3.0)

# 包含头文件路径
include_directories(${GTK3_INCLUDE_DIRS})

# 链接库
link_directories(${GTK3_LIBRARY_DIRS})
add_executable(my_gtk_app main.c)
target_link_libraries(my_gtk_app ${GTK3_LIBRARIES})

# 添加编译宏
add_definitions(${GTK3_CFLAGS_OTHER})