日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Makefile入门(超详细一文读懂)

發(fā)布時間:2023/12/10 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Makefile入门(超详细一文读懂) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

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、變量

$符號表示取變量的值,當變量名多于一個字符時,使用"( )"
$符的其他用法

$^ 表示所有的依賴文件
$@ 表示生成的目標文件
$< 代表第一個依賴文件

SRC = $(wildcard *.c) OBJ = $(patsubst %.c, %.o, $(SRC))ALL: hello.outhello.out: $(OBJ)gcc $< -o $@$(OBJ): $(SRC)gcc -c $< -o $@

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、":=" 表示直接賦值,賦予當前位置的值。

VIR_A := A VIR_B := $(VIR_A) B VIR_A := AA

??最后BIR_B的值是A B,即根據(jù)當前位置進行賦值。因此相當于“=”,“:=”才是真正意義上的直接賦值
??3、"?=" 表示如果該變量沒有被賦值,賦值予等號后面的值。

VIR ?= new_value

??如果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ī)則語句了,而是可以像下面這樣寫

SRC = $(wildcard *.c) OBJ = $(patsubst %.c, %.o, $(SRC))ALL: hello.outhello.out: $(OBJ)gcc $(OBJ) -o hello.out$(OBJ): $(SRC)gcc -c $(SRC) -o $(OBJ)

這里先將所有.c 文件編譯為 .o 文件,這樣后面更改某個 .c 文件時,其他的 .c 文件將不在編譯,而只是編譯有更改的 .c 文件,可以大大提高大項目中的編譯速度。

7、偽目標 .PHONY

偽目標只是一個標簽,clean是個偽目標沒有依賴文件,只有用make來調用時才會執(zhí)行
當目錄下有與make 命令 同名的文件時 執(zhí)行make 命令就會出現(xiàn)錯誤。
解決辦法就是使用偽目標

SRC = $(wildcard *.c) OBJ = $(patsubst %.c, %.o, $(SRC))ALL: hello.outhello.out: $(OBJ)gcc $< -o $@$(OBJ): $(SRC)gcc -c $< -o $@clean:rm -rf $(OBJ) hello.out.PHONY: clean ALL

通常也會把ALL設置成偽目標

8、其他常用功能

代碼清理clean
我們可以編譯一條屬于自己的clean語句,來清理make命令所產(chǎn)生的所有文件,列如

SRC = $(wildcard *.c) OBJ = $(patsubst %.c, %.o, $(SRC))ALL: hello.outhello.out: $(OBJ)gcc $< -o $@$(OBJ): $(SRC)gcc -c $< -o $@clean:rm -rf $(OBJ) hello.out

9、嵌套執(zhí)行Makefile

??在一些大工程中,會把不同模塊或不同功能的源文件放在不同的目錄中,我們可以在每個目錄中都寫一個該目錄的Makefile這有利于讓我們的Makefile變的更加簡潔,不至于把所有東西全部寫在一個Makefile中。
??列如在子目錄subdir目錄下有個Makefile文件,來指明這個目錄下文件的編譯規(guī)則。外部總Makefile可以這樣寫

subsystem:cd subdir && $(MAKE) 其等價于: subsystem:$(MAKE) -C subdir

??定義$(MAKE)宏變量的意思是,也許我們的make需要一些參數(shù),所以定義成一個變量比較有利于維護。兩個例子意思都是先進入"subdir"目錄,然后執(zhí)行make命令
??我們把這個Makefile叫做總控Makefile,總控Makefile的變量可以傳遞到下級的Makefile中,但是不會覆蓋下層Makefile中所定義的變量,除非指定了 "-e"參數(shù)。
??如果傳遞變量到下級Makefile中,那么可以使用這樣的聲明
??export
??如果不想讓某些變量傳遞到下級Makefile,可以使用
??unexport

export variable = value 等價于 variable = value export variable 等價于 export variable := value 等價于 variable := value export variable 如果需要傳遞所有變量,那么只要一個export就行了。后面什么也不用跟,表示傳遞所有變量

10、指定頭文件路徑

一般都是通過"-I"(大寫i)來指定,假設頭文件在:

/home/develop/include

則可以通過-I指定:

-I/home/develop/include

將該目錄添加到頭文件搜索路徑中
在Makefile中則可以這樣寫:

CFLAGS=-I/home/develop/include

然后在編譯的時候,引用CFLAGS即可,如下

yourapp:*.cgcc $(CFLAGS) -o yourapp

11、指定庫文件路徑

與上面指定頭文件類似只不過使用的是"-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
目標前面的路徑,意思是將目標生成到指定的目錄下

../$(OBJS_DIR)/f1.o:f1.c @$(CC) -c $^ -o $@

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入门(超详细一文读懂)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。