APUE在Mac OSX 10.7如何編譯

這篇是給自己看的筆記,算是完結以前未完成的功課。大學是唸管院的,研究所到交大,發現有很多課程的老師太有高度,自己有很多跟不上的,其中一個課程老師建議的補充教材就是這本APUE(W. Richard Stevens, Advanced Programming in the UNIX Environment, 1992)。在大學之前都是玩DOS,研一只有計算機中心給的一個帳號,可以連入工作站使用,但是什麼權限都沒有,玩沒多久很快就覺得沒意思。那個時代不像現在有Ubuntu, 有建立在BSD Darwin的Mac OSX, 有FreeBSD等可以上手玩,比較流行的是Sun Solaris。那個時候一台最最便宜的Sun工作站也要二十萬台幣,所上某些實驗室有,可惜不是我熟識的學長。總之,我有很多藉口,可以解釋當時為什麼那門課修得這麼差。
只是我還是想把這些缺口給修補起來。反而造成我日後走入這個行業,但是轉來轉去,最近才有機會又碰到UNIX-like的環境,又去把這本書拿出來看。

第一個重點,我知道這本書很老了,至少有出第二版。但因為我手上是1992年的初版(當時做學生時,花了一千多台幣買的)當然要善用現有資源。有意思的是,書上所提供source code的ftp site, 現在當然是不存在了。不過,現在我們有google可以用,只要輸入stevens.advprog.tar.z就可以找到很多mirror download site.

第二個重點,在網路上有看到第二版好像已經有針對Mac OSX有編譯設定,但是初版是沒有的。但我想Mac OSX的底層是一個BSD的版本,所以就用bsd的編譯方式來修改。

解開stevens.advprog.tar.z後,看到很多目錄和一些檔案,很好有一個README檔。
README說,第一件事就是要把Make.def.xxx的其中一個做成Make.defines,那就先試著用$ cp Make.def.44 Make.defines做完這件事。
接著我看到有三個目錄叫做lib.xxx,正好也對應到Make.def.xxx的三個UNIX版本,所以我就使用其中的lib.44來編譯程式庫。
$ cd lib.44
$more Makefile
發現Makefile使用systype.sh來找系統種類,但是手動跑systype.sh沒有跑出結果,所以我直接把Makefile裡的all:後的gmake `systype.sh' 改成make bsd,同時bsd:後的gmake也改成make
再試著編譯:


$ make
make bsd
make "CFLAGS = -O" \
"OBJS = bufargs.o cliconn.o clrfl.o daemoninit.o error.o errorlog.o lockreg.o locktest.o openmax.o pathalloc.o pathconf.o popen.o prexit.o prmask.o ptyfork.o ptyopen.o readn.o recvfd.o senderr.o sendfd.o servaccept.o servlisten.o setfl.o signal.o signalintr.o sleep.o sleepus.o spipe.o strerror.o sysconf.o tellwait.o ttymodes.o writen.o " "RANLIB = ranlib" lib
gcc -O  -c -o bufargs.o bufargs.c
gcc -O  -c -o cliconn.o cliconn.c
gcc -O  -c -o clrfl.o clrfl.c
gcc -O  -c -o daemoninit.o daemoninit.c
gcc -O  -c -o error.o error.c
gcc -O  -c -o errorlog.o errorlog.c
errorlog.c: In function ‘log_doit’:
errorlog.c:97: warning: format not a string literal and no format arguments
gcc -O  -c -o lockreg.o lockreg.c
gcc -O  -c -o locktest.o locktest.c
gcc -O  -c -o openmax.o openmax.c
gcc -O  -c -o pathalloc.o pathalloc.c
gcc -O  -c -o pathconf.o pathconf.c
gcc -O  -c -o popen.o popen.c
gcc -O  -c -o prexit.o prexit.c
gcc -O  -c -o prmask.o prmask.c
gcc -O  -c -o ptyfork.o ptyfork.c
gcc -O  -c -o ptyopen.o ptyopen.c
gcc -O  -c -o readn.o readn.c
gcc -O  -c -o recvfd.o recvfd.c
gcc -O  -c -o senderr.o senderr.c
gcc -O  -c -o sendfd.o sendfd.c
gcc -O  -c -o servaccept.o servaccept.c
gcc -O  -c -o servlisten.o servlisten.c
gcc -O  -c -o setfl.o setfl.c
gcc -O  -c -o signal.o signal.c
gcc -O  -c -o signalintr.o signalintr.c
gcc -O  -c -o sleep.o sleep.c
sleep.c: In function ‘sleep’:
sleep.c:18: warning: assignment from incompatible pointer type
gcc -O  -c -o sleepus.o sleepus.c
gcc -O  -c -o spipe.o spipe.c
gcc -O  -c -o strerror.o strerror.c
strerror.c:3: error: conflicting types for ‘sys_errlist’
/usr/include/stdio.h:460: error: previous declaration of ‘sys_errlist’ was here
strerror.c:4: error: conflicting type qualifiers for ‘sys_nerr’
/usr/include/stdio.h:459: error: previous declaration of ‘sys_nerr’ was here
make[2]: *** [strerror.o] Error 1
make[1]: *** [bsd] Error 2
make: *** [all] Error 2


果然可以編了,但是有錯誤,沒有完全成功!看一下問題在那裡,發現是strerror.c有兩個變數的宣告和stdio.h有衝突。此時想到strerror應該是處理系統錯誤的內建function,所以再去改Makefile, 將strerror.c由編譯程序中移除。再重編一次:


$ make
make bsd
make "CFLAGS = -O" \
"OBJS = bufargs.o cliconn.o clrfl.o daemoninit.o error.o errorlog.o lockreg.o locktest.o openmax.o pathalloc.o pathconf.o popen.o prexit.o prmask.o ptyfork.o ptyopen.o readn.o recvfd.o senderr.o sendfd.o servaccept.o servlisten.o setfl.o signal.o signalintr.o sleep.o sleepus.o spipe.o strerror.o sysconf.o tellwait.o ttymodes.o writen.o " "RANLIB = ranlib" lib
gcc -O  -c -o sysconf.o sysconf.c
gcc -O  -c -o tellwait.o tellwait.c
gcc -O  -c -o ttymodes.o ttymodes.c
gcc -O  -c -o writen.o writen.c
ar rv ../libmisc.a bufargs.o cliconn.o clrfl.o daemoninit.o error.o errorlog.o lockreg.o locktest.o openmax.o pathalloc.o pathconf.o popen.o prexit.o prmask.o ptyfork.o ptyopen.o readn.o recvfd.o senderr.o sendfd.o servaccept.o servlisten.o setfl.o signal.o signalintr.o sleep.o sleepus.o spipe.o strerror.o sysconf.o tellwait.o ttymodes.o writen.o
ar: creating archive ../libmisc.a
a - bufargs.o
a - cliconn.o
a - clrfl.o
a - daemoninit.o
a - error.o
a - errorlog.o
a - lockreg.o
a - locktest.o
a - openmax.o
a - pathalloc.o
a - pathconf.o
a - popen.o
a - prexit.o
a - prmask.o
a - ptyfork.o
a - ptyopen.o
a - readn.o
a - recvfd.o
a - senderr.o
a - sendfd.o
a - servaccept.o
a - servlisten.o
a - setfl.o
a - signal.o
a - signalintr.o
a - sleep.o
a - sleepus.o
a - spipe.o
a - strerror.o
ar: strerror.o: No such file or directory
a - sysconf.o
a - tellwait.o
a - ttymodes.o
a - writen.o
make[2]: *** [lib] Error 1
make[1]: *** [bsd] Error 2
make: *** [all] Error 2

$ make
make bsd
make "CFLAGS = -O" \
"OBJS = bufargs.o cliconn.o clrfl.o daemoninit.o error.o errorlog.o lockreg.o locktest.o openmax.o pathalloc.o pathconf.o popen.o prexit.o prmask.o ptyfork.o ptyopen.o readn.o recvfd.o senderr.o sendfd.o servaccept.o servlisten.o setfl.o signal.o signalintr.o sleep.o sleepus.o spipe.o sysconf.o tellwait.o ttymodes.o writen.o " "RANLIB = ranlib" lib
ar rv ../libmisc.a bufargs.o cliconn.o clrfl.o daemoninit.o error.o errorlog.o lockreg.o locktest.o openmax.o pathalloc.o pathconf.o popen.o prexit.o prmask.o ptyfork.o ptyopen.o readn.o recvfd.o senderr.o sendfd.o servaccept.o servlisten.o setfl.o signal.o signalintr.o sleep.o sleepus.o spipe.o sysconf.o tellwait.o ttymodes.o writen.o
r - bufargs.o
r - cliconn.o
r - clrfl.o
r - daemoninit.o
r - error.o
r - errorlog.o
r - lockreg.o
r - locktest.o
r - openmax.o
r - pathalloc.o
r - pathconf.o
r - popen.o
r - prexit.o
r - prmask.o
r - ptyfork.o
r - ptyopen.o
r - readn.o
r - recvfd.o
r - senderr.o
r - sendfd.o
r - servaccept.o
r - servlisten.o
r - setfl.o
r - signal.o
r - signalintr.o
r - sleep.o
r - sleepus.o
r - spipe.o
r - sysconf.o
r - tellwait.o
r - ttymodes.o
r - writen.o
ranlib ../libmisc.a

成功了,我得到libmisc.a這個程式庫了。

要試一下能不能用:
先找第一個範例程式file/ls1.c來編編看:
$ cd file
$ gcc ls1.c -L.. -lmisc
./a.out
a single argument (the directory name) is required
$ ./a.out /dev
.
..
console
tty
null
zero
klog
fd
stdin
stdout
stderr

$ ./a.out hello.c
can't open hello.c: Not a directory

沒錯,程式執行結果都正確。



留言

這個網誌中的熱門文章

D-BUS學習筆記

關於藍牙裝置找尋(inquiry, scan)兩三事

Cisco Switch學習筆記: EtherChannel