在cmake中使用pkg-config

package-153360_960_720.png

什么是pkg-config

简单理解,pkg-config根据.pc结尾的文件做依赖配置。
找到.pc文件周,解析其内容,然后对底层构建工具(C/C++编译器、链接器)或高层构建工具(automake?, cmake)提供具体配置项目。

通常是在POSIX系统(Linux,MacOS等)使用pkg-config,解决第三方依赖项配置问题。

近些年来随着CMake的越发流行,原本用pkg-config的很多软件包提供了cmake的配置作为替代;少部分仍然提供.pc文件作为兼容考虑;还有另外一小部分的软件包,即使基于cmake构建了,对外提供依赖配置时仍然只有.pc文件。

这就导致一个问题:虽然我学会了cmake在大部分时候都能解决依赖问题,但个别格楞子软件包还是要用pkg-config来搞。

pkg-config的基本使用

官方说明

最直接的说明,来自于Ubuntu下pkg-config的man页面:

DESCRIPTION
       The  pkg-config program is used to retrieve information about installed libraries in the system.  It
       is typically used to compile and link against one or more libraries.  Here is a typical  usage  sce‐
       nario in a Makefile:

       program: program.c
            cc program.c $(pkg-config --cflags --libs gnomeui)

       pkg-config  retrieves  information about packages from special metadata files. These files are named
       after the package, and has a .pc extension.  On most systems, pkg-config looks  in  /usr/lib/pkgcon‐
       fig,  /usr/share/pkgconfig, /usr/local/lib/pkgconfig and /usr/local/share/pkgconfig for these files.
       It will additionally look in the colon-separated (on Windows, semicolon-separated) list of  directo‐
       ries specified by the PKG_CONFIG_PATH environment variable.

       The  package name specified on the pkg-config command line is defined to be the name of the metadata
       file, minus the .pc extension. If a library can install multiple versions  simultaneously,  it  must
       give  each  version  its own name (for example, GTK 1.2 might have the package name "gtk+" while GTK
       2.0 has "gtk+-2.0").

       In addition to specifying a package name on the command line, the full path to a given .pc file  may
       be given instead. This allows a user to directly query a particular .pc file.

也就是说,pkg-config默认会在以下路径中查找指定的包(库)对应的.pc文件:

  • /usr/lib/pkgconfig目录
  • /usr/share/pkgconfig目录
  • /usr/local/lib/pkgconfig目录
  • /usr/local/share/pkgconfig目录
  • PKG_CONFIG_PATH环境变量里的目录(可通过export PKG_CONFIG_PATH=XXX来修改)
  • 给pkg-config传入的.pc文件绝对路径

而比较常用的选项是:

--cflags  表示C/C++编译选项,例如指定头文件搜索目录
--libs    表示链接选项,例如库的绝对目录,链接库按顺序列出等

例如Linux下apt安装的opencv的结果分别为:

(base) 1080Ti% pkg-config opencv --cflags
-I/usr/include/opencv
(base) 1080Ti% pkg-config opencv --libs  
/usr/lib/x86_64-linux-gnu/libopencv_calib3d.so -lopencv_calib3d /usr/lib/x86_64-linux-gnu/libopencv_contrib.so -lopencv_contrib /usr/lib/x86_64-linux-gnu/libopencv_core.so -lopencv_core /usr/lib/x86_64-linux-gnu/libopencv_features2d.so -lopencv_features2d /usr/lib/x86_64-linux-gnu/libopencv_flann.so -lopencv_flann /usr/lib/x86_64-linux-gnu/libopencv_gpu.so -lopencv_gpu /usr/lib/x86_64-linux-gnu/libopencv_highgui.so -lopencv_highgui /usr/lib/x86_64-linux-gnu/libopencv_imgproc.so -lopencv_imgproc /usr/lib/x86_64-linux-gnu/libopencv_legacy.so -lopencv_legacy /usr/lib/x86_64-linux-gnu/libopencv_ml.so -lopencv_ml /usr/lib/x86_64-linux-gnu/libopencv_objdetect.so -lopencv_objdetect /usr/lib/x86_64-linux-gnu/libopencv_ocl.so -lopencv_ocl /usr/lib/x86_64-linux-gnu/libopencv_photo.so -lopencv_photo /usr/lib/x86_64-linux-gnu/libopencv_stitching.so -lopencv_stitching /usr/lib/x86_64-linux-gnu/libopencv_superres.so -lopencv_superres /usr/lib/x86_64-linux-gnu/libopencv_ts.so -lopencv_ts /usr/lib/x86_64-linux-gnu/libopencv_video.so -lopencv_video /usr/lib/x86_64-linux-gnu/libopencv_videostab.so -lopencv_videostab

pkg-config到底用的是哪个.pc文件?

比如我系统装了好多个版本的opencv,那么pkg-config到底找到并使用的是哪个opencv.pc呢?

pkg-config opencv --debug > log.txt 2>&1
ag 'opencv.pc' log.txt

(不知为何,我用不了管道操作符,用了xargs也不行)
输出:

⚡ ag 'opencv.pc' log.txt 
167:File 'opencv.pc' appears to be a .pc file
168:Will find package 'opencv' in file '/usr/lib/x86_64-linux-gnu/pkgconfig/opencv.pc'
521:Reading 'opencv' from file '/usr/lib/x86_64-linux-gnu/pkgconfig/opencv.pc'
522:Parsing package file '/usr/lib/x86_64-linux-gnu/pkgconfig/opencv.pc'

于是打开/usr/lib/x86_64-linux-gnu/pkgconfig/opencv.pc文件,可以发现是2.4.9.1版本。

给编译器和链接器传入pkg-config的结果

例如单个文件使用opencv:

g++ -o a.out hello_opencv.cpp `pkg-config --libs opencv`

也可以在Makefile中进行设定。例如著名的Darknet,它早期某个版本的makefile内容如下:

CC=gcc
CFLAGS=-Wall `pkg-config --cflags opencv` -O3 -flto -ffast-math
CFLAGS=-Wall `pkg-config --cflags opencv` -O0 -g
LDFLAGS=`pkg-config --libs opencv` -lm
VPATH=./src/

OBJ=network.o image.o tests.o convolutional_layer.o connected_layer.o maxpool_layer.o activations.o

all: cnn

cnn: $(OBJ)
    $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@

%.o: %.c 
    $(CC) $(CFLAGS) -c $< -o $@

.PHONY: clean

clean:
    rm -rf $(OBJ) cnn

CMake中使用pkg-config

1. 安装pkg-config

安装pkg-config,并确保在CMake中能找到它的可执行文件。

Ubuntu: sudo apt install pkg-config

Windows: 下载 pkg-config-lite 。注意Anaconda/Miniconda中也带了pkg-config,但实测cmake中无法使用。为避免冲突,这里不把pkg-config-lite版的可执行文件路径放PATH系统环境变量,而是在cmake中单独配置:

set(PKG_CONFIG_EXECUTABLE "D:/soft/pkg-config/bin/pkg-config.exe")

2. CMakeLists.txt中使用pkg-config

包括3个具体的步骤:

  • 确定.pc文件绝对路径(例如只提供.pc方式配置),记作$prefix/xxx.pc

  • 在CMakeLists.txt中,分别把$prefix和xxx填写入座:

set(ENV{PKG_CONFIG_PATH} $prefix)
find_package(PkgConfig)
pkg_search_module(MyDepName REQUIRED xxx)

其中MyDepName是自行起的名字,可以和原始包的名字不一样

  • 后续使用${MyDepName_LIBRARIES}${MyDepName_INCLUDE_DIRS}即可

3. 举例

Ubuntu 16.04下用apt安装openblas并在CMake中用pkg-config方式配置:

#安装
sudo apt install libopenblas-dev

#查找.pc文件。
#若查不到,执行sudo apt install --reinstall libopenblas-dev再执行
dpkg -L libopenblas-dev | grep '.pc'

#找到,在/usr/lib/pkgconfig/blas-openblas.pc

编写CMakeLists.txt,把/usr/lib/pkgconfig/blas-openblas.pc拆分为/usr/lib/pkgconfigblas-openblas:

cmake_minimum_required(VERSION 3.15)

project(cmake_pkg_config_example)

set(ENV{PKG_CONFIG_PATH} /usr/lib/pkgconfig)
find_package(PkgConfig)
pkg_search_module(OBS REQUIRED blas-openblas)

message(STATUS "=== OBS_LIBRARIES: ${OBS_LIBRARIES}")
message(STATUS "=== OBS_INCLUDE_DIRS: ${OBS_INCLUDE_DIRS}")

其中OBS是我随便起的前缀,你也可以换成别的。后续使用这个库的时候,使用OBS_LIBRARIESOBS_INCLUDE_DIRS即可。

Windows 10下用CMake配置Pangolin安装中配置的zlib
Pangolin怎么配置这里就不贴了,正常使用cmake调用Visual Studio编译的流程即可。它会自动源码编译安装zlib。这里假设另一个项目要用到这个版本的zlib,则CMakeLists.txt写法如下:

cmake_minimum_required(VERSION 3.15)

project(cmake_pkg_config_example)

#指定pkg-config.exe绝对路径
set(PKG_CONFIG_EXECUTABLE "D:/soft/pkg-config/bin/pkg-config.exe")

#指定zlib.pc所在目录
set(ENV{PKG_CONFIG_PATH} "D:/lib/pangolin/share/pkgconfig")

find_package(PkgConfig)
message(STATUS "--- PKG_CONFIG_FOUND: ${PKG_CONFIG_FOUND}")
message(STATUS "--- PKG_CONFIG_VERSION_STRING: ${PKG_CONFIG_VERSION_STRING}")

pkg_search_module(ZLIB REQUIRED zlib)

message(STATUS "=== ZLIB_LIBRARIES: ${ZLIB_LIBRARIES}")
message(STATUS "=== ZLIB_INCLUDE_DIRS: ${ZLIB_INCLUDE_DIRS}")

参考

FindPkgConfig----CMake的pkg-config模块

CMake的pkg-config模块使用

How to install pkg config in windows?

pkg-config-lite SourceForge

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270