Makefile好助手:pkgconfig
你在Unix下开发过软件吗?写完一个程序,编译运行完全正常,在你本机上工作得好好的,你放到源代码管理系统中。然后,告诉你的同事说,你可以取下来用了。这时,你长长的出了一口气,几天的工作没有白费,多么清新的空气啊,你开始飘飘然了。 “Hi,怎么编译不过去?”你还沉浸在那种美妙的感觉之中,双臂充满着力量,似乎没有什么问题能难倒你的。正在此时,那个笨蛋已经冲着你嚷开了。 “不会吧,我这边
你在Unix下开发过软件吗?写完一个程序,编译运行完全正常,在你本机上工作得好好的,你放到源代码管理系统中。然后,告诉你的同事说,你可以取下来用了。这时,你长长的出了一口气,几天的工作没有白费,多么清新的空气啊,你开始飘飘然了。
“Hi,怎么编译不过去?”你还沉浸在那种美妙的感觉之中,双臂充满着力量,似乎没有什么问题能难倒你的。正在此时,那个笨蛋已经冲着你嚷开了。
“不会吧,我这边好好的!”表面上你说得很客气,其实,你心里已经骂开了,真笨,不知道脑子干嘛用的。也许,你想的没错,上次,他犯了一个简单的错误,不是你一去就解决了吗。
他喊三次之后,你不得不放下你手上的工作,刚才那种美妙的感觉已经消失得无影无踪了,要不是你把情绪控制得很好,一肚子气就要撒在他身上了。你走到他的电脑前,键入make,优雅的按下回车。怎么可能出错呢?你信心十足。然而,屏幕上的结果多少有点让人脸红,该死的,libxxx.so怎么会让不到呢?
你在/usr目录中查找libxxx.so,一切都逃不过你的眼睛。奇怪,libxxx.so怎么在/usr/local/lib下,不是应该在/usr/lib下的吗?这你可不能怪别人,别人想安装在哪里都行,下次还可能安装到/lib目录下呢。
以上的场景并非虚构,我都经历过好几次,明明在本机上好好的,在别人的机器上连编译都过不去。可能两人的操作系统一模一样,需要的库都安装上,只是由于个人喜好不同,安装在不同的目录而已。遇到这种情况,每次都技巧性的绕过去了,用的补丁型的方法,心里老惦记其它地方能不能工作。
今天我们要介绍的pkgconfig,为解决以上问题提供了一个优美方案。从此,你再也不为此担忧了。Pkgconfig提供了下面几个功能:
1. 检查库的版本号。如果所需要的库的版本不满足要求,它会打印出错误信息,避免链接错误版本的库文件。
2. 获得编译预处理参数,如宏定义,头文件的位置。
3. 获得链接参数,如库及依赖的其它库的位置,文件名及其它一些连接参数。
4. 自动加入所依赖的其它库的设置。
这一切都自动的,库文件安装在哪里都没关系!
在使用前,我们说说pkgconfig的原理,pkgconfig并非精灵,可以凭空得到以上信息。事实上,为了让pkgconfig可以得到这些信息,要求库的提供者,提供一个.pc文件。比如gtk+-2.0的pc文件内容如下:
prefix=/usr
exec_prefix=/usr
libdir=/usr/lib
includedir=/usr/include
target=x11
gtk_binary_version=2.4.0
gtk_host=i386-redhat-linux-gnu
Name: GTK+
Description: GIMP Tool Kit (${target} target)
Version: 2.6.7
Requires: gdk-${target}-2.0 atk
Libs: -L${libdir} -lgtk-${target}-2.0
Cflags: -I${includedir}/gtk-2.0
这个文件一般放在/usr/lib/pkgconfig/或者/usr/local/lib/pkgconfig/里,当然也可以放在其它任何地方,如像X11相关的pc文件是放在/usr/X11R6/lib/pkgconfig下的。为了让pkgconfig可以找到你的pc文件,你要把pc文件所在的路径,设置在环境变量PKG_CONFIG_PATH里。
使用方法很简单,比如,我们要使用gtk+的库编译一个程序:
gcc -g arrow.c -o arrow `pkg-config "gtk+-2.0 > 2.0.0" --cflags --libs`
只要安装了gtk+2.0,不管它在哪里,编译都是正常的。这是不是简单很多了?
++++++++++++++++++++++++++++++++++++++++++++++pkg-config
pkg-config 查看gcc的CFLAGS参数
Perhaps you should add the directory containing `opencv.pc'
to the PKG_CONFIG_PATH environment variable
No package 'opencv' found
================================================================
查看一个.pc文件的内容:
[root@yx pkgconfig]# cat glib-2.0.pc
prefix=/usr
exec_prefix=/usr
libdir=/lib
includedir=/usr/include
configexecincludedir=/usr/lib/glib-2.0/include
glib_genmarshal=glib-genmarshal
gobject_query=gobject-query
glib_mkenums=glib-mkenums
Name: GLib
Description: C Utility Library
Version: 2.12.3
Libs: -L${libdir} -lglib-2.0
Cflags: -I${includedir}/glib-2.0 -I${configexecincludedir}
[root@yx pkgconfig]# pwd
/usr/lib/pkgconfig
可见.pc文件 是对其的库文件路径,头 文件路径, 版本号,Cflags等一些参数进行封装。
再来看看第一个Gtk+程序里的 `pkg-config --cflags --libs gtk+-2.0`意思:
`pkg-config --cflags --libs gtk+-2.0` 是pkg-config从路径/usr/lib/pkgconfig
/gtk+-2.0.pc中提取出来的用于编译用的。
[root@yx pkgconfig]# cat gtk+-2.0.pc
prefix=/usr
exec_prefix=/usr
libdir=/usr/lib
includedir=/usr/include
target=x11
gtk_binary_version=2.10.0
gtk_host=i686-redhat-linux-gnu
Name: GTK+
Description: GIMP Tool Kit (${target} target)
Version: 2.10.4
Requires: gdk-${target}-2.0 atk cairo
Libs: -L${libdir} -lgtk-${target}-2.0
Cflags: -I${includedir}/gtk-2.0
显然,出可以自己来指定为:-L/usr/lib -lgtk-{target}-2.0 -I/usr/include/gtk-2.0
下面来看一下{target}该是多少:
[root@yx lib]# ls gt
gthumb/ gtk-2.0/ gtkhtml/
gtk/ gtk-sharp-2.0/ gtkmm-2.4/
[root@yx lib]# ls gtk-2.0/
2.10.0 2.4.0 immodules include modules
[root@yx lib]# ls gtk-sharp-2.0/
gconfsharp-schemagen.exe
[root@yx lib]# pwd
/usr/lib
所以认为 -lgtk-{target}-2.0中的 {target}该是空字符:
-lgtk-{target}-2.0====> -lgtk--2.0
At Last So:(理论大致上:)
-L/usr/lib -lgtk-{target}-2.0 -I/usr/include/gtk-2.0 ====>
-L/usr/lib -lgtk--2.0 -I/usr/include/gtk-2.0
而实际上更多些:
对比pkg-config对gtk+-2.0看实际效果:
[yuxu@yx base]$ pkg-config --cflags --libs gtk+-2.0
-I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/freetype2 -I/usr/include/libpng12 -L/lib -lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lm -lpangocairo-1.0 -lpango-1.0 -lcairo -lgobject-2.0 -lgmodule-2.0 -ldl -lglib-2.0
后面还有很多的路径哦。
gtk_base.c:
#include <gtk/gtk.h>
int main(int argc,char *argv[])
{
GtkWidget *window;
gtk_init(&argc,&argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_show(window);
gtk_main();
return FALSE;
}
gcc -o gtk_base gtk_base.c `pkg-config --cflags --libs gtk+-2.0`
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)