Makefile入门(超详细一文读懂)
1、Makefile編譯過程
??Makefile文件中的命令有一定規(guī)范,一旦該文件編寫好以后在Linux命令行中執(zhí)行一條make命令即可自動編譯整個工程。不同廠家的make可能會稍有不同,并且語法上也有區(qū)別,不過基本思想都差不多,主要還是落在目標依賴上,最廣泛使用的是GNUmake。
2、語法規(guī)則
目標 ... : 依賴 ...命令1命令2. . .??Makefile的核心規(guī)則,類似于一位廚神做菜,目標就是做好一道菜,那么所謂的依賴就是各種食材,各種廚具等等,然后需要廚師好的技術方法類似于命令,才能作出一道好菜。
??同時這些依賴也有可能此時并不存在,需要現(xiàn)場制作,或者是由其他廚師做好,那么這個依賴就成為了其他規(guī)則的目標,該目標也會有他自己的依賴和命令。這樣就形成了一層一層遞歸依賴組成了Makefile文件。
??Makefile并不會關心命令是如何執(zhí)行的,僅僅只是會去執(zhí)行所有定義的命令,和我們平時直接輸入命令行是一樣的效果。
1、目標即要生成的文件。如果目標文件的更新時間晚于依賴文件更新時間,則說明依賴文件沒有改動,目標文件不需要重新編譯。否則會進行重新編譯并更新目標文件。
2、默認情況下Makefile的第一個目標為終極目標。
3、依賴:即目標文件由哪些文件生成。
4、命令:即通過執(zhí)行命令由依賴文件生成目標文件。注意每條命令之前必須有一個tab保持縮進,這是語法要求(會有一些編輯工具默認tab為4個空格,會造成Makefile語法錯誤)。
5、all:Makefile文件默認只生成第一個目標文件即完成編譯,但是我們可以通過all 指定所需要生成的目標文件。
3、變量
$符號表示取變量的值,當變量名多于一個字符時,使用"( )"
$符的其他用法
$^ 表示所有的依賴文件
$@ 表示生成的目標文件
$< 代表第一個依賴文件
4、變量賦值
??1、"="是最普通的等號,在Makefile中容易搞錯賦值等號,使用 “=”進行賦值,變量的值是整個Makefile中最后被指定的值。
VIR_A = A VIR_B = $(VIR_A) B VIR_A = AA??經(jīng)過上面的賦值后,最后VIR_B的值是AA B,而不是A B,在make時,會把整個Makefile展開,來決定變量的值
??2、":=" 表示直接賦值,賦予當前位置的值。
??最后BIR_B的值是A B,即根據(jù)當前位置進行賦值。因此相當于“=”,“:=”才是真正意義上的直接賦值
??3、"?=" 表示如果該變量沒有被賦值,賦值予等號后面的值。
??如果VIR在之前沒有被賦值,那么VIR的值就為new_value。
VIR := old_value VIR ?= new_value??這種情況下,VIR的值就是old_value
??4、"+="和平時寫代碼的理解是一樣的,表示將符號后面的值添加到前面的變量上
5、預定義變量
CC:c編譯器的名稱,默認值為cc。cpp c預編譯器的名稱默認值為$(CC) -E
CC = gcc回顯問題,Makefile中的命令都會被打印出來。如果不想打印命令部分 可以使用@去除回顯
@echo "clean done!"6、函數(shù)
通配符
SRC = $(wildcard ./*.c)匹配目錄下所有.c 文件,并將其賦值給SRC變量。
OBJ = $(patsubst %.c, %.o, $(SRC))這個函數(shù)有三個參數(shù),意思是取出SRC中的所有值,然后將.c 替換為.o 最后賦值給OBJ變量。
示例:如果目錄下有很多個.c 源文件,就不需要寫很多條規(guī)則語句了,而是可以像下面這樣寫
這里先將所有.c 文件編譯為 .o 文件,這樣后面更改某個 .c 文件時,其他的 .c 文件將不在編譯,而只是編譯有更改的 .c 文件,可以大大提高大項目中的編譯速度。
7、偽目標 .PHONY
偽目標只是一個標簽,clean是個偽目標沒有依賴文件,只有用make來調用時才會執(zhí)行
當目錄下有與make 命令 同名的文件時 執(zhí)行make 命令就會出現(xiàn)錯誤。
解決辦法就是使用偽目標
通常也會把ALL設置成偽目標
8、其他常用功能
代碼清理clean
我們可以編譯一條屬于自己的clean語句,來清理make命令所產(chǎn)生的所有文件,列如
9、嵌套執(zhí)行Makefile
??在一些大工程中,會把不同模塊或不同功能的源文件放在不同的目錄中,我們可以在每個目錄中都寫一個該目錄的Makefile這有利于讓我們的Makefile變的更加簡潔,不至于把所有東西全部寫在一個Makefile中。
??列如在子目錄subdir目錄下有個Makefile文件,來指明這個目錄下文件的編譯規(guī)則。外部總Makefile可以這樣寫
??定義$(MAKE)宏變量的意思是,也許我們的make需要一些參數(shù),所以定義成一個變量比較有利于維護。兩個例子意思都是先進入"subdir"目錄,然后執(zhí)行make命令
??我們把這個Makefile叫做總控Makefile,總控Makefile的變量可以傳遞到下級的Makefile中,但是不會覆蓋下層Makefile中所定義的變量,除非指定了 "-e"參數(shù)。
??如果傳遞變量到下級Makefile中,那么可以使用這樣的聲明
??export
??如果不想讓某些變量傳遞到下級Makefile,可以使用
??unexport
10、指定頭文件路徑
一般都是通過"-I"(大寫i)來指定,假設頭文件在:
/home/develop/include則可以通過-I指定:
-I/home/develop/include將該目錄添加到頭文件搜索路徑中
在Makefile中則可以這樣寫:
然后在編譯的時候,引用CFLAGS即可,如下
yourapp:*.cgcc $(CFLAGS) -o yourapp11、指定庫文件路徑
與上面指定頭文件類似只不過使用的是"-L"來指定
LDFLAGS=-L/usr/lib -L/path/to/your/lib告訴鏈接器要鏈接哪些庫文件,使用"-l"(小寫L)如下:
LIBS = -lpthread -liconv簡單的Makefile實例
目錄結構
include
myinclude.h
#include <stdio.h> void print1() ; void print2() ;f1
f1.c
#include "../include/myinclude.h" void print1() { printf("Message f1.c\n"); return; }Makefile
目標前面的路徑,意思是將目標生成到指定的目錄下
f2
f2.c
#include "../include/myinclude.h" void print2() { printf("Message f2.c\n"); return; }Makefile
../$(OBJS_DIR)/f2.o:f2.c @$(CC) -c $^ -o $@main
main.c
#include "../include/myinclude.h" int main(int argc, char const *argv[]) {print1(); print2(); return 0; }Makefile
../$(OBJS_DIR)/main.o:main.c @$(CC) -c $^ -o $@obj
此目錄用來存放相關生成的目標文件Makefile
../$(BIN_DIR)/$(BIN) : $(OBJS)@$(CC) $^ -o $@主Makefile
#預定義變量 CC = gcc #預定義編譯目錄 SUBDIRS = f1 \f2 \main \obj #預定義目標 OBJS = f1.o f2.o main.o BIN = myapp OBJS_DIR = obj BIN_DIR = bin #傳遞預定義參數(shù) export CC OBJS BIN OBJS_DIR BIN_DIRall:CHECK_DIR $(SUBDIRS) CHECK_DIR:@mkdir -p $(BIN_DIR) $(SUBDIRS):ECHO@make -C $@ ECHO:@echo $(SUBDIRS)@echo begin compile clean:@$(RM) $(OBJS_DIR)/*.o@rm -rf $(BIN_DIR)bin
此文件用來存放生成的二進制文件
執(zhí)行結果
主Makefile執(zhí)行過程
生成.o文件
生成二進制文件執(zhí)行結果
總結
以上是生活随笔為你收集整理的Makefile入门(超详细一文读懂)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: eclipse创建folder变成pac
- 下一篇: AMTEmu v0.9.2