main.c, mytool1.h, mytool1.c, mytool2.h, mytool2.c函數
咱們能夠這樣來編譯:學習
gcc -c main.cspa
gcc -c mytool1.c線程
gcc -c mytool2.c調試
gcc -o main main.o mytool1.o mytool2.ocomponent
Makefile文件中最重要的是描述文件的依賴關係的說明,其通常的格式爲:對象
target: components文檔
TAB ruleget
第一行表示的是依賴關係,第二行是規則。編譯器
例如上面那個Makefile文件的第二行:main: main.o mytool1.o mytool2.o,表示咱們的目標(target)main的依賴對象(components)是main.o mytool1.o mytool2.o
當依賴的對象在目標修改後修改的話,就要去執行規則行所指定的命令。
例如上面那個Makefile文件的第三行:gcc -o main main.o mytool1.o mytool2.o
注意:規則行中的TAB表示那裏是一個TAB 鍵。
3. Makefile的經常使用變量
Makefile 有三個很是有用的變量:$@,$^,$<。其意義爲:
$@:目標文件
$^:全部的依賴文件
$<:第一個依賴文件
若是使用上面三個變量,上面那個Makefile文件可簡化爲:
通過簡化後咱們的Makefile是簡單了一點,不過人們有時候還想簡單一點。這裏咱們學習一個Makefile的缺省規則
.c.o:
gcc -c $<
這個規則表示全部的 .o文件都是依賴與相應的.c文件的。例如mytool.o依賴於mytool.c這樣Makefile還能夠變爲:
# 這是再一次簡化後的Makefile
main:main.o mytool1.o mytool2.o
gcc -o $@ $^
.c.o:
gcc -c $<
好了,咱們的Makefile 也差很少了,若是想知道更多的關於Makefile規則能夠查看相應的文檔。
3.程序庫的連接
試着編譯下面這個程序
/* temp.c */
#include
int main(int argc,char **argv)
{
double value;
printf("Value:%f\n",value);
}
這個程序至關簡單,可是當咱們用 gcc -o temp temp.c 編譯時會出現下面所示的錯誤。
/tmp/cc33Kydu.o: In function `main':
/tmp/cc33Kydu.o(.text+0xe): undefined reference to `log'
collect2: ld returned 1 exit status
出現這個錯誤是由於編譯器找不到log的具體實現。雖然咱們包括了正確的頭文件,可是咱們在編譯的時候仍是要鏈接肯定的庫。在Linux下,爲了使用數學 函數,咱們必須和數學庫鏈接,爲此咱們要加入 -lm 選項。 gcc -o temp temp.c -lm這樣纔可以正確的編譯。也許有人要問,前面咱們用printf函數的時候怎麼沒有鏈接庫呢?是這樣的,對於一些經常使用的函數的實現,gcc編譯器會自 動去鏈接一些經常使用庫,這樣咱們就沒有必要本身去指定了。有時候咱們在編譯程序的時候還要指定庫的路徑,這個時候咱們要用到編譯器的 -L選項指定路徑。好比說咱們有一個庫在 /home/hoyt/mylib下,這樣咱們編譯的時候還要加上 -L/home/hoyt/mylib。對於一些標準庫來講,咱們沒有必要指出路徑。只要它們在起缺省庫的路徑下就能夠了。系統的缺省庫的路徑/lib /usr/lib /usr/local/lib 在這三個路徑下面的庫,咱們能夠不指定路徑。
還有一個問題,有時候咱們使用了某個函數,可是咱們不知道庫的名字,這個時候怎麼辦呢?很抱歉,對於這個問題我也不知道答案,我只有一個傻辦法。首先,我 到標準庫路徑下面去找看看有沒有和我用的函數相關的庫,我就這樣找到了線程(thread)函數的庫文件(libpthread.a)。 固然,若是找不到,只有一個笨方法。好比我要找sin這個函數所在的庫。 就只好用 nm -o /lib/*.so|grep sin>~/sin 命令,而後看~/sin文件,到那裏面去找了。在sin文件當中,我會找到這樣的一行libm-2.1.2.so:00009fa0 W sin 這樣我就知道了sin在 libm-2.1.2.so庫裏面,我用 -lm選項就能夠了(去掉前面的lib和後面的版本標誌,就剩下m了因此是 -lm)。 若是你知道怎麼找,請趕快告訴我,我回很是感激的。謝謝!
4.程序的調試
咱們編寫的程序不太可能一次性就會成功的,在咱們的程序當中,會出現許許多多咱們想不到的錯誤,這個時候咱們就要對咱們的程序進行調試了。
最經常使用的調試軟件是gdb.若是你想在圖形界面下調試程序,那麼你如今能夠選擇xxgdb.記得要在編譯的時候加入 -g選項.關於gdb的使用能夠看gdb的幫助文件。因爲我沒有用過這個軟件,因此我也不可以說出如何使用。不過我不喜歡用gdb.跟蹤一個程序是很煩的 事情,我通常用在程序當中輸出中間變量的值來調試程序的。固然你能夠選擇本身的辦法,沒有必要去學別人的。如今有了許多IDE環境,裏面已經本身帶了調試 器了。你能夠選擇幾個試一試找出本身喜歡的一個用。
5.頭文件和系統求助
有時候咱們只知道一個函數的大概形式,不記得確切的表達式,或者是不記得着函數在那個頭文件進行了說明。這個時候咱們能夠求助系統。
好比說咱們想知道fread這個函數的確切形式,咱們只要執行 man fread 系統就會輸出着函數的詳細解釋的。和這個函數所在的頭文件說明了。 若是咱們要write這個函數的說明,當咱們執行man write時,輸出的結果卻不是咱們所須要的。 由於咱們要的是write這個函數的說明,但是出來的倒是write這個命令的說明。爲了獲得write的函數說明咱們要用 man 2 write. 2表示咱們用的write這個函數是系統調用函數,還有一個咱們經常使用的是3表示函數是C的庫函數。
記住無論何時,man都是咱們的最好助手。