GNU make 總結 (一)


make的執行依賴於一個makefile文件,該文件告訴make應該如何執行編譯和鏈接操作。make通過比較對應文件的最后修改時間來決定哪些文件需要更新。make工具主要用來進行工程編譯和程序鏈接操作。當使用make時,工程中的如下幾種文件會被重新編譯:

  • 所有從未被編譯過的源文件
  • 執行make后,修改過的源文件
  • 執行make后,修改過頭文件,則包含該頭文件的源文件都需要重新編譯

 

2.1 makefile簡介

Target : Prerequisites

    command

    ...

    ...

Target: 目標

Prerequisites: 依賴

Command: 命令

一條規則可以有command,每個command占一行。command必須以Tab開頭。command用於在prerequisites改變后重建target。make程序根據規則的依賴關系來決定是否執行所定義的command,這個過程我們稱之為執行規則

可以使用\來斷行,但是\后邊不能有空格。

makefile文件中沒有依賴項而只有command的目標稱為“偽目標”。

執行make時,將執行第一個定義的target

注意:所有的command行都必須以Tab開始,但並不是所有以Tab開始的行都是command,make把出現在第一條規則之后的所有以Tab開始的行都作為command來處理

 

頭文件和源文件如下:

 1 // benxin.h
 2 void print_benxin();
 3 
 4 // benxin.c
 5 #include <stdio.h>
 6 
 7 void print_benxin()
 8 {
 9         printf("benxin ");
10 }
11 
12 // tuzi.h
13 void print_tuzi();
14 
15 // tuzi.c
16 #include <stdio.h>
17 
18 void print_tuzi()
19 {
20         printf("tuzi !\n");
21 }
 1 // makefile
 2 main : main.o \
 3         benxin.o tuzi.o
 4   gcc -o main main.o benxin.o tuzi.o
 5 main.o : main.c benxin.h tuzi.h
 6   gcc -c main.c
 7 benxin.o : benxin.c benxin.h
 8   gcc -c benxin.c
 9 tuzi.o : tuzi.c tuzi.h
10   gcc -c tuzi.c
11 clean : 12   rm main main.o benxin.o tuzi.o

執行:make

 

執行:./main

 

2.2 指定變量

可以指定一個變量表示所有的文件列表,如下:

OBJECTS = main.o benxin.o \

tuzi.o \

使用變量:

main : $(OBJECTS)

    gcc –o main $(OBJECTS)

clean :

    rm main $(OBJECTS)

 

2.3 Makefile組成

makefile文件中可能包含以下5個內容:顯式規則、隱式規則、變量定義、提示符、注釋。

  • 顯式規則:規則中明確指定目標文件、依賴文件列表、更新目標所需的命令。
  • 隱式規則:make程序根據目標文件名自動產生目標依賴文件列表,並使用默認的命令更新目標。
  • 變量定義:定義一個變量表示一系列文件列表。
  • 指示符:包含文件、條件執行、多行定義。
    • 包含文件:include ----->  一個makefile文件中可以使用include包含另一個makefile文件中的內容,其告訴make程序,暫停執行當前makefile,而先去include指定的makefile,然后繼續執行。書寫include時獨立占據一行,但是不能以Tab鍵開始,格式如下:include FILENAMES...其中,FILENAMES是shell所支持的文件名,可以使用通配符表示。如果被include的文件中存在變量或者函數,那么將會在包含它們的makefile中被展開。
    • include的應用:

      <1> 多個不同目錄下的makefile文件都使用一組同樣的變量或者模式規則,此時可以將這些共性的內容定義在一個文件中,然后在不同的makefile文件中include該文件。

      <2> 當根據源文件自動產生依賴時,可以將這些依賴關系保存到一個特定的文件中,然后在makefile文件中include這個特定的文件,這樣可以減少錯誤。

  • 注釋:用#表示注釋,因此如果需要在makefile的非注釋行中使用#時,需要加上轉義字符\,表示為”\#”。

 

2.4 makefile文件的指定規則

make程序默認會執行名為makefile或者Makefile的文件。否則需要通過-f或者—file選項來指定makefile文件,具體格式為:-f FILENAME或者—file=FILENAME。當然,也可以直接指定make的目標,只要當前文件夾下存在該目標的依賴文件列表即可。

 

2.5 MAKEFILES

如果當前環境中定義了MAKEFILES變量,那么make程序執行時,首先將此變量的值作為需要讀入的makefile文件。但是區別如下:

MAKEFILES變量指定的makefile文件中的“目標”不會被當作make執行的“終極目標”。

MAKEFILES變量指定的文件列表中的文件是否存在,make都不會提示錯誤。

make程序執行時,首先讀取MAKEFILES變量,然后才是當前工作目錄下的makefile文件。

 

2.6 MAKEFILE_LIST

make程序在讀取多個makefile文件時,比如,MAKEFILES變量、命令行、makefile、include等,在對這些文件進行解析之前,make讀取到的文件名會被自動加到MAKEFILE_LIST中。如此,我們可以通過判斷MAKEFILE_LIST變量的最后一塊內容來獲取當前make程序正在處理的makefile文件名。

 

2.7 特殊變量.VARIABLE

make包含一個特殊的變量,不能通過任何途徑給它賦值,其被展開后是makefile文件中當前點之前的所有全局變量列表,包括:空變量和make的內嵌變量。

 

2.8 makefile文件的重載

如果兩個makefile文件中擁有相同的目標,但是依賴與規則卻不同,此時使用include命令顯然行不通。此時需要使用“所有匹配模式 %”。%可以匹配任何一個目標,其依賴項假設為force,而force卻使用空命令。這是為了防止make程序試圖尋找一個規則去創建目標force時,又使用到% : force,這樣就陷入死循環了。

 

2.9 make解析makefile

<1>依次讀取變量MAKEFILES定義的makefile文件列表

<2> 讀取當前目錄中的makefile文件

<3> 讀取當前目錄makefile文件中使用的include包含的文件

<4> 查找重建所有已讀取的makefile文件的規則

<5> 初始化變量值並展開那些需要立即展開的變量和函數,同時根據預設條件確定執行分支

<6> 根據“終極目標”以及其他目標的依賴關系建立依賴關系鏈表

<7> 執行除“終極目標”以外的所有的目標規則

<8> 執行“終極目標”更新規則

 

附注知識點:

編譯:

將高級語言程序轉換為機器碼的過程,結果為中間目標文件,linux中以后綴名.o標識目標文件。

鏈接:

 

將多個.o文件以及庫文件鏈接稱為可執行文件。鏈接器並不檢查函數所在的源文件,只檢查.o文件中定義的符號,將.o文件中使用的函數和庫文件中的函數進行合並,然后對合並后的符號重新排序,並鏈接上系統相關文件,最終生成可執行程序,Linux中的可執行程序為ELF格式。

靜態庫:

 

又名歸檔文件,其是多個.o文件的集合,庫中不同的.o文件之間沒有特殊的關系。Linux中靜態庫后綴名為.a,使用工具ar管理。

共享庫:

 

也是多個.o文件的集合,但是這些.o文件是由編譯器按照某種特殊方式生成的。Linux中,共享庫格式通常為ELF,即該類型庫具備可執行條件。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM