摸了两天的unix环境下的编程,其中的开山之碍是对apue.h及相关文档的处理。先来小览一下这两天的著多,成果吧。本打算低低调调的做coding,没想到一开始就遇到了麻烦。涮涮的编了个程序,可是在linux gcc下一调,真是warning and error一长列,那个郁闷啊,当时很是惊慌,我堕落于此呼?还是好好的解决吧。apue.h以及一些相关的出错处理文件找不着,对啊,我一看是没有啊,SO长时间没有编程,但不致于大意如此吧,心中一阵冷汗。后来补上了这些文档,可是编译,未果!想想问题是出自哪了?怎么就是找不到这个文件和相关的函数呢。于是深思,找了两个方法解决:
1.将在编译中error的函数,用man命令找出,然后分别再包括进应用程序中,并将相关的提示出错处理函数改用printf()输出。这样就可以通过编译。但是之个方法,对于效率来说是大大的打了折扣,一是要在每个文件中都要增加这些系统头文件,另一方面,如果有一个修改了,所有的引用此文件的都要修改。工作量大且烦。这就相当于你如果有事要通知,你是发N个消息给每一个人呢,还是建立一个群,由这个群的相关机制帮你完成通知工作,这就是1:N与1:1:N这两者关系的优劣的问题。于是想到了另一个方法。
2.就是将apue.h和apue_err.c、apue_log.c编译成一个库。以后都是对这个库的引用,以后如果以上这几个文件要有修改,只要重新编译这个库就可以了,而应用程序与库之间的接口不变,不用更改,至于库是怎么实现的,这就不关应用程序的事了。很好的实现了“四两博千斤”之势。突然醒悟为什么国际上那么多的组织为什么花那么大的心思在做接口的标准化工作。接口的标准化横向上让不同系统之间的通信变得平坦,纵向上让系统构架上将接口与实现分开,尽量减少修改时的“遍地开花”的局面。
下面针对第二点,看看将多个文件编译成库的方法,在此之前要先了解系统一般默认的头文件和库文件的收搜位置是:/usr/include 和/usr/lib。但这只是默认而矣。
第一种情况是将这三个文件放在/home/dlruan/include下的情况:因为不在默认的收搜位置,所以在编译时要向链接阶段的LD提供库位置的信息就可以了。还有一点要说明就是#include“”与#include<>这两个的区别,前者“”系统先到指定的目录中找->到指定的-Idirname中去找->到系统默认的目录中去找。而<>到系统默认指定的目录中去找。
1.在VI下编辑这三个文件:apue.h , apue_err.c , apue_log.c
2.将.c文件编译成目标文件。
gcc -c apue_err.c -o apue_err.o
gcc -c apue_log.c -o apue_log.o
3.将目标文件和头文件一起编译成静态库(。a文件):
ar rcs libapue.a apue.h apue_err.o apue_log.o
4.切换到//home/dlruan/chap01下,编译1-1.c文件(第一行的要变为#include “../include/apue.h”,虽然将apue.h放入库中,本以为指定了库的收搜位置就可以不用写成这个样子了,但是后来想想编译的4过程,如果写成#include “apue.h”,这是编译不通的,本指望去收搜库能找到,后一想要先预编译,不能根据后边的信息来指导前边的过程,还没到连接库阶段呢,,到第四步才连接库呢,因此一定要将包含的头文件位置写对才行)。
gcc 1-1.c -L /home/dlruan/include -lapue -o 1-1
5.执行程序
./1-1 /home/dlruna/chap01
6.执行正确。
以上是编译成静态库的过程,如果要编译为动态库(。so文件),则过程如下:
1.在VI下编辑这三个文件:apue.h , apue_err.c , apue_log.c
2.将.c文件编译成目标文件。
gcc -c apue_err.c -o apue_err.o
gcc -c apue_log.c -o apue_log.o
7.将目标文件和头文件一起编译成动态库:
gcc -shared -o libapue.so apue.h apue_err.o apue_log.o
8.切换到//home/dlruan/chap01下,编译1-1.c文件(第一行的要变为#include “../include/apue.h”,虽然将apue.h放入库中,本以为指定了库的收搜位置就可以不用写成这个样子了,但是后来想想编译的4过程,如果写成#include “apue.h”,这是编译不通的,本指望去收搜库能找到,后一想要先预编译,不能根据后边的信息来指导前边的过程,还没到连接库阶段呢,,到第四步才连接库呢,因此一定要将包含的头文件位置写对才行)。
gcc 1-1.c -L /home/dlruan/include -lapue -o 1-1
9.执行程序
./1-1 /home/dlruna/chap01
10.执行正确。
以上大体也是对静态和动态文件编译成库的方法。但是发现了每次编译应用程序时都要指定库的收搜目录即:-Ldirname,这个很烦,所以能不能更改了下,那就是将这个库文件放到系统默认的目录下/usr/lib下,这样就可以变成:gcc 1-1.c -lapue -o 1-1 这样系统在做第四个阶段的工作时,就会到系统默认的目录下去找。理解编译的原理和过程,对这个的理解会有很大的帮助。一般库分为头文件和函数的定义(实现),将一些变量的声明和函数的原型声明放到头文件中,头文件一般是由编译的第一阶段中使用的。而函数的具体定义是即实现是放在我们所谓的库函数中,这个实现被编译成目标文件,这一做法一是保护开发商的利益,是二进制代码。另一方面实现代码的重用。只在链接阶段根据指定的地址信息进行连接就可以了,如果没有明确指定就按系统默认的来,如果指定了库的位置,则链接阶段就从指定位置找到函数的实现信息。