linux下《UNIX环境高级编程》(apue2)源码编译出错的处理方法
文章出处:http://www.diybl.com/course/3_program/c++/cppjs/2008617/126036.html
相信很多跟我一样想要学习unix编程的朋友在兴冲冲拿到《unix环境高级编程》后,准备拿源码练练手时,执行第一个myls就出现一大堆的错误,这未免时个不小的打击。今天把解决方法写下来,第一自己有个记录,第二也帮助那些被同样问题困扰的朋友尽快的进入linux美丽的世界。(只限linux系统) 首先需要make一次源代码
编辑源码解压生成的apue.2e文件夹下的Make.defines.linux
修改WKDIR=/home/var/apue.2e为你的apue.2e目录,比如我的apue源码解压在/usr/local,那我就改为:
WKDIR=/usr/local/apue.2e
然后进入apue.2e/std 目录,编辑linux.mk。修改里面所有的nawk为awk。 最后返回apue.2e目录,执行make命令。
在我的机器上编译时,提示ARG_MAX未定义,可以这么修改。 在apue.2e/include/apue.h中添加一行: #define ARG_MAX 4096
打开apue.2e/threadtl/getenv1.c 和apue.2e/threadctl/getenv3.c,添加一行: #include \
把头文件apue.h放到/usr/include/中,
1. cp ~/apue.2e/include/apue.h /usr/include
复制代码
改源码包中的Make.defines.linux,make一下就在源码目录/lib中生成了libapue.a共享
库了,将它放到/usr/lib中,这样就可以方便调用了。
1. cp ~/apue.2e/lib/libapue.a /usr/lib
复制代码
编译一个例子看看:
1. gcc ls1.c -o ls1 -lapue
复制代码
搞定!
以下是编译源码时的错误提示跟解决方法(假定你的工作目录跟我的一样,为/usr/local/apue.2e)
错误提示1:
myls.c:1:19: apue.h: No such file or directory myls.c: In function `main':
myls.c:13: error: `NULL' undeclared (first use in this function) myls.c:13: error: (Each undeclared identifier is reported only once myls.c:13: error: for each function it appears in.) 解决办法:
拷贝apue.h到系统默认头文件目录中
$cp /usr/local/apue.2e/include/apue.h /usr/include 错误提示2:
/tmp/ccBBopm0.o(.text+0x2b): In function `main': : undefined reference to `err_quit'
/tmp/ccBBopm0.o(.text+0x5f): In function `main': : undefined reference to `err_sys' collect2: ld returned 1 exit status 解决办法:
err_quit跟err_sys是作者自己定义的错误处理函数,需要单独定义头文件
在/usr/include 下新建一个名为myerr.h的文件,拷贝在原书的附录B中头文件到其中。
《UNIX环境高级编程》源码编译方法
这里要谈到的一个问题就是该书中的源代码编译的问题。此书中差不多每个历程中,都会有这样一行源码:
#include \
在第二版中改为: #include \
这个头文件是作者把把每个例程中常用的标准头文件,一些常用的出错处理函数(err_**()之类的函数)和一些常用的宏定义给整理在一个头文件中。这个可以省去在每个例程中录入较多的重复代码,这样可以减少每个例程的长度。但是,这样就给读者带来了不少麻烦。因为我们还要去搞明白如和把这个头文件编译,然后做成库文件,添加到我们的系统中。特别读于初学者,本来满怀信心的,结果在编译第一个程序的时候就出现了问题。我也没有搞明白如何把 \静态的编译到系统中。
不过,不明白如何使用\这个头文件,并不会影响我们学习APUE,也不会影响我们编译和运行每一个例程。其实,简单的想一下,如果一个 C程序要能顺利的编译和运行,除了我们要语法正确等方面外,最根本的是要保证我们程序中所调用的函数以及宏等等都要有完整的来源,也就是必须包含所有调用函数和宏所在的头文件。对于一个具体的源程序,如果我们正确的包含了头文件,那么剩下的就是程序本生语法方面应该注意的事项。
如何确定系统调用函数包含在那个头文件中呢?这在Unix/Linux系统下并非一件难事。Unix/Linux下命令man可以帮助我们找到。man命令不仅可以帮助我们查找一般命令的用法,
同时提供不同层次的帮助诸如系统调用或者管理员级别的命令等等(譬如FreeBSD6.1中,man 1是用户专用手册,man 2是系统调用,man 3是库函数查询等等)。
下面我们就以APUE书中程序1-1 (实现ls命令部分功能)为例,来说明如何将书中的程序改编成全部使用标准头文件的程序。其中,操作系统用的是FreeBSD6.1,经过相应的修改可以在书中所说的几个Unix系统及Linux系统中运行,我也曾在Debian Linux下成功编译和运行该程序。书中1-1.c的原始代码如下:
#include
int
main(int argc, char *argv[]) {
DIR *dp; struct dirent *dirp;
if (argc != 2)
err_quit(\
if ((dp = opendir(argv[1])) == NULL) err_sys(\ while ((dirp = readdir(dp)) != NULL) printf(\
closedir(dp); exit(0); }
从书后面的附录中可以看到\的内容比较多,包含了比较多的常用头文件,一些宏定义和一些常用函数和出错函数的定义。其实,对于每一个具体的程序,我们只需要找到该程序中用到的头文件即可。
该1-1.c中所用到的系统函数调用有:opnedir(),readdir(),printf(),closedir()和exit()。
其中,对于常用的函数prinft()和exit(),它们所在的头文件一般都知道,分别是
其次,1-1.c中还用到了作者自定义的两个函数:err_quit()和err_sys()。这两个函数主要使用来进行出错处理的。当然,使用这两个函数对错误信息的处理是比较完善的。但是,作为我们学习来讲,了解程序的核心功能是首要的,我们可以将出错处理简化一点,即当遇到错