重学C语言:你真的会用这些工具吗,pkg-config-pkg文件怎么打开

重学C语言:你真的会用这些工具吗,pkg-config-pkg文件怎么打开

c语言历史

1978年前后,K&R发明了C语言,并编写了UNIX操作系统。

1989年,ANSI出版了C语言标准,被称为ANSI C89。

1999年,C标准经历了一次主要的改版。为数值和科学计算增添了一些附加功能,单行注释,for循环中声明变量等等。

2011年,C11标准发布,有了可以编写泛型函数的方法。

POSIX标准

Portable Operating System Interface of UNIX,缩写为 POSIX。实际上1978年C和UNIX都问世了,到了1988年POSIX标准建立,随后1989年C语言标准建立。当前最新的POSIX标准应该是2008年的标准。C语言标准和POSIX标准之间是存在一定联系的。例如POSIX标准定义了shell脚本如何工作,以及C程序原希望用到的一些C库。例如C语言的popen(打开管道)就是POSIX标准,而不是C语言定义的内容。POSIX标准的操作系统必须通过支持C99的编译器编译。几乎所有的操作系统都建立在POSIX兼容的基础上,甚至windows server也是基于POSIX的。

BSD和GNU是两个有着较高流行度和影响力的POSIX的实现版本,BSD许可证的要求弱于GNU,它要求使用者维持BSD授权源码原有的版权声明和免责声明,但不要求同时提供你的源码。如果你要商用GNU声明过的源码,GNU有权要求你公开源码。

编译环境

编译器,首选gcc

gdb调试器,可以单步执行C代码

Valgrind,用于测试C内存使用错误

Gprof,用于运行效率评测

Make,使你不用直接调用编译器,优化编译过程

pkg-config,用于查找库

doxygen,用于生成程序文档

text editor,这个就不多说了,每个人都有自己喜欢的编辑器。

开始编写代码了

#include <math.h> //erf,sqrt

#include <stdio.h> //printf

int main(){

printf("the integral of a Normal(0,1) distribution"

"between -1.96 and 1.96 is :0\n",ert(1.96*sqrt(1/2.)));

}

这段代码没啥好解释的,和helloworld差不多。我们来看看如何编译的。

gcc erf.c -o erf -lm -g -Wall -O3 -std=gnull

-o用来给出输出的文件名

-lm表示math库需要被链接进来,实际上gcc编译时有一个隐含的-lc选项,把libc库链接进来了,否则printf是找不到的。

-g表示加入调试符号,这些符号不会把程序拖慢,但是会增大程序的大小(占用硬盘的大小)。

-std=gnull,允许你使用符合C11和POSIX标准的代码。如果你的代码是C11标准发布之前的,可以使用-std=gnu99

-O3是指优化等级为3级,

-Wall添加编译器告警,你也可以加上-Werror,那么所有告警都当作错误处理,你必须解决所有的编译告警才能得到编译结果。

链接库文件

如果你的代码用到了个库,并且这个库放在某个特定位置,那么你的gcc语句应该如下所示:

gcc -I/usr/local/include erf.c -o erf -L/usr/local/lib -luserful

-I选项指定编译器的搜索范围,这里可以找到这个lib的供外部使用的头文件

-L选项指定链接时库的搜索路径

假如你需要用到两个库,而且着两个库又存在依赖关系,那么在gcc中需要按顺序给定库的搜索路径。假设libgel依赖libboard,gcc语句如下:

gcc erf.o -lborad -lgel

一般来说,如果你找到一个库文件在/some/path/lib中,那么对应的头文件会在/some/path/include中。

在硬盘中查找库文件是很烦人的事情,实际上pkg-config维护了一个包含配置信息和位置信息的资料库,如果你的机器中没有,建议安装。

sudo apt-get install pkg-config

然后安装libxml

sudo apt-get install libxml2

安装完成之后,我们就可以看看pkg-config的功能了

ubuntu$ pkg-config --libs libxml-2.0

-lxml2 //这里得到的刚好是链接是所需要的

ubuntu$ pkg-config --cflags libxml-2.0

-I/usr/include/libxml2 //这里得到的刚好是gcc编译时所需要的。

因此gcc语句可以改写为

gcc 'pkg-config --cflags --libs libxml-2.0' -o erf erf.c

需要提醒的是,不是所有的平台都又pkg-config,也不是每个库都用它注册。

编译器在链接静态库时,是将库里的相关内容直接复制到最终的可执行文件。而共享库是你的程序在运行时链接进去的,此时需要在运行过程中查找库文件。如果你的库在一个非标准的路径,那你需要找到一个修改运行时搜索路径的方法。

如果你用autotools打包你的程序,libtools知道如何添加何时的选项。但是如果你使用gcc编译,就需要添加如下语句:

LDADD=-Llibpath -W1, -Rlibpath

-W1是从gcc传递这个选项到连接器。而连接器将给定的-R嵌入所连接的库的运行时搜索路径。

后记

下一次讲讲常用的makefile语法

推荐阅读