本文是转载自简书pkg-config用法详解,并根据自己的环境修改。

背景

当开发过程中使用第三方库时,我们需要知道被使用的第三方库,它包含的头文件在哪儿、它依赖哪些库、它的编译选项有哪些、它的链接选项有哪些等等,也就是说需要知道这些信息我们才能正确的编译和链接它。当然可以通过直接在编译选项中指定的方式来使用,但是,对于一些大型或者比较复杂的第三方库,包含的头文件或者依赖库非常多、非常复杂的时候,这样做的成本就非常高,而且非常不便于在不同平台之间的移植。

pkg-config 就是解决这个问题的一种方案。

pkg-config 是什么

pkg-config 是一个用于获取系统中安装的包/库的相关信息(例如依赖头文件目录、依赖库文件目录)的程序,通常用于编译和链接一个或多个库,典型的用法为:

1
2
3
4
5
# Makefile

program: program.c
cc program.c `pkg-config --cflags --libs XXX` # 此处的XXX表示库名称,(数字1左边的符号)

注意符号 `,不是引号,而是重音符

pkg-config 通过读取一个名为 <PackageName>.pc 的文件来获取 <PackageName> 包的信息,一般会从 /usr/lib/pkgconfig, /usr/share/pkgconfig, /usr/local/lib/pkgconfig, /usr/local/share/pkgconfig 来查找 .pc 文件,除此之外,也可通过设置 PKG_CONFIG_PATH 环境变量指定查找路径。

编写一个自己的库

Linux 或 macOS 系统可以通过 man pkg-config 来查看pkg-config 的用法,选项有很多,此处不一一介绍,最常用到的两个选项是 pkg-config --cflags <PackageName>pkg-config --libs <PackageName>,其含义分别为:

  • --cflags:获取编译 <PackageName> 包的所需要的预处理或者编译选项,例如 -I/usr/include,指定编译 <PackageName> 包的头文件搜索路径。
  • --libs:获取编译 <PackageName> 包所需要的链接选项,例如 -L/usr/lib 指定库文件搜索路径,或 -lXXX 指定具体的库文件。

下面以一个例子来说明 pkg-config 的用法,例子将会用到我们自己编写的 mymath 库。程序很简单,就是调用一个 mymath 库提供的函数:

1
2
3
4
5
6
7
// test.cpp
#include "mymath.h"

int main(int argc, char** argv) {
mymath::add(1, 2);
return 0;
}

对于 mymath 库,我们给出它的结构和代码如下:

1
2
3
4
5
6
7
8
9
├── CMakeLists.txt
├── build
├── include
│   └── mymath.h
├── lib
│   └── libmymath.a
├── mymath.pc
└── src
└── mymath.cpp
1
2
3
4
5
6
7
// mymath.h

#pragma once

namespace mymath{
int add(int a, int b);
}
1
2
3
4
5
6
7
8
9
10
// mymath.cpp
#include "mymath.h"
#include <iostream>

namespace mymath{
int add(int a, int b){
std::cout << "Add " << a << " and " << b << " is " << a+b << std::endl;
return a+b;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
// CMakeLists.txt
cmake_minimum_required(VERSION 3.22)
project(mymath)

set(CMAKE_CXX_STANDARD 14)

add_library(mymath STATIC src/mymath.cpp)

target_include_directories(mymath
PUBLIC
${PROJECT_SOURCE_DIR}/include
)

mymath 库的源码可以 点击链接下载

有了 mymath.hmymath.cppCMakeLists.txt 这三个文件后,我们在 build 目录下执行 cmake ..,然后再执行 make,将会生成 libmymath.a 的静态库。把该静态库复制到 lib 目录下即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
~/Code/cmake/mymath/build ❯ 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
-- Configuring done
-- Generating done
-- Build files have been written to: /home/lushuangning/Code/cmake/mymath/build
~/Code/cmake/mymath/build ❯ make
[ 50%] Building CXX object CMakeFiles/mymath.dir/src/mymath.cpp.o
[100%] Linking CXX static library libmymath.a
[100%] Built target mymath

这个时候,直接使用 g++ -o test test.cpp 是无法编译通过的,因为我们不知道关于 mymath 库的任何信息(例如 头文件mymath.h 在哪个目录下,mymath 库在哪个目录下等等),此时就是 pkg-config 发挥作用的时候了。

如何让 pkg-config 找到所需的第三方库?

从前面的介绍可以知道,pkg-config 会在常用的系统路径下查找 .pc 文件,除此之外,还会查找 PKG_CONFIG_PATH 环境变量指定的路径。那么如何让 pkg-config 找到并使用 OpenCV 呢?需要两个步骤:

  • 编写库相关的 .pc 文件;
  • .pc 文件放在 pkg-config 的查找路径之下;

第二点好办,将 .pc 文件放在几个指定的路径或者环境变量 PKG_CONFIG_PATH 指定的路径即可,那么 .pc 文件怎么编写呢?

.pc 文件的格式

.pc 是用来描述一个库的名称、版本、编译选项、链接选项等内容的文件,因此它需要包含:名称、描述、版本信息、编译选项和链接选项几个部分,具体来说,是对 Name、Description、Version、Cflags、Libs 五个变量的一个定义,定义方式为变量: 内容,其中 CflagsLibs 可能会使用编译或者链接的一些选项,例如 -I-L 等。

1
2
3
4
5
6
# mylib.pc
Name: mylib
Description: mylib for test
Version: 1.0
Cflags:-I/XXX/mylib/include
Libs:-L/XXX/mylib/lib –lmylib

当然,这个文件也可以定义其他变量,以方便使用。例如目录可以使用一个变量来定义,这样在 CflagsLibs 中就直接使用该变量即可,例如:

1
2
3
4
5
6
7
# mylib.pc
librootdir=/XXX/mylib
Name: mylib
Description: mylib for test
Version: 1.0
Cflags:-I${librootdir}include
Libs:-L${librootdir}/lib –lmylib

下面来写一个 mymath 库的简单示例。

1
2
3
4
5
6
7
8
# mymath.pc
librootdir=/home/lushuangning/Code/cmake/mymath

Name: mymath
Description: a simple add function
Version: 1.0
Cflags: -I${librootdir}/include
Libs: -L${librootdir}/lib -lmymath

点击下载 包含 .pc 文件的 mymath 库。

.pc 文件对 pkg-config 可见

这里我采用把 mymath.pc 的路径添加到环境变量 PKG_CONFIG_PATH 中的方式。

此时,在终端中执行下面的命令来获取 mymath 库的信息:

1
2
3
4
~/Code/cmake/mymath ❯ pkg-config --list-all | grep "mymath"
mymath mymath - a simple add function
~/Code/cmake/mymath ❯ pkg-config --cflags --libs mymath
-I/home/lushuangning/Code/cmake/mymath/include -L/home/lushuangning/Code/cmake/mymath/lib -lmymath

测试 pkg-configmymath 库的使用

编译命令如下

1
2
// 在终端中执行
g++ -o test test.cpp `pkg-config --cflags --libs mymath`

运行结果:

1
2
3
4
5
6
7
~/Code/cmake/myproj ❯ g++ -o test test.cpp `pkg-config --cflags --libs mymath`
~/Code/cmake/myproj ❯ ll
total 24K
-rwxr-xr-x 1 lushuangning lushuangning 17K Dec 6 00:14 test
-rw-r--r-- 1 lushuangning lushuangning 89 Nov 30 14:14 test.cpp
~/Code/cmake/myproj ❯ ./test
Add 1 and 2 is 3