pkg-config

前言

在介绍 pkg-config 之前,先讲一个我的经历。
有一次我想用 libgtk 库在 ubuntu 上实现一个简单的图形界面,就像下面代码

#include 

int main(int argc, char *argv[])
{
	GtkWidget *window;

	gtk_init(&argc, &argv);
	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gtk_widget_show(window);
	g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
	gtk_main();

	return 0;
}

写个 Makefile 进行编译

gtk:
	gcc gtk.c -o gtk.out -lgtk

run:
	./gtk.out

想的简单,使用 gtk 库就引用下库 -lgtk 就好了,结果,编译报错

gcc gtk.c -o gtk.out -lgtk
gtk.c:1:10: fatal error: gtk/gtk.h: 没有那个文件或目录
    1 | #include <gtk/gtk.h>
      |          ^~~~~~~~~~~
compilation terminated.
make: *** [Makefile:4:gtk] 错误 1

没有 gtk.h,那就查找该文件在哪,

$ locate gtk.h
/usr/include/gtk-2.0/gtk/gtk.h

添加下头文件路径

gtk:
	gcc gtk.c -o gtk.out -lgtk \
	-I /usr/include/gtk-2.0

run:
	./gtk.out

编译,结果又报错

$ make
gcc gtk.c -o gtk.out -lgtk \
-I /usr/include/gtk-2.0
In file included from /usr/include/gtk-2.0/gdk/gdk.h:32,
                 from /usr/include/gtk-2.0/gtk/gtk.h:32,
                 from gtk.c:1:
/usr/include/gtk-2.0/gdk/gdkapplaunchcontext.h:30:10: fatal error: gio/gio.h: 没有那个文件或目录
   30 | #include <gio/gio.h>
      |          ^~~~~~~~~~~
compilation terminated.
make: *** [Makefile:4:gtk] 错误 1

就这样,头文件路径我一直加到如下,

gtk:
	gcc gtk.c -o gtk.out -lgtk \
	-I /usr/include/gtk-2.0 \
	-I /usr/include/glib-2.0 \
	-I /usr/lib/x86_64-linux-gnu/glib-2.0/include \
	-I /usr/lib/x86_64-linux-gnu/gtk-2.0/include \
	-I /usr/include/cairo \
	-I /usr/include/pango-1.0 \
	-I /usr/include/harfbuzz/ \
	-I /usr/include/gdk-pixbuf-2.0 \
	-I /usr/include/atk-1.0

run:
	./gtk.out

结果报 找不到 -lgtk,崩溃

pkg-config

后来,找到了 pkg-config 这个绝招,只要一行就解决了我上面的问题

gtk:
	gcc gtk.c -o gtk.out `pkg-config --cflags --libs gtk+-2.0`

run:
	./gtk.out

编译成功,运行效果如下
pkg-config_第1张图片
回过头再来看下 pkg-config 作用

什么是 pkg-config

pkg-config 是一个 linux 下的命令,用于获得某一个库/模块的所有编译相关的信息。
例子

$ pkg-config --cflags --libs gtk+-2.0
-pthread -I/usr/include/gtk-2.0 -I/usr/lib/x86_64-linux-gnu/gtk-2.0/include -I/usr/include/pango-1.0 -I/usr/include/atk-1.0 -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/pango-1.0 -I/usr/include/fribidi -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/harfbuzz -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/uuid -I/usr/include/freetype2 -I/usr/include/libpng16 -lgtk-x11-2.0 -lgdk-x11-2.0 -lpangocairo-1.0 -latk-1.0 -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lpangoft2-1.0 -lpango-1.0 -lgobject-2.0 -lglib-2.0 -lharfbuzz -lfontconfig -lfreetype

为什么要有 pkg-config

从上面的例子,可以看出,pkg-config 给出了 gtk+-2.0 的头文件和库的所有信息!
这有什么好处?
所有用 gtk+-2.0 的其他程序,在编译时,只需要写 pkg-config --cflags --libs gtk+-2.0,而不需要自己去找 gtk+-2.0 的头文件在哪里,要链接的库在哪里!省时省力!
如果你写了一个库,不管是静态的还是动态的,要提供给第三方使用,那除了给人家库/头文件,最好也写一个 pkg-config 文件,这样别人使用就方便很多,不用自己再手动写依赖了你哪些库,只需要敲一个 pkg-config --libs --cflags [YOUR_LIB]

pkg-config 的信息从哪里来

很简单,有 2 种路径:
第一种:取系统的 /usr/lib 下的所有 *.pc 文件。
第二种:PKG_CONFIG_PATH 环境变量所指向的路径下的所有 *.pc 文件。

这些 pc 文件什么时候有的?都是在你安装某个库/模块的时候,添加的。比如你往系统安装libcrypt-dev 时,就会在 /usr/lib/x86_64-linux-gnu/pkgconfig/ 目录下,放一个 libcrypt.pc。
那么,pc文件到底写了什么?
打开看看就知道啦。比如 libcrypt.pc

$ cat /usr/lib/x86_64-linux-gnu/pkgconfig/libcrypt.pc
#############################################
#####   Pkg-Config file for libxcrypt   #####
#############################################

prefix=/usr
exec_prefix=${prefix}

libdir=/usr/lib/x86_64-linux-gnu
includedir=${prefix}/include

Name: libxcrypt
Version: 4.4.10
Description: Extended crypt library for DES, MD5, Blowfish and others
Libs: -L${libdir} -lcrypt
Cflags: -I${includedir}

一目了然,就是存了所有 libcrypt 的头文件/库的路径信息。

pkg-config 都有哪些命令参数

所有参数,可以通过 pkg-config –help 来查看。
但我觉得其实就 3 个参数有用。
pkg-config --cflags [NAME],查看头文件信息,如

$ pkg-config --cflags gtk+-2.0
-pthread -I/usr/include/gtk-2.0 -I/usr/lib/x86_64-linux-gnu/gtk-2.0/include -I/usr/include/pango-1.0 -I/usr/include/atk-1.0 -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/pango-1.0 -I/usr/include/fribidi -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/harfbuzz -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/uuid -I/usr/include/freetype2 -I/usr/include/libpng16

pkg-config --libs [NAME],查看库信息,如

pkg-config --libs gtk+-2.0
-lgtk-x11-2.0 -lgdk-x11-2.0 -lpangocairo-1.0 -latk-1.0 -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lpangoft2-1.0 -lpango-1.0 -lgobject-2.0 -lglib-2.0 -lharfbuzz -lfontconfig -lfreetype

pkg-config --list-all。查看 pkg-config 的所有模块信息,如

$ pkg-config --list-all
xf86driproto                   XF86DRIProto - XF86DRI extension headers
libelf                         libelf - elfutils libelf library to read and write ELF files
cairo-ps                       cairo-ps - PostScript surface backend for cairo graphics library
ncursesw                       ncursesw - ncurses 6.2 library
libcrypto                      OpenSSL-libcrypto - OpenSSL cryptography library
libnfnetlink                   libnfnetlink - Low-level netfilter netlink communication library
libffi                         libffi - Library supporting Foreign Function Interfaces
python-2.7                     Python - Python library
...

如何添加自己的 pc 文件

如上文所说,有 2 种方式。

  1. 把你的 pc 文件,直接放到 /usr/lib/… 默认路径下。
  2. 把你的 pc 文件的路径写到 PKG_CONFIG_PATH 环境变量里。

比如,你可以在 ~/.bashrc 的文件末尾添加:

PKG_CONFIG_PATH=$PKG_CONFIG_PATH:xxx/pkgconfig/
export PKG_CONFIG_PATH

那么,pkg-config 就会到 xxx/pkgconfig/ 寻找 *.pc 文件。
我猜你想问,那我这个pc文件何时生效呢?
答案是,如果是 /usr/lib 下,立马生效!!!如果在环境变量里,只要先 source ~/.bashrc 一下,让环境变量生成,也立马生效。
并不需要什么 pkg-config update 啥命令,让其更新信息。
其实每次你执行 pkg-config,都会去遍历所有的 *.pc 文件。

如何自己写 pkg-config 的 pc 文件

其实很简单,只需要拿别人的 pc 文件改一改就行了。不过我还是提一下吧。
pc 文件的所有参数:

Name: 该模块的名字,比如你的 pc 名字是 xxxx.pc,那么名字最好也是 xxxx。
Description: 模块的简单描述。上文 pkg-config --list-all 命令出来的结果,每个名字后面就是 description。
URL: 用户可以通过该 URL 获得更多信息,或者下载信息。也是辅助的,可要可不要。
Version: 版本号。
Requires: 该模块有木有依赖于其他模块。一般没有。
Requires.private: 该模块有木有依赖于其他模块,并且还不需要第三方知道的。一般也没有。
Conflicts: 有没有和别的模块冲突。常用于版本冲突。比如,Conflicts: bar < 1.2.3,表示和 bar 模块的 1.2.3 以下的版本有冲突。
Cflags: 这个就很重要了。pkg-config 的参数 --cflags 就指向这里。主要用于写本模块的头文件的路径。
Libs: 也很重要,pkg-config 的参数 --libs 就指向这里。主要用于写本模块的库/依赖库的路径。
Libs.private: 本模块依赖的库,但不需要第三方知道。

其实必须写的只有 5 个。Name、Description、Version、Cflags、Libs。

参考

pkg-config 详解

你可能感兴趣的:(#,C,Linux,c++,linux,ubuntu,pkg-config)