最近在读 Richard Stevens 的大作《UNIX环境高级编程》,相信很多初读此书的人都会与我一样遇到这个问题,编译书中的程序实例时会出现问题,提示 “错误:apue.h:没有那个文件或目录”。

apue.h 是作者自定义的一个头文件,并不是Unix/Linux系统自带的,此头文件包括了Unix程序所需的常用头文件及作者Richard自己写的出错处理函数。所以在默认情况下,gcc在编译时是读不到这个头文件的。

先在这个网站 http://www.apuebook.com/src.tar.gz 下载tar.gz格式的源码包,然后解压至某个目录,比如说/home/godsoul/下,然后进入目录apue.2e。

1 把文件 Make.defines.linux 中的 WKDIR=/home/xxx/apue.2e 修改为 WKDIR=/home/godsoul/apue.2e

2 然后再进入apue.2e目录下的std目录,打开linux.mk,将里面的nawk全部替换为awk,如果是用的vi/vim编辑器,可以使用这个 命令  :1.$s/nawk/awk/g (注意前面有冒号)

3 回到apue.2e目录,然后在此目录下运行make命令,即回到 /home/godsoul/apue.2e 目录在终端中输入 “./make” (不含引号)

可能遇到的问题如下:

如果出现stropts.h找不到的情况,则下载glibc-2.11,http://ftp.gnu.org/gnu/glibc/glibc-2.11.tar.gz解压缩tar -zxvf glibc-2.11.tar.gz
cp ./glibc-2.11/streams/stropts.h /usr/include
cp ./glibc-2.11/bits/stropts.h /usr/include/bits
cp ./glibc-2.11/sysdeps/x86_64/bits/xtitypes.h /usr/include/bits

接着 make,又会出现

在我的机器上编译时,提示ARG_MAX未定义,可以这么修改。
在apue.2e/include/apue.h中添加一行:
#define ARG_MAX 4096
打开apue.2e/threadctl/getenv1.c和apue.2e/threadctl/getenv3.c,添加一行:
#include “apue.h”

改好了,继续make,这时能通过编译了

4 然后把 /home/godsoul/apue.2e/inlcude 目录下的 apue.h 文件和位于 /home/godsoul/apue.2e/lib 目录下的 error.c 文件都复制到 /usr/include 目录下,apue.2e/lib/libapue.a 到/usr/lib/和 /usr/lib64下。注意复制这文件你需要有root权限。之所以要这样做,是因为gcc在链接头文件时会到 /usr/include 这个目录下寻找需要的头文件,若找不到则报错

5 最终还要编辑一下复制过来的 apue.h 文件
在最后一行 #endif 前面添加一行 #include “error.c”

例子如下:

使用apue.h文件和libapue.a库。

假定/tmp下有一个文件:threadid.c,内容如下(apue线程章节的例子):
#include <apue.h>
#include <pthread.h>

pthread_t ntid;

void
printids(const char *s)
{
pid_t           pid;
pthread_t       tid;

pid = getpid();
tid = pthread_self();
printf(“%s pid %u tid %u (0x%x)\n”, s, (unsigned int)pid,
(unsigned int)tid, (unsigned int)tid);
}

void *
thr_fn(void *arg)
{
printids(“new thread: “);
return((void *)0);
}

int
main(void)
{
int            err;

err = pthread_create(&ntid, NULL, thr_fn, NULL);
if (err != 0)
err_quit(“can’t create thread: %s\n”, strerror(err));
printids(“main thread:”);
sleep(1);
exit(0);
}

使用如下命令编译:
cc -o threadid threadid.c -lapue -lpthread
可以运行一下:
dan@dan-laptop:/tmp$ ./threadid
new thread:  pid 17490 tid 816015696 (0x30a36950)
main thread: pid 17490 tid 823949040 (0x311c76f0)

配置unp的环境如下:

3. 编译《UNP》
这个稍微麻烦些。

http://www.unpbook.com/unpv13e.tar.gz

我们首先产生一个目录,以后自己的代码就敲在这个目录里。
mkdir /home/dan/study/unp

仍然是下载到/home/dan/download/,解压缩,进入目录
cd /home/dan/download/unpv13e/
README文件中说的很详细:
========================================
Execute the following from the src/ directory:

./configure    # try to figure out all implementationdifferences

cd lib         # build the basiclibrary that all programs need
make           # use “gmake”everywhere on BSD/OS systems

cd ../libfree  # continue building the basic library
make

cd ../libroute # only if your system supports 4.4BSD style routing sockets
make           # only if yoursystem supports 4.4BSD style routing sockets

cd ../libxti   # only if your system supports XTI
make           # only if yoursystem supports XTI

cd ../intro    # build and test a basic client program
make daytimetcpcli
========================================
这里只编译lib下的文件,这样可以产生libunp.a,复制这个静态库到/usr/lib/和/usr/lib64/
如果提示:
unp.h:139: error: conflicting types for ‘socklen_t’
/usr/include/bits/socket.h:35: error: previous declaration of ‘socklen_t’ was here
需要注释掉当前目录中unp.h的第139行。
复制libunp.a到系统目录:
root@dan-laptop:/home/dan/download/unpv13e/lib# cp ../libunp.a /usr/lib
root@dan-laptop:/home/dan/download/unpv13e/lib# cp ../libunp.a /usr/lib64/

4.使用unp.h和libunp.a
如果直接复制unpv13e/lib/unp.h到/usr/include,那么在别的目录编译书上代码时,很可会得到类似下面的错误:
In file included from daytimetcpsrv1.c:1:
/usr/include/unp.h:227: error: redefinition of ‘struct sockaddr_storage’
In file included from daytimetcpsrv1.c:1:
/usr/include/unp.h:249:30: error: ../lib/addrinfo.h: No such file or directory
/usr/include/unp.h:263: error: redefinition of ‘struct timespec’
/usr/include/unp.h:363: error: conflicting types for ‘gai_strerror’
/usr/include/netdb.h:647: error: previous declaration of ‘gai_strerror’ washere
/usr/include/unp.h:367: error: conflicting types for ‘getnameinfo’
/usr/include/netdb.h:653: error: previous declaration of ‘getnameinfo’ was here
/usr/include/unp.h:371: error: conflicting types for ‘gethostname’
/usr/include/unistd.h:857: error: previous declaration of ‘gethostname’ washere
/usr/include/unp.h:387: error: conflicting types for ‘inet_ntop’
/usr/include/arpa/inet.h:65: error: previous declaration of ‘inet_ntop’ washere
/usr/include/unp.h:395: error: conflicting types for ‘pselect’
/usr/include/sys/select.h:121: error: previous declaration of ‘pselect’ washere
daytimetcpsrv1.c: In function ‘main’:
daytimetcpsrv1.c:9: error: ‘MAX_LINE’ undeclared (first use in this function)
daytimetcpsrv1.c:9: error: (Each undeclared identifier is reported only once
daytimetcpsrv1.c:9: error: for each function it appears in.)
dan@dan-laptop:~/study/unp/4$ rm -f /usr/include/unp.h
解决方法有点傻:
进入我们开始时建立的目录:
cd /home/dan/study/unp
复制config.h和unp.h到此目录:
dan@dan-laptop:~/study/unp$ cp /home/dan/download/unpv13e/config.h .
dan@dan-laptop:~/study/unp$ cp /home/dan/download/unpv13e/lib/unp.h .
修改unp.h,
#include “../config.h”改成 #include “config.h”
添加一行:
#define MAX_LINE 2048
练习书上代码时,在unp目录下建立相应的章节目录,文件中添加一行:
#include “../unp.h”
编译时链接unp库就可以了。

以第四章的daytimetcpsrv1.c为例:
dan@dan-laptop:~/study/unp/4$ pwd
/home/dan/study/unp/4
dan@dan-laptop:~/study/unp/4$ cat daytimetcpsrv1.c
#include “../unp.h”
#include <time.h>

int main(int argc, char **argv)
{
int    listenfd, connfd;
socklen_t    len;
struct sockaddr_in    servaddr, cliaddr;
char    buff[MAX_LINE];
time_t    ticks;

listenfd = Socket(AF_INET, SOCK_STREAM, 0);

bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(13);

Bind(listenfd, (SA *)&servaddr, sizeof(servaddr));

Listen(listenfd, LISTENQ);

for (;;) {
len = sizeof(cliaddr);
connfd = Accept(listenfd, (SA *)&cliaddr, &len);
printf(“connection from %s, port %d\n”,
Inet_ntop(AF_INET, &cliaddr.sin_addr, buff, sizeof(buff)),
ntohs(cliaddr.sin_port));

ticks = time(NULL);
snprintf(buff, sizeof(buff), “%.24s\r\n”, ctime(&ticks));
Write(connfd, buff, strlen(buff));

Close(connfd);
}
}
编译:
cc -o daytimetcpsrv1 daytimetcpsrv1.c -lunp
运行一下:
root@dan-laptop:/home/dan/study/unp/4# ./daytimetcpsrv1 &
[1] 22106
root@dan-laptop:/home/dan/study/unp/4#
root@dan-laptop:/home/dan/study/unp/4# ./daytimetcpcli
usage: a.out <IPaddress>
root@dan-laptop:/home/dan/study/unp/4# ./daytimetcpcli 127.0.0.1
connection from 127.0.0.1, port 42064
Fri Aug 21 23:03:56 2009
root@dan-laptop:/home/dan/study/unp/4# netstat -nt
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q LocalAddress           ForeignAddress         State
tcp        0      0127.0.0.1:13           127.0.0.1:42064         TIME_WAIT

apue2e unp安装的更多相关文章

  1. 《UNIX网络编程(第3版)》unp.h等源码文件的编译安装

    操作系统:Mac OS X 10.11.5 1.下载书中的源代码:点击下载 2.切换到解压后的目录 unpv13e,先查看下 README,依次执行: ./configure cd lib make ...

  2. UNP环境配置

    最近在学习<UNIX网络编程>,书上将常用的头文件都放在unp.h里,需要自己编译一下代码搭建环境. UNP环境配置过程 下载源码 http://www.unpbook.com/src.h ...

  3. Unix NetWork Programming(unix环境编程)——环境搭建(解决unp.h等源码编译问题)

    此配置实例亲测成功,共勉,有问题大家留言. 环境:VMware 10 + unbuntu 14.04 为了unix进行网络编程,编程第一个unix程序时遇到的问题,不能包含unp.h文件,这个感觉和a ...

  4. 【转】Unix NetWork Programming——环境搭建(解决unp.h等源码编译问题)

    下面开始用简单但典型的客户端和服务器端程序说明如何进行网络编程.这一小节讲的是客户端,一个用来连接并读取服务器发送来的时间的客户端. 这里涉及到了编写代码,因此要 搭建unix网络编程环境 unix系 ...

  5. Unix网络编程 -- ubuntu下搭建编译环境( 解决unp.h 编译等问题)

    1.安装编译器,安装build-essential sudo apt-get install build-essential 2.下载本书的头文件 下载unpv13e  http://ishare.i ...

  6. Maven-002-eclipse 插件安装及实例

    因为平常编码的时候,习惯了使用 eclipse 进行编码,因而需要将 eclipse 安装 maven 的插件,安装步骤如下所示: 一.安装 选择菜单: help -> Install New  ...

  7. nodejs安装及npm模块插件安装路径配置

    在学习完js后,我们就要进入nodejs的学习,因此就必须配置nodejs和npm的属性了. 我相信,个别人在安装时会遇到这样那样的问题,看着同学都已装好,难免会焦虑起来.于是就开始上网查找解决方案, ...

  8. UNP学习笔记(第六章 I/O复用)

    I/O模型 首先我们将查看UNIX下可用的5种I/O模型的基本区别: 1.阻塞式I/O 2.非阻塞式I/O 3.I/O复用(select和poll) 4.信号驱动式I/O(SIGIO) 5.异步I/O ...

  9. 16.unix网络编程一卷 unp.h

    unix网络编程 --ubuntu下建立编译环境 1.安装编译器,安装build-essential sudo apt-get install build-essential 2.下载本书的头文件 下 ...

随机推荐

  1. 转:php中判断某个IP地址是否存在范围内

    原文:php中判断某个IP地址是否存在范围内 //案例:判断192.168.1.127是否在 (192.168.1.1--192.168.1.255)的范围里面 $ip_start = get_ipl ...

  2. 分享到xxx

    来源百度 一.概述 百度分享代码已升级到2.0,本页将介绍新版百度分享的安装配置方法,请点击左侧列表查看相关章节. 二.代码结构 分享代码可以分为三个部分:HTML.设置和js加载,示例如下: 代码结 ...

  3. Android设置日期DatePickerDialog

    设置日期DatePickerDialog package com.example.testview; import java.util.Calendar; import java.util.Date; ...

  4. python中的字符串编码问题——3.各操作系统下的不同编码方式

    各操作系统下的不同编码方式  先看一下 linux,python2.7 >>> B = b'\xc3\x84\xc3\xa8' >>> B.decode('utf- ...

  5. 回归JavaScript基础(二)

    主题:在HTML中使用JavaScript. 要想把JavaScript放到网页中,就必须涉及到Web的核心语言HTML.向HTML页面中插入JavaScript的主要方法,就是使用<scrip ...

  6. LeetCode 题解之Plus One

    1.题目描述 2.题目分析 从后向前做加法,等于10则进位,否则直接加1 ,返回 digits; 3.代码 vector<int> plusOne(vector<int>&am ...

  7. HBase 负载均衡

    HBase 可以根据当前集群的负载以region为单位进行rebalance.在HMaster中,后台会起一个线程定期检查是否需要进行rebalance,线程叫做BalancerChore.线程每隔  ...

  8. RHEL7: How to configure a rc-local service

    问题: linux7 /etc/rc.local 不生效: [root@bogon mysql3306]# uname -aLinux bogon 3.10.0-862.el7.x86_64 #1 S ...

  9. Django的model中创建表

    类中的class Meta字段的作用: 第一个作用可以给这个类起名字 在后台的admin中显示这个类名字 class CourseCategory(models.Model): "" ...

  10. 使用 Versions for mac 进行版本控制

    刚开始折腾 xcode 5.1 自己的svn版本控制,应该很好用,但是用不好,搞了半天也没法把工程传到svn服务器上去. 在 xcode 5.1 Soure Control 中弄 点击 Check O ...