溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

make 中的路徑搜索(十二)

發(fā)布時(shí)間:2020-06-08 03:42:32 來源:網(wǎng)絡(luò) 閱讀:1749 作者:上帝之子521 欄目:系統(tǒng)運(yùn)維

        我們在實(shí)際的工程項(xiàng)目中,所有的源文件和頭文件都放在同一個(gè)文件夾中嗎?如果是比較小的項(xiàng)目,當(dāng)然是可以的。但如果是成千上萬的源文件,當(dāng)然必須得分開存放。常用的源碼管理方式如下

make 中的路徑搜索(十二)

        那么下面的 makefile 能夠編譯成功嗎?

make 中的路徑搜索(十二)

        我們來試試,編譯結(jié)果如下

make 中的路徑搜索(十二)

        那么結(jié)果肯定會是這樣的,因?yàn)槲覀冊?makefile 中就沒有指定路徑,它在當(dāng)前目錄下沒有找到源文件。接下來我們就得來介紹一個(gè)特殊的預(yù)定義變量 VPATH (全大寫),VAPTH 變量的值用于指示 make 如何查找文件,不同文件夾可作為 VPATH 的值同時(shí)出現(xiàn),文件夾的名字之間需要使用分隔符進(jìn)行區(qū)分。格式如下

make 中的路徑搜索(十二)

        make 對于 VAPTH 值的處理方式:1、當(dāng)前文件夾找不到需要的文件時(shí),VAPTH 會被使用;2、make 會在 VAPTH 指定的文件夾中依次搜索文件;3、當(dāng)多個(gè)文件夾存在同名文件時(shí),選擇第一次搜索到的文件。注意事項(xiàng):1、VAPTH 只能決定 make 的搜索路徑,無法決定命令的搜素路徑;2、對于特定的編譯命令(gcc),需要獨(dú)立指定編譯搜索路徑。如下

make 中的路徑搜索(十二)

        下來我們還是以代碼為例來進(jìn)行說明,在上面的 makefile 基礎(chǔ)上進(jìn)行改寫

OBJS := func.o main.o
INC := inc
SRC := src
VPATH := $(INC) $(SRC)

hello.out : $(OBJS)
    @gcc -o $@ $^
    @echo "Target File ==> $@"

$(OBJS) : %.o : %.c func.h
    @gcc -o $@ -c $^

        我們來編譯試試看

make 中的路徑搜索(十二)

        我么你看到編譯還是報(bào)錯(cuò),原因就是我們在 gcc 的時(shí)候依賴文件中還包含有 func.h,下來我們將最后一行的 $^ 改為 $<。再來試試看

make 中的路徑搜索(十二)

        我們在編譯的時(shí)候,編譯器又報(bào)錯(cuò)了,說是找不到 func.h。我們的 func.h 文件在 inc 文件中放著,編譯器并不知道去這個(gè)文件夾下找,只是在當(dāng)前文件下進(jìn)行查找。現(xiàn)在就用到了我們上面說的為特定的編譯命令(gcc)獨(dú)立的指定編譯路徑。加上 CFLAGS := -I $(INC),并將 CFLAGS 變量加在 gcc 編譯的命令中。再來看看編譯結(jié)果

make 中的路徑搜索(十二)

        我們看到已經(jīng)正確編譯了,并且可執(zhí)行程序也完美運(yùn)行??此茊栴}完美的解決了,但其實(shí) VPATH 也存在一定的問題,當(dāng) inc 文件夾中意外出現(xiàn)源文件(c/cpp 文件),那么可能就會產(chǎn)生編譯錯(cuò)誤。我們?nèi)绻麑?func.c 誤放在 inc 文件夾中,這個(gè) func.c 文件中打印的是 this is from inc ... ,看看會發(fā)生什么

make 中的路徑搜索(十二)

        我們看到輸出的竟然會是 inc 文件中的 func.c 的內(nèi)容,按照預(yù)想應(yīng)該是 hello makefile 啊。那么這時(shí)的解決方案便是利用 vpath 關(guān)鍵字(全小寫),它是為不同類型的文件指定不同的搜索路徑。語法是在 Directory 中搜索符合 Pattern 的規(guī)則的格式,格式如下

make 中的路徑搜索(十二)

        我們再次用 vpath 來進(jìn)行設(shè)置,看看編譯結(jié)果是怎樣的

make 中的路徑搜索(十二)

        我們看到已經(jīng)正確實(shí)現(xiàn)了。那么既然有設(shè)置這個(gè)規(guī)則,是否也可以有取消此規(guī)則的設(shè)置呢?當(dāng)然有了。在進(jìn)行某個(gè)具體搜索規(guī)則的取消時(shí),是 vpath Pattern(如下圖);取消所有的設(shè)置規(guī)則時(shí),直接 vpath 即可

make 中的路徑搜索(十二)

        我們來試試,直接在下面加上 vpath %.h,代碼如下

OBJS := func.o main.o
INC := inc
SRC := src
CFLAGS := -I $(INC)

vpath %.h $(INC)
vpath %.c $(SRC)

hello.out : $(OBJS)
    @gcc -o $@ $^
    @echo "Target File ==> $@"

vpath %.h

$(OBJS) : %.o : %.c func.h
    @gcc $(CFLAGS) -o $@ -c $<

        編譯結(jié)果如下

make 中的路徑搜索(十二)

        我們看到編譯標(biāo)錯(cuò)了,說找不到 func.h 頭文件啦。當(dāng)然找不到了,我們?nèi)∠?.h 頭文件的搜索路徑了。

        下來我們來看看如果當(dāng) VPATH 和 vpath 同時(shí)出現(xiàn)時(shí),make 會如何處理呢?如下

make 中的路徑搜索(十二)

        下面的項(xiàng)目中,會選擇哪一個(gè)文件夾進(jìn)行編譯?

make 中的路徑搜索(十二)

        我們還是以代碼為例來進(jìn)行編譯看看

VPATH := src1
CFLAGS := -I inc

vpath %.c src2
vpath %.h inc

app.out : func.o main.o
    @gcc -o $@ $^
    @echo "Target File ==> $@"

$(OBJS) : %.o : %.c func.h
    @gcc $(CFLAGS) -o $@ -c $<

        編譯結(jié)果如下

make 中的路徑搜索(十二)

        我們看到它是按照 vpath 關(guān)鍵字指定的路徑下進(jìn)行編譯的。我們?nèi)绻麑?src2 文件夾中的 func.c 換成 func.cpp 呢,看看結(jié)果

make 中的路徑搜索(十二)

        我們看到:make 首先在當(dāng)前文件夾搜索需要的文件,如果失敗的話,make 優(yōu)先在 vpath 指定的文件夾中搜索目標(biāo)文件;當(dāng) vpath 搜索失敗時(shí),轉(zhuǎn)而搜索 VPATH 指定的文件夾。如下

make 中的路徑搜索(十二)

        下來我們看看當(dāng)使用 vpath 對同一個(gè) Pattern 指定多個(gè)文件夾時(shí),make 會如何處理?如下

make 中的路徑搜索(十二)

        下面的項(xiàng)目中,會選擇哪一個(gè)文件夾進(jìn)行編譯?

make 中的路徑搜索(十二)

        我們來編譯看看結(jié)果

make 中的路徑搜索(十二)

        我們看到編譯的是第一個(gè)文件夾 src1 。make 首先在當(dāng)前文件夾搜索需要的文件,如果失?。簃ake 以自上而下的順序搜索 vpath 指定的文件夾,當(dāng)找到目標(biāo)文件,搜索結(jié)束。如下

make 中的路徑搜索(十二)

        下面來看看通過 VPATH 指定搜索路徑后,make 如何決定目標(biāo)文件的最終位置?下面的項(xiàng)目中,會選擇哪一個(gè)文件夾進(jìn)行編譯?

make 中的路徑搜索(十二)

        我們來看看編譯結(jié)果

make 中的路徑搜索(十二)

        我們看到生成可執(zhí)行程序 app.out。并且成功運(yùn)行。下來我們將 app.out 放入 src 文件夾中,重新 make,編譯器應(yīng)該是重新生成一個(gè) app.out

make 中的路徑搜索(十二)

        它提示 app.out 是最新的,為什么沒有重新生成 app.out 呢?仔細(xì)分析下,在當(dāng)前文件夾下沒找到,但是編譯器不死心,繼續(xù)在 VPATH 變量指定的路徑下進(jìn)行尋找,終于在 src 文件夾下找到了 app.out,所以直接就不更新了。那么我們在 func.c 源文件中改變輸出的字符串為 hello D.T.Software 呢?看看結(jié)果

make 中的路徑搜索(十二)

        我們看到重新生成了一個(gè) app.out,在 src 文件夾下的 app.out 是沒有改變的。但是在當(dāng)前目錄下又重新生成了一個(gè) app.out 可執(zhí)行程序。當(dāng) app.out 完全不存在時(shí),make 在當(dāng)前文件下創(chuàng)建 app.out。當(dāng) src 文件夾下存在 app.out 時(shí),所有目標(biāo)和依賴的新舊關(guān)系不變,make 不會重新創(chuàng)建 app.out;當(dāng)依賴文件被更新,make 在當(dāng)前文件夾下創(chuàng)建 app.out。

        那么問題就來了,當(dāng)依賴改變時(shí),如何使得 src 下的 app.out 也被更新呢?解決方案便是使用 GPATH 特殊變量指定目標(biāo)文件夾;GPATH  := src ,當(dāng) app.out 完全不存在時(shí),make 默認(rèn)在當(dāng)前文件夾創(chuàng)建 app.out;當(dāng) app.out 存在于 src,且依賴文件被更新,make 在 src 中創(chuàng)建 app.out。下來還是以代碼為例來進(jìn)行說明

GPATH := src
PATH := src
CFLAGS := -I inc

app.out : func.o main.o
    @gcc -o $@ $^
    @echo "Target File ==> $@"

 %.o : %.c inc/func.h
    @gcc $(CFLAGS) -o $@ -c $<

        編譯結(jié)果如下        

make 中的路徑搜索(十二)

        在工程項(xiàng)目中:1、盡量使用 vpath 為不同文件指定搜索路徑;2、不要在源碼文件夾中生成目標(biāo)文件;3、為編譯得到的結(jié)果創(chuàng)建獨(dú)立的文件夾;4、避免 VPATH 和 GPATH 特殊變量的使用。 通過對 make 中的路徑搜索的學(xué)習(xí),總結(jié)如下:1、VPATH 變量用于指示 make 如何查找文件;2、make 會在 VPATH 指定的文件夾中依次搜索文件;3、vpath 關(guān)鍵字可以為不同類型的文件指定不同的搜索路徑;4、vpath 比 VPATH 更靈活易用,可動(dòng)態(tài)設(shè)置/取消搜索路徑。


        歡迎大家一起來學(xué)習(xí) makefile,可以加我QQ:243343083。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI