国产精品一区二区在线观看完整版,在线观看91精品国产性色,欧美日韩另类视频

杭州校區(qū)切換校區(qū)
圖片

Makefile 及其工作原理

發(fā)布時(shí)間: 2018-09-11

當(dāng)你需要在一些源文件改變后運(yùn)行或更新一個(gè)任務(wù)時(shí),通常會(huì)用到 make 工具。make 工具需要讀取一個(gè) Makefile(或 makefile)文件,在該文件中定義了一系列需要執(zhí)行的任務(wù)。你可以使用 make 來(lái)將源代碼編譯為可執(zhí)行程序。大部分開(kāi)源項(xiàng)目會(huì)使用 make 來(lái)實(shí)現(xiàn)最終的二進(jìn)制文件的編譯,然后使用 make install 命令來(lái)執(zhí)行安裝。

本文將通過(guò)一些基礎(chǔ)和進(jìn)階的示例來(lái)展示 make 和 Makefile 的使用方法。在開(kāi)始前,請(qǐng)確保你的系統(tǒng)中安裝了 make。

基礎(chǔ)示例

依然從打印 “Hello World” 開(kāi)始。首先創(chuàng)建一個(gè)名字為 myproject 的目錄,目錄下新建 Makefile 文件,文件內(nèi)容為:

  1. say_hello:

  2.         echo "Hello World"

在 myproject 目錄下執(zhí)行 make,會(huì)有如下輸出:

  1. $ make

  2. echo "Hello World"

  3. Hello World

在上面的例子中,“say_hello” 類似于其他編程語(yǔ)言中的函數(shù)名。這被稱之為目標(biāo)target。在該目標(biāo)之后的是預(yù)置條件或依賴。為了簡(jiǎn)單起見(jiàn),我們?cè)谶@個(gè)示例中沒(méi)有定義預(yù)置條件。echo ‘Hello World' 命令被稱為步驟recipe。這些步驟基于預(yù)置條件來(lái)實(shí)現(xiàn)目標(biāo)。目標(biāo)、預(yù)置條件和步驟共同構(gòu)成一個(gè)規(guī)則。

總結(jié)一下,一個(gè)典型的規(guī)則的語(yǔ)法為:

  1. 目標(biāo): 預(yù)置條件

  2. <TAB> 步驟

作為示例,目標(biāo)可以是一個(gè)基于預(yù)置條件(源代碼)的二進(jìn)制文件。另一方面,預(yù)置條件也可以是依賴其他預(yù)置條件的目標(biāo)。

  1. final_target: sub_target final_target.c

  2.         Recipe_to_create_final_target

  3.        

  4. sub_target: sub_target.c

  5.         Recipe_to_create_sub_target

目標(biāo)并不要求是一個(gè)文件,也可以只是步驟的名字,就如我們的例子中一樣。我們稱之為“偽目標(biāo)”。

再回到上面的示例中,當(dāng) make 被執(zhí)行時(shí),整條指令 echo "Hello World" 都被顯示出來(lái),之后才是真正的執(zhí)行結(jié)果。如果不希望指令本身被打印處理,需要在 echo 前添加 @。

say_hello:
        @echo "Hello World"

重新運(yùn)行 make,將會(huì)只有如下輸出:

  1. $ make

  2. Hello World

接下來(lái)在 Makefile 中添加如下偽目標(biāo):generate 和 clean:

  1. say_hello:

  2.         @echo "Hello World"

  3. generate:

  4.         @echo "Creating empty text files..."

  5.         touch file-{1..10}.txt

  6. clean:

  7.         @echo "Cleaning up..."

  8.         rm *.txt

隨后當(dāng)我們運(yùn)行 make 時(shí),只有 say_hello 這個(gè)目標(biāo)被執(zhí)行。這是因?yàn)镸akefile 中的第一個(gè)目標(biāo)為默認(rèn)目標(biāo)。通常情況下會(huì)調(diào)用默認(rèn)目標(biāo),這就是你在大多數(shù)項(xiàng)目中看到 all 作為第一個(gè)目標(biāo)而出現(xiàn)。all 負(fù)責(zé)來(lái)調(diào)用它他的目標(biāo)。我們可以通過(guò) .DEFAULT_GOAL 這個(gè)特殊的偽目標(biāo)來(lái)覆蓋掉默認(rèn)的行為。

在 Makefile 文件開(kāi)頭增加 .DEFAULT_GOAL:

  1. .DEFAULT_GOAL := generate

make 會(huì)將 generate 作為默認(rèn)目標(biāo):

  1. $ make

  2. Creating empty text files...

  3. touch file-{1..10}.txt

顧名思義,.DEFAULT_GOAL 偽目標(biāo)僅能定義一個(gè)目標(biāo)。這就是為什么很多 Makefile 會(huì)包括 all 這個(gè)目標(biāo),這樣可以調(diào)用多個(gè)目標(biāo)。

下面刪除掉 .DEFAULT_GOAL,增加 all 目標(biāo):

  1. all: say_hello generate

  2. say_hello:

  3.         @echo "Hello World"

  4. generate:

  5.         @echo "Creating empty text files..."

  6.         touch file-{1..10}.txt

  7. clean:

  8.         @echo "Cleaning up..."

  9.         rm *.txt

運(yùn)行之前,我們?cè)僭黾右恍┨厥獾膫文繕?biāo)。.PHONY 用來(lái)定義這些不是文件的目標(biāo)。make 會(huì)默認(rèn)調(diào)用這些偽目標(biāo)下的步驟,而不去檢查文件名是否存在或最后修改日期。完整的 Makefile如下:

  1. .PHONY: all say_hello generate clean

  2. all: say_hello generate

  3. say_hello:

  4.         @echo "Hello World"

  5. generate:

  6.         @echo "Creating empty text files..."

  7.         touch file-{1..10}.txt

  8. clean:

  9.         @echo "Cleaning up..."

  10.         rm *.txt

make 命令會(huì)調(diào)用 say_hello 和 generate:

  1. $ make

  2. Hello World

  3. Creating empty text files...

  4. touch file-{1..10}.txt

clean 不應(yīng)該被放入 all 中,或者被放入第一個(gè)目標(biāo)中。clean 應(yīng)當(dāng)在需要清理時(shí)手動(dòng)調(diào)用,調(diào)用方法為 make clean。

  1. $ make clean

  2. Cleaning up...

  3. rm *.txt

現(xiàn)在你應(yīng)該已經(jīng)對(duì) Makefile 有了基礎(chǔ)的了解,接下來(lái)我們看一些進(jìn)階的示例。

進(jìn)階示例

變量

在之前的實(shí)例中,大部分目標(biāo)和預(yù)置條件是已經(jīng)固定了的,但在實(shí)際項(xiàng)目中,它們通常用變量和模式來(lái)代替。

定義變量最簡(jiǎn)單的方式是使用 = 操作符。例如,將命令 gcc 賦值給變量 CC:

  1. CC = gcc

這被稱為遞歸擴(kuò)展變量,用于如下所示的規(guī)則中:

  1. hello: hello.c

  2.     ${CC} hello.c -o hello

你可能已經(jīng)想到了,這些步驟將會(huì)在傳遞給終端時(shí)展開(kāi)為:

  1. gcc hello.c -o hello

${CC} 和 $(CC) 都能對(duì) gcc 進(jìn)行引用。但如果一個(gè)變量嘗試將它本身賦值給自己,將會(huì)造成死循環(huán)。讓我們驗(yàn)證一下:

  1. CC = gcc

  2. CC = ${CC}

  3. all:

  4.     @echo ${CC}

此時(shí)運(yùn)行 make 會(huì)導(dǎo)致:

  1. $ make

  2. Makefile:8: *** Recursive variable 'CC' references itself (eventually).  Stop.

為了避免這種情況發(fā)生,可以使用 := 操作符(這被稱為簡(jiǎn)單擴(kuò)展變量)。以下代碼不會(huì)造成上述問(wèn)題:

  1. CC := gcc

  2. CC := ${CC}

  3. all:

  4.     @echo ${CC}

模式和函數(shù)

下面的 Makefile 使用了變量、模式和函數(shù)來(lái)實(shí)現(xiàn)所有 C 代碼的編譯。我們來(lái)逐行分析下:

  1. # Usage:

  2. # make        # compile all binary

  3. # make clean  # remove ALL binaries and objects

  4. .PHONY = all clean

  5. CC = gcc                        # compiler to use

  6. LINKERFLAG = -lm

  7. SRCS := $(wildcard *.c)

  8. BINS := $(SRCS:%.c=%)

  9. all: ${BINS}

  10. %: %.o

  11.         @echo "Checking.."

  12.         ${CC} ${LINKERFLAG} $< -o $@

  13. %.o: %.c

  14.         @echo "Creating object.."

  15.         ${CC} -c $<

  16. clean:

  17.         @echo "Cleaning up..."

  18.         rm -rvf *.o ${BINS}

? 以 # 開(kāi)頭的行是評(píng)論。? .PHONY = all clean 行定義了 all 和 clean 兩個(gè)偽目標(biāo)。? 變量 LINKERFLAG 定義了在步驟中 gcc 命令需要用到的參數(shù)。? SRCS := $(wildcard *.c):$(wildcard pattern) 是與文件名相關(guān)的一個(gè)函數(shù)。在本示例中,所有 “.c”后綴的文件會(huì)被存入 SRCS 變量。? BINS := $(SRCS:%.c=%):這被稱為替代引用。本例中,如果 SRCS 的值為 'foo.c bar.c',則 BINS的值為 'foo bar'。? all: ${BINS} 行:偽目標(biāo) all 調(diào)用 ${BINS} 變量中的所有值作為子目標(biāo)。?

規(guī)則:

  1. %: %.o

  2.   @echo "Checking.."

  3.   ${CC} ${LINKERFLAG} $&lt; -o $@

下面通過(guò)一個(gè)示例來(lái)理解這條規(guī)則。假定 foo 是變量 ${BINS} 中的一個(gè)值。% 會(huì)匹配到 foo(%匹配任意一個(gè)目標(biāo))。下面是規(guī)則展開(kāi)后的內(nèi)容:

  1. foo: foo.o

  2.   @echo "Checking.."

  3.   gcc -lm foo.o -o foo

如上所示,% 被 foo 替換掉了。$< 被 foo.o 替換掉。$<用于匹配預(yù)置條件,$@ 匹配目標(biāo)。對(duì) ${BINS} 中的每個(gè)值,這條規(guī)則都會(huì)被調(diào)用一遍。

?

規(guī)則:

  1. %.o: %.c

  2.   @echo "Creating object.."

  3.   ${CC} -c $&lt;

之前規(guī)則中的每個(gè)預(yù)置條件在這條規(guī)則中都會(huì)都被作為一個(gè)目標(biāo)。下面是展開(kāi)后的內(nèi)容:

  1. foo.o: foo.c

  2.   @echo "Creating object.."

  3.   gcc -c foo.c

?

最后,在 clean 目標(biāo)中,所有的二進(jìn)制文件和編譯文件將被刪除。

下面是重寫(xiě)后的 Makefile,該文件應(yīng)該被放置在一個(gè)有 foo.c 文件的目錄下:

  1. # Usage:

  2. # make        # compile all binary

  3. # make clean  # remove ALL binaries and objects

  4. .PHONY = all clean

  5. CC = gcc                        # compiler to use

  6. LINKERFLAG = -lm

  7. SRCS := foo.c

  8. BINS := foo

  9. all: foo

  10. foo: foo.o

  11.         @echo "Checking.."

  12.         gcc -lm foo.o -o foo

  13. foo.o: foo.c

  14.         @echo "Creating object.."

  15.         gcc -c foo.c

  16. clean:

  17.         @echo "Cleaning up..."

  18.         rm -rvf foo.o foo

上一篇: Linux 進(jìn)程基礎(chǔ)

下一篇: 因數(shù)而驅(qū)的商務(wù)智能將如何賦能于人

在線咨詢 ×

您好,請(qǐng)問(wèn)有什么可以幫您?我們將竭誠(chéng)提供最優(yōu)質(zhì)服務(wù)!

<bdo id="pdyax"></bdo>

    <pre id="pdyax"></pre>
    <menuitem id="pdyax"></menuitem>
      <form id="pdyax"><tbody id="pdyax"></tbody></form>

      1. <center id="pdyax"><center id="pdyax"></center></center>
          1. 主站蜘蛛池模板: 静乐县| 乐昌市| 塔城市| 辽宁省| 吴桥县| 明溪县| 黄龙县| 定结县| 武威市| 连平县| 宜宾县| 颍上县| 新宾| 南岸区| 合作市| 丹江口市| 焦作市| 黎城县| 莎车县| 南通市| 临高县| 大埔区| 西乌| 随州市| 富民县| 曲松县| 苏尼特左旗| 辽源市| 台南市| 山西省| 长沙县| 金湖县| 南昌县| 海盐县| 武隆县| 分宜县| 海原县| 罗山县| 郁南县| 建湖县| 莱阳市|