如何本身編譯apue.3e中代碼 & 學習寫makefile

原本是搜pthread的相關資料,看blog發現不少linux程序員都看的一本神書《APUE》,裏面有系統的兩章內容專門講pthread(不過是用c語言作的代碼示例,這個不礙事,仍是歸到原來linux c++分類中了),決定把這本書打印出來,過一下這兩章內容。這個系列後面的日誌會根據APUE書中的內容來。html

 

這篇日誌說的內容與APUE沒有直接關係,可是倒是由APUE引起的。python

 

背景是這樣的linux

(1)對於我這個只在windows下用vs等IDE寫過一些c程序,不知道gcc是幹啥的人來講,在unix下搞c就有困難(這個感受有點兒相似於只學過開自動擋的汽車,一會兒讓你開手動擋了)。c++

(2)上來APUE的第一個demo就不能編譯經過,由於APUE的全部demo代碼中都包含一行include 「apue.h」。翻開/apue/include/apue.h看了一眼:都是一些宏定義和函數聲明,一些函數的具體實現都在/apue/lib/中了。這些東西怎麼整合起來?之前在windows下好像都是用IDE創建一個工程,剩下的都是IDE給作好了。可是如今用的mac,未來在公司要用的是Linux,學會在linux下開發c c++的工程項目是遲早的事情,躲不開。程序員

(3)若是是python這種腳本語言,只要有python解釋器就OK了;可是c語言這種強類型的語言的源代碼是如何變成可執行的二進制文件的?這個問題我也說不清楚。(非計算機科班出身,沒學過編譯原理shell

上面的三個問題,恐怕也是不少只在win下開發過程序的人遇到的問題,而我就是其中一員。下面記錄下解決上面困難的過程。macos

 

記錄一下遇到的各類問題,經過查閱資料和推理一點兒點兒摸索着解決了(純本身記錄,非小白可直接忽略,不敢浪費你們時間)ubuntu

(一)gcc -I(搞清楚include "..."windows

原書的demo中 第一行是include "apue.h",但本身意識到「apue.h」不在當前路徑下,應該把apue.h所在的路徑完整寫出來。 因而照貓畫虎的代碼以下:編輯器

#include "../apue.3e/include/apue.h"
#include <pthread.h>

void * thr_fn1(void *arg)
{
    printf(("thread 1 returning\n"));
    return ((void *)1);
}

void * thr_fn2(void *arg)
{
    printf(("thread 2 exiting"));
    pthread_exit((void *)2);
}

int main(int argc, char const *argv[])
{
    int err;
    pthread_t tid1, tid2;
    void *tret;
    err = pthread_create(&tid1, NULL, thr_fn1, NULL);
    err_exit(err, "can't");
    return 0;
}

但立刻以爲上述的代碼有問題:若是apue.h的路徑改了,那豈不是全部源代碼中的include 「apue.h」都要跟着改?這樣確定不科學。

因而查閱了一下gcc命令(http://blog.sina.com.cn/s/blog_57295811010008pj.html),知道了-I這個選項,能夠把include "..."包含的文件路徑放在-I後面。因而作了以下修改:

#include "apue.h"

並執行命令:gcc -I../apue.3e/include 11.3.c -pthread

獲得了以下結果:

報錯的內容就是說err_exit()這個函數找不到吧(這個時候不知道ld是什麼意思,linker是啥也不知道

因而推理一下:多是隻有apue.h頭文件,gcc的過程當中沒有找到實際函數實現吧。

去翻翻發現apue.h中有一句話:

void    err_exit(int, const char *, ...) __attribute__((noreturn));

這就是一句函數聲明。

那麼函數實體在哪裏呢?到這裏有點兒瞎,由於原書給的文件很大,那麼多的文件上哪找err_exit呢?

即便找到的err_exit()的函數定義,又怎麼讓包含err_exit()函數定義的這個文件與demo文件合在一塊兒呢?線索斷了。

(二)make命令以及Makefile (在unix下本身完成win下IDE完成的事情)

接着(一),瞎查了半天沒有什麼結果,糾結了一下子。

一個偶然的想法讓我在解決問題的路上去學了下make以及Makefile。

因爲書上的demo畢竟是在ubuntu上運行的,而個人電腦是mac系統,雖然說都是unix,可是會不會是個人系統有問題或者gcc版本這類的問題致使不能編譯經過呢?因而,我就想試試,能不能在APUE提供的源代碼目錄下編譯經過呢?

這時候,我找到了APUE提供的源碼文件夾中的Makefile文件,以下:

ROOT=..
EXTRALIBS=-pthread
PLATFORM=$(shell $(ROOT)/systype.sh)
include $(ROOT)/Make.defines.$(PLATFORM)

BAR =
ifeq "$(PLATFORM)" "macos"
  TLOCK =
  EXTRALIBS=-pthread
else
  TLOCK = timedlock
endif
ifeq "$(PLATFORM)" "linux"
  BAR = barrier
  EXTRALIBS=-pthread -lrt -lbsd
endif
ifeq "$(PLATFORM)" "freebsd"
  BAR = barrier
  EXTRALIBS=-pthread
endif
ifeq "$(PLATFORM)" "solaris"
  BAR = barrier
  EXTRALIBS=-lpthread -lrt
endif

PROGS = badexit2 cleanup exitstatus threadid

all:    $(PROGS) condvar.o maketimeout.o mutex1.o mutex2.o mutex3.o rwlock.o $(TLOCK) $(BAR)

$(PROGS):    $(LIBAPUE)
        $(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS) $(LDLIBS)

clean:
    rm -f $(PROGS) $(TEMPFILES) *.o $(TLOCK) $(BAR)

include $(ROOT)/Make.libapue.inc

以前據說過,Makefile貌似是告訴系統去怎麼編譯源代碼這類的。因而,上網搜了以下的資料,對make和Makefile進行了下突擊:

中文的blog:
youtube上的20分鐘視頻:
視頻中提到的能夠查閱的規範資料: http://www.gnu.org/software/make/manual/make.html
OK,看過上面的內容,我就試試在這個文件夾下直接make吧。獲得了下面的結果:
編譯經過了!而且運行了可執行文件,也與書中的結果同樣。
這就證實了,這個demo源代碼是能夠被正確編譯調試的,確定是我中間哪一個環節沒弄對。線索又續上了。
 
(三)gcc -L -l (連接的過程)
接着(二),上圖中執行make命令是對pthreads這一章全部demo的源代碼進行編譯了,我從中抽出來了關心的那一條:
gcc -ansi -I../include -Wall -DMACOS -D_DARWIN_C_SOURCE  threadid.c -o threadid  -L../lib -lapue -pthread

本身運行的命令照比make執行的命令主要少了紅字的那一塊。原來,是-L -l告訴了gcc,函數err_exit()的具體實如今哪裏的啊。

==================================================

插播:忽然想起來本身買過一本書《程序員的自我修養》,裏面講了編譯、連接什麼的。

因而趕忙讀了讀,搞清楚點兒。也是在那本書中,知道了「連接」是一個很重要的過程,把

不一樣模塊拼在一塊兒組成最後的完整的程序。

插播結束。

==================================================

-l後面接的「apue」應該是庫文件的名字(linux靜態庫文件通常以libXXX.a的形式,XXX就是-l後面跟着的名字),因而天然就想看看這個apue庫文件的樣子

(四)sublime的陷阱 (有些格式的文件,sublime不顯示

先找了下原書提供的代碼文件中的lib文件夾;果真,找到了err_exit()函數的實現文件:error.c

你們能夠看到,本人用的編輯器是sublime text2。爲何要提一下這個編輯器?後面立刻說,如何被編輯器的設置給坑了。

看看sublime左側邊欄中,lib文件夾下也沒有這樣的文件啊,難倒還有其餘的坑麼?到這裏又有些糾結了

(1)如今源文件所在目錄已經找到了

(2)也知道-L把外部的庫文件路徑告訴gcc,-l告訴gcc應該具體用哪一個庫文件

因而我在網上搜了一下(如這篇blog,http://www.cnblogs.com/showna/articles/1013399.html),庫文件確實都是lib開頭,.a .dylib結尾的這類啊。難倒庫文件在lib文件夾中丟了?仍是有其餘的說道?。

正在鬱悶的時候,用iTerm命令行進入了lib文件夾下面,忽然展示了驚人的一幕:

喵了個咪的,這個apue庫文件.a、編譯後的目標文件.o都有啊!原來只是sublime的左邊欄中沒有這些.o和.a文件啊。

因而,知道被sublime給坑了。很快上網搜到了緣由,在sublime的Preferences選中中有以下的幾行默認配置:

在sublime默認中,.a .o .lib這些擴展名的文件都不顯示啊!!!

 

到了這裏,終於把這一系列問題搞清楚了(這個過程大概持續了一白天),總結下緣由:

(1)對編輯器特性不熟悉(不知道有些文件還自動過濾了不顯示),這個只能靠實踐去磨了

(2)對於程序由源代碼到可執行文件的原理不瞭解。之前在windows平臺不少事情都VS作了,用Eclipse寫Java就更省事兒了;如今須要本身寫Makefile去作,就要把每一個環節都搞清楚。這個光靠實踐不行,還得去系統的學學,好比《程序員的自我修養》這本書就是很是好的內容。遂決定讀。

相關文章
相關標籤/搜索