九色91_成人精品一区二区三区中文字幕_国产精品久久久久一区二区三区_欧美精品久久_国产精品99久久久久久久vr_www.国产视频

Hello! 歡迎來到小浪云!


自動化構建-make/Makefile 【Linux基礎開發工具】


avatar
小浪云 2025-04-17 15

一、背景

? 會不會寫makefile,從一個側面說明了一個?是否具備完成大型工程的能力 ? 一個工程中的源文件不計數,其按類型、功能、模塊分別放在若干個目錄中,makefile定義了一系列的規則來指定,哪些文件需要先編譯,哪些文件需要后編譯,哪些文件需要重新編譯,甚至于進行更復雜的功能操作 ? makefile帶來的好處就是?“自動化編譯”,一旦寫好,只需要一個make命令,整個工程完全自動編譯,極大的提高了軟件開發的效率。 ? make是一個命令#%#$#%@%@%$#%$#%#%#$%@_20dc++e2c6fa909a5cd62526615fe2788a,是一個解釋makefile中指令的命令工具,一般來說,大多數的ide都有這個命令,比如:delphi的make,visual c++的nmake,linuxgnu的make。可見,makefile都成為了一種在工程方面的編譯方法。 ? make是一條命令,makefile是一個文件,兩個搭配使用,完成項目自動化構建。

二、Makefile編譯過程

自動化構建-make/Makefile 【Linux基礎開發工具】

Makefile文件中的命令有一定規范,一旦該文件編寫好以后在Linux命令行中執行一條make命令即可自動編譯整個工程。不同廠家的make可能會稍有不同,并且語法上也有區別,不過基本思想都差不多,主要還是落在目標依賴上,最廣泛使用的是gnumake。

2、語法規則

代碼語言:JavaScript代碼運行次數:0運行復制

目標 ... : 依賴 ...命令1命令2. . .

“Makefile的核心規則,類似于一位廚師做菜,目標就是做好一道菜,那么所謂的依賴就是各種食材,各種廚具等等,然后需要廚師好的技術方法類似于命令,才能作出一道好菜。 ??同時這些依賴也有可能此時并不存在,需要現場制作,或者是由其他廚師做好,那么這個依賴就成為了其他規則的目標,該目標也會有他自己的依賴和命令。這樣就形成了一層一層遞歸依賴組成了Makefile文件。 Makefile并不會關心命令是如何執行的,僅僅只是會去執行所有定義的命令,和我們平時直接輸入命令行是一樣的效果。”

目標即要生成的文件。如果目標文件的更新時間晚于依賴文件更新時間,則說明依賴文件沒有改動,目標文件不需要重新編譯。否則會進行重新編譯并更新目標文件。默認情況下Makefile的第一個目標為終極目標。依賴:即目標文件由哪些文件生成。命令:即通過執行命令由依賴文件生成目標文件。注意每條命令之前必須有一個tab(此文檔編輯器默認是空格,復制下來的代碼需要把命令代碼的縮進改為tab制表符)保持縮進,這是語法要求。all:Makefile文件默認只生成第一個目標文件即完成編譯,但是我們可以通過all 指定所需要生成的目標文件。 例如下面的例子:代碼語言:javascript代碼運行次數:0運行復制

all: target1 target2 target3target1:# 編譯規則1target2:# 編譯規則2target3:# 編譯規則3

all被設置為第一個目標,并且target1、target2和target3被列為all的依賴。當你在命令行中運行make時,make命令會尋找并執行all目標規則,這將依次執行target1、target2和target3的編譯規則。 因此,通過在Makefile中設置all作為默認目標規則,你可以簡化構建過程,只需運行make命令即可執行整個編譯過程,無需顯式指定目標三、變量

符號表示取變量的值,當變量名多于一個字符時,使用”( )”

^ 表示所有的依賴文件 @ 表示生成的目標文件

代碼語言:javascript代碼運行次數:0運行復制

SRC = $(wildcard *.c)OBJ = $(patsubst %.c, %.o, $(SRC)) ALL: hello.out hello.out: $(OBJ)        gcc $四、變量賦值1、"="是最普通的等號代碼語言:javascript<i class="icon-code"></i>代碼運行次數:<!-- -->0<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewbox="0 0 16 16" fill="none"><path d="M6.66666 10.9999L10.6667 7.99992L6.66666 4.99992V10.9999ZM7.99999 1.33325C4.31999 1.33325 1.33333 4.31992 1.33333 7.99992C1.33333 11.6799 4.31999 14.6666 7.99999 14.6666C11.68 14.6666 14.6667 11.6799 14.6667 7.99992C14.6667 4.31992 11.68 1.33325 7.99999 1.33325ZM7.99999 13.3333C5.05999 13.3333 2.66666 10.9399 2.66666 7.99992C2.66666 5.05992 5.05999 2.66659 7.99999 2.66659C10.94 2.66659 13.3333 5.05992 13.3333 7.99992C13.3333 10.9399 10.94 13.3333 7.99999 13.3333Z" fill="currentcolor"></path></svg>運行<svg width="16" height="16" viewbox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M4.5 15.5V3.5H14.5V15.5H4.5ZM12.5 5.5H6.5V13.5H12.5V5.5ZM9.5 2.5H3.5V12.5H1.5V0.5H11.5V2.5H9.5Z" fill="currentcolor"></path></svg>復制<pre class="prism-token token line-numbers javascript">在Makefile中容易搞錯賦值等號,

使用 “=”進行賦值,變量的值是整個Makefile中最后被指定的值。

代碼語言:javascript代碼運行次數:0運行復制

VIR_A = AVIR_B = $(VIR_A) BVIR_A = AA

經過上面的賦值后,最后VIR_B的值是AA B,而不是A B,在make時,會把整個Makefile展開,來決定變量的值(類似于宏定義)

2、“:=” 表示直接賦值代碼語言:javascript代碼運行次數:0運行復制

賦予當前位置的值。

代碼語言:javascript代碼運行次數:0運行復制

VIR_A := AVIR_B := $(VIR_A) BVIR_A := AA

最后BIR_B的值是A B,即根據當前位置進行賦值。因此相當于“=”,“:=”才是真正意義上的直接賦值

3、“?=” 表示如果該變量沒有被賦值,代碼語言:javascript代碼運行次數:0運行復制

賦值予等號后面的值。

代碼語言:javascript代碼運行次數:0運行復制

VIR ?= new_value

如果VIR在之前沒有被賦值,那么VIR的值就為new_value。

代碼語言:javascript代碼運行次數:0運行復制

VIR := old_valueVIR ?= new_value

這種情況下,VIR的值就是old_value

4、”+=”和寫代碼是一樣的,代碼語言:javascript代碼運行次數:0運行復制

表示將符號后面的值添加到前面的變量上

五、預定義變量

CC:c編譯器的名稱,默認值為cc。 cpp c預編譯器的名稱默認值為$(CC) -E

代碼語言:javascript代碼運行次數:0運行復制

CC = gcc

回顯問題,Makefile中的命令都會被打印出來。如果不想打印命令部分 可以使用@去除回顯

代碼語言:javascript代碼運行次數:0運行復制

@echo "clean done!"

六、函數通配符代碼語言:javascript代碼運行次數:0運行復制

SRC = $(wildcard ./*.c)

匹配目錄下所有.c 文件,并將其賦值給SRC變量。

代碼語言:javascript代碼運行次數:0運行復制

OBJ = $(patsubst %.c, %.o, $(SRC))

這個函數有三個參數,意思是取出SRC中的所有值,然后將.c 替換為.o 最后賦值給OBJ變量。

示例:如果目錄下有很多個.c 源文件,就不需要寫很多條規則語句了,而是可以像下面這樣寫

代碼語言:javascript代碼運行次數:0運行復制

SRC = $(wildcard *.c)OBJ = $(patsubst %.c, %.o, $(SRC)) ALL: test.exe  #生成執行文件 test.exe: $(OBJ)        gcc $(OBJ) -o test %.o: %.c        gcc -c $<p>這里先將所有.c 文件編譯為 .o 文件,這樣后面更改某個 .c 文件時,其他的 .c 文件將不在編譯,而只是編譯有更改的 .c 文件,可以大大提高大項目中的編譯速度。</p>七、偽目標 .PHONY<p>偽目標只是一個標簽,clean是個偽目標沒有依賴文件,只有用make來調用時才會執行 當目錄下有與make 命令 同名的文件時 執行make 命令就會出現錯誤。 解決辦法就是使用偽目標</p>代碼語言:javascript<i class="icon-code"></i>代碼運行次數:<!-- -->0<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewbox="0 0 16 16" fill="none"><path d="M6.66666 10.9999L10.6667 7.99992L6.66666 4.99992V10.9999ZM7.99999 1.33325C4.31999 1.33325 1.33333 4.31992 1.33333 7.99992C1.33333 11.6799 4.31999 14.6666 7.99999 14.6666C11.68 14.6666 14.6667 11.6799 14.6667 7.99992C14.6667 4.31992 11.68 1.33325 7.99999 1.33325ZM7.99999 13.3333C5.05999 13.3333 2.66666 10.9399 2.66666 7.99992C2.66666 5.05992 5.05999 2.66659 7.99999 2.66659C10.94 2.66659 13.3333 5.05992 13.3333 7.99992C13.3333 10.9399 10.94 13.3333 7.99999 13.3333Z" fill="currentcolor"></path></svg>運行<svg width="16" height="16" viewbox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M4.5 15.5V3.5H14.5V15.5H4.5ZM12.5 5.5H6.5V13.5H12.5V5.5ZM9.5 2.5H3.5V12.5H1.5V0.5H11.5V2.5H9.5Z" fill="currentcolor"></path></svg>復制<pre class="prism-token token line-numbers javascript">SRC = $(wildcard *.c)OBJ = $(patsubst %.c, %.o, $(SRC)) ALL: test.exe test.exe: $(OBJ)        gcc $八、其他常用功能代碼清理clean<p>我們可以編譯一條屬于自己的clean語句,來清理make命令所產生的所有文件,列如</p>代碼語言:javascript<i class="icon-code"></i>代碼運行次數:<!-- -->0<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewbox="0 0 16 16" fill="none"><path d="M6.66666 10.9999L10.6667 7.99992L6.66666 4.99992V10.9999ZM7.99999 1.33325C4.31999 1.33325 1.33333 4.31992 1.33333 7.99992C1.33333 11.6799 4.31999 14.6666 7.99999 14.6666C11.68 14.6666 14.6667 11.6799 14.6667 7.99992C14.6667 4.31992 11.68 1.33325 7.99999 1.33325ZM7.99999 13.3333C5.05999 13.3333 2.66666 10.9399 2.66666 7.99992C2.66666 5.05992 5.05999 2.66659 7.99999 2.66659C10.94 2.66659 13.3333 5.05992 13.3333 7.99992C13.3333 10.9399 10.94 13.3333 7.99999 13.3333Z" fill="currentcolor"></path></svg>運行<svg width="16" height="16" viewbox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M4.5 15.5V3.5H14.5V15.5H4.5ZM12.5 5.5H6.5V13.5H12.5V5.5ZM9.5 2.5H3.5V12.5H1.5V0.5H11.5V2.5H9.5Z" fill="currentcolor"></path></svg>復制<pre class="prism-token token line-numbers javascript">SRC = $(wildcard *.c)OBJ = $(patsubst %.c, %.o, $(SRC)) ALL: test.exe test.exe: $(OBJ)        gcc $九、嵌套執行Makefile<p>在一些大工程中,會把不同模塊或不同功能的源文件放在不同的目錄中,我們可以在每個目錄中都寫一個該目錄的Makefile這有利于讓我們的Makefile變的更加簡潔,不至于把所有東西全部寫在一個Makefile中。 ??列如在子目錄subdir目錄下有個Makefile文件,來指明這個目錄下文件的編譯規則。外部總Makefile可以這樣寫</p>代碼語言:javascript<i class="icon-code"></i>代碼運行次數:<!-- -->0<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewbox="0 0 16 16" fill="none"><path d="M6.66666 10.9999L10.6667 7.99992L6.66666 4.99992V10.9999ZM7.99999 1.33325C4.31999 1.33325 1.33333 4.31992 1.33333 7.99992C1.33333 11.6799 4.31999 14.6666 7.99999 14.6666C11.68 14.6666 14.6667 11.6799 14.6667 7.99992C14.6667 4.31992 11.68 1.33325 7.99999 1.33325ZM7.99999 13.3333C5.05999 13.3333 2.66666 10.9399 2.66666 7.99992C2.66666 5.05992 5.05999 2.66659 7.99999 2.66659C10.94 2.66659 13.3333 5.05992 13.3333 7.99992C13.3333 10.9399 10.94 13.3333 7.99999 13.3333Z" fill="currentcolor"></path></svg>運行<svg width="16" height="16" viewbox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M4.5 15.5V3.5H14.5V15.5H4.5ZM12.5 5.5H6.5V13.5H12.5V5.5ZM9.5 2.5H3.5V12.5H1.5V0.5H11.5V2.5H9.5Z" fill="currentcolor"></path></svg>復制<pre class="prism-token token line-numbers javascript">subsystem:            cd subdir &amp;&amp; $(MAKE)其等價于:subsystem:            $(MAKE) -C subdir

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

代碼語言:javascript代碼運行次數:0運行復制

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

十、指定頭文件路徑

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

代碼語言:javascript代碼運行次數:0運行復制

/home/develop/include

則可以通過-I指定:

代碼語言:javascript代碼運行次數:0運行復制

-I/home/develop/include

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

代碼語言:javascript代碼運行次數:0運行復制

CFLAGS=-I/home/develop/include

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

代碼語言:javascript代碼運行次數:0運行復制

yourapp:*.c    gcc $(CFLAGS) -o yourapp

十一、指定庫文件路徑

與上面指定頭文件類似只不過使用的是”-L”來指定

代碼語言:javascript代碼運行次數:0運行復制

LDFLAGS=-L/usr/lib -L/path/to/your/lib

告訴鏈接器要鏈接哪些庫文件,使用”-l”(小寫L)如下:

代碼語言:javascript代碼運行次數:0運行復制

LIBS = -lpthread -liconv

十二、基本使用

實例代碼

代碼語言:javascript代碼運行次數:0運行復制

#include <stdio.h> int main() {     printf("hello Makefile!n");     return 0;} </stdio.h>

Makefile文件

代碼語言:javascript代碼運行次數:0運行復制

myproc:myproc.cgcc -o myproc myproc.c.PHONY:cleanclean:rm -f myproc 

依賴關系 ? 上面的文件myproc,它依賴myproc.c 依賴方法 ? gcc -o myproc myproc.c ,就是與之對應的依賴關系 項目清理 ? 工程是需要被清理的 ? 像clean這種,沒有被第一個目標文件直接或間接關聯,那么它后面所定義的命令將不會被自動執行,不過,我們可以顯示要make執行。即命令?“make clean”,以此來清除所有的目標文件,以便重編譯。 ? 但是一般我們這種clean的目標文件,我們將它設置為偽目標,用 .PHONY 修飾,偽目標的特性是,總是被執行的。 ? 可以將我們的 hello 目標文件聲明成偽目標,測試一下。 什么叫做總是被執行?

代碼語言:javascript代碼運行次數:0運行復制

$ stat XXXFile: ‘XXX’Size: 987  Blocks: 8  IO Block: 4096  regular fileDevice: fd01h/64769d Inode: 1321125 Links: 1access: (0664/-rw-rw-r--) Uid: ( 1000/ whb) Gid: ( 1000/ whb)Access: 2024-10-25 17:05:30.430619002 +0800Modify: 2024-10-25 17:05:25.940595116 +0800Change: 2024-10-25 17:05:25.940595116 +0800?件 = 內容 + 屬性Modify: 內容變更,時間更新Change:屬性變更,時間更新Access:常指的是?件最近?次被訪問的時間。在Linux的早期版本中,每當?件被訪問時,其atime都會更新。但這種機制會導致?量的IO操作。具體更新原則,不做過多解釋。
自動化構建-make/Makefile 【Linux基礎開發工具】

? 結論: .PHONY:讓make忽略源文件和可執行目標文件的M時間對比

十三、推導過程代碼語言:javascript代碼運行次數:0運行復制

myproc:myproc.o gcc myproc.o -o myproc myproc.o:myproc.sgcc -c myproc.s -o myproc.omyproc.s:myproc.i gcc -S myproc.i -o myproc.smyproc.i:myproc.c gcc -E myproc.c -o myproc.i .PHONY:clean clean: rm -f *.i *.s *.o myproc

編譯

代碼語言:javascript代碼運行次數:0運行復制

$ makegcc -E myproc.c -o myproc.igcc -S myproc.i -o myproc.sgcc -c myproc.s -o myproc.ogcc myproc.o -o myproc
自動化構建-make/Makefile 【Linux基礎開發工具】

make是如何工作的,在默認的方式下,也就是我們只輸入make命令。那么:

make會在當前目錄下找名字叫“Makefile”或“makefile”的文件。如果找到,它會找文件中的第一個目標文件(target),在上面的例子中,他會找到 myproc 這個文件,并把這個文件作為最終的目標文件。如果 myproc 文件不存在,或是 myproc 所依賴的后面的 myproc.o 文件的文件修改時間要比 myproc 這個文件新(可以用 touch 測試),那么,他就會執行后面所定義的命令來生成myproc 這個文件。如果 myproc 所依賴的 myproc.o 文件不存在,那么 make 會在當前文件中找目標為myproc.o 文件的依賴性,如果找到則再根據那一個規則生成 myproc.o 文件。(這有點像一個的過程)當然,你的C文件和H文件是存在的啦,于是 make 會生成 myproc.o 文件,然后再用 myproc.o 文件聲明 make 的終極任務,也就是執行文件 hello 了。這就是整個make的依賴性,make會一層又一層地去找文件的依賴關系,直到最終編譯出第一個目標文件。在找尋的過程中,如果出現錯誤,比如最后被依賴的文件找不到,那么make就會直接退出,并報錯,而對于所定義的命令的錯誤,或是編譯不成功,make根本不理。make只管文件的依賴性,即,如果在我找了依賴關系之后,冒號后面的文件還是不在,那么對不起,我就不工作啦。十四、適度擴展語法代碼語言:javascript代碼運行次數:0運行復制

BIN=proc.exe  # 定義變量CC=gcc#SRC=$(shell ls *.c)   # 采?shell命令??式,獲取當前所有.c?件名SRC=$(wildcard *.c)   # 或者使? wildcard 函數,獲取當前所有.c?件名OBJ=$(SRC:.c=.o)   # 將SRC的所有同名.c 替換 成為.o 形成?標?件列表LFLAGS=-o   # 鏈接選項FLAGS=-c   # 編譯選項RM=rm -f   # 引?命令$(BIN):$(OBJ)@$(CC) $(LFLAGS) $@ $^   # $@:代表?標?件名。 $^: 代表依賴?件列表@echo "linking ... $^ to $@"%.o:%.c # %.c 展開當前?錄下所有的.c。 %.o: 同時展開同名.o@$(CC) $(FLAGS) $

相關閱讀

主站蜘蛛池模板: 97精品一区二区 | 91国自视频 | 午夜爽爽爽男女免费观看影院 | 日韩欧美国产精品一区二区 | 日韩精品一区二区三区在线播放 | 欧美日韩一区二区三区四区 | 91影院| 精品免费| 中文字幕一区二区三区精彩视频 | 国产精品一区二区av | 国产精品色 | 欧美aaaaaaaaaa | 国产综合精品 | 亚洲欧美日韩精品久久亚洲区 | 一区二区中文 | 91精品国产91久久久久福利 | 日韩精品一区二区三区在线播放 | 免费在线观看黄视频 | 欧美日韩久久 | 嫩草懂你的影院入口 | 日本精品视频在线 | 欧洲av一区| 九九综合| 国产激情小视频 | 国产精品一区一区三区 | 精品三区 | 超碰在线播 | 精品欧美| av国产精品毛片一区二区小说 | 亚洲视频www| 日韩成人在线播放 | 中文字幕视频在线免费 | 日本超碰 | 国产午夜精品福利 | 九九精品视频在线 | 国产欧美一区二区三区国产幕精品 | 欧美精品一区二区三区四区 在线 | 亚洲成av人影片在线观看 | 欧美精品网 | 色视频欧美| 免费看黄色片 |