Unix 高級編程 環境配置(Centos + X86_64)

UNIX環境高級編程

最近在讀 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,把文件 Make.defines.linux 中的 WKDIR=/home/xxx/apue.2e 修改爲 WKDIR=/home/godsoul/apue.2e ,然後再進入apue.2e目錄下的std目錄,打開linux.mk,將裏面的nawk全部替換爲awk,如果是用的vi/vim編輯器,可以使用這個 命令  :1.$s/nawk/awk/g (注意前面有冒號)
然後在此目錄下運行make命令,即回到 /home/godsoul/apue.2e 目錄在終端中輸入 “./make” (不含引號)

然後把 /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 這個目錄下尋找需要的頭文件,若找不到則報錯。

最終還要編輯一下複製過來的 apue.h 文件
在最後一行 #endif 前面添加一行 #include “error.c”

然後進入apue.2e/std 目錄,編輯linux.mk。修改裏面所有的nawk爲awk。

這樣就不會報錯了。

還又可能遇到的問題如下:

如果出現stropts.h找不到的情況,則下載glibc-2.11,解壓縮
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

在我的機器上編譯時,提示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 clean再重新make

2. 使用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)

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 implementation differences

cd lib         # build the basic library 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 your system supports 4.4BSD style routing sockets

cd ../libxti   # only if your system supports XTI
make           # only if your system 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’ was here
/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’ was here
/usr/include/unp.h:387: error: conflicting types for ‘inet_ntop’
/usr/include/arpa/inet.h:65: error: previous declaration of ‘inet_ntop’ was here
/usr/include/unp.h:395: error: conflicting types for ‘pselect’
/usr/include/sys/select.h:121: error: previous declaration of ‘pselect’ was here
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 Local Address           Foreign Address         State
tcp        0      0 127.0.0.1:13            127.0.0.1:42064         TIME_WAIT


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章