溫馨提示×

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

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

makefile(07)_路徑搜索

發(fā)布時(shí)間:2020-03-01 13:35:58 來源:網(wǎng)絡(luò) 閱讀:1969 作者:三九感冒靈 欄目:系統(tǒng)運(yùn)維

17.Make中的路徑搜索_上

17.0.實(shí)驗(yàn)素材

源文件位于: src目錄下
源文件:main.c

#include <stdio.h>
#include "func.h"

int main()
{
    foo();

    return 0;
}   

源文件:func.c

#include <stdio.h>
#include "func.h"

void foo()
{
    printf("void foo() : %s\n", "Hello, D.T.Software ...");
}

頭文件位于: inc目錄下
頭文件func.c

#ifndef FUNC_H
#define FUNC_H

void foo();

#endif

17.1. 工程源碼組織方式

問題:實(shí)際的工程項(xiàng)目中,所有的源文件和頭文件都放在一個(gè)文件夾嗎?
實(shí)際的工程中,源碼和頭文件都是按照模塊劃分的,舉例如下:
makefile(07)_路徑搜索
項(xiàng)目中的makefile必須能夠正確的定位源文件和依賴文件,最終編譯產(chǎn)生可執(zhí)行程序。
實(shí)驗(yàn)1:
當(dāng)源碼組織目錄如下時(shí),下面的makefile能夠編譯成功嗎?
makefile(07)_路徑搜索

OBJS := func.o main.o

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

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

編譯結(jié)果:
makefile(07)_路徑搜索
由于make默認(rèn)只會(huì)在makefile所在的文件家去查找源文件和頭文件,所以自然會(huì)導(dǎo)致編譯報(bào)錯(cuò)。

17.2. 預(yù)定義變量VPATH

VPATH變量的值用于指示make如何查找文件,不同文件夾可以作為VPATH的值同時(shí)出現(xiàn),可以使用空格,冒號(hào),分號(hào)這樣的分隔符進(jìn)行分隔,如VPATH := src inc
實(shí)驗(yàn)2:源碼目錄如下(注意這里存在兩個(gè)同名的C文件),下面的makefile編譯結(jié)果如何?
makefile(07)_路徑搜索

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 $<

編譯結(jié)果:
makefile(07)_路徑搜索
原因:VPATH只能決定make的搜索路徑,無法決定命令的搜索路徑,對(duì)特定編譯命令(gcc),需要獨(dú)立指定編譯搜索路徑。
makefile(07)_路徑搜索
修改makefile 內(nèi)容如下,再進(jìn)行實(shí)驗(yàn):

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

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

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

編譯和運(yùn)行結(jié)果:
makefile(07)_路徑搜索
此時(shí),我們看到編譯結(jié)果正確,但運(yùn)行后發(fā)現(xiàn)被編譯的時(shí)inc目錄下的func.c文件,這可能不是我們預(yù)期的。
原因:當(dāng)make在當(dāng)前文件夾找不到需要的文件時(shí),VPATH會(huì)被使用,make會(huì)在VPATH指定的文件夾中依次進(jìn)行搜索文件,當(dāng)多個(gè)文件夾存在同名文件時(shí),選擇第一次搜索到的文件。
實(shí)驗(yàn)3:
此時(shí),我們講源文件中的.c文件更名為.cpp文件,進(jìn)行上面的實(shí)驗(yàn)

當(dāng)inc文件夾意外出現(xiàn)文件(c/cpp文件),那么可能產(chǎn)生編譯錯(cuò)誤。

17.3. vpath關(guān)鍵字

為了解決上面的問題,我們使用vpath關(guān)鍵字,為不同類型的文件指定不同的搜索路徑
語法:eg : vpath %.h inc或者 vpath %.h src
取消搜索路徑:
取消已經(jīng)設(shè)置的某個(gè)所搜規(guī)則:vpath patten,
eg: vpath %.h inc # 在inc中搜索.h文件
vpath %.h # 不再inc中搜索.h文件
取消所有已經(jīng)設(shè)置的規(guī)則
vpath

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 $<

17.4. 總結(jié):

VPATH變量用于指示make如何查找文件,make會(huì)在VPATH指定的文件夾中依次搜索文件
vpath 關(guān)鍵字可以為不同類型的文件指定不同的搜索路徑,比VPATH更靈活易用,可動(dòng)態(tài)設(shè)置取消搜索路徑。

18.Make中的路徑搜索_下

18.1.VPATH和vpath同時(shí)使用

問題一:VPATH和vpath同時(shí)出現(xiàn)時(shí),make會(huì)如何處理?
makefile(07)_路徑搜索

VPATH := src1
CFLAGS := -I inc

vpath %.c src2
vpath %.h inc

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

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

實(shí)驗(yàn)結(jié)果:
makefile(07)_路徑搜索
實(shí)驗(yàn)結(jié)論:
make首先在當(dāng)前文件夾搜索需要的文件,如果失?。?br/>Make優(yōu)先在vpath指定的文件夾中搜索目標(biāo)文件
當(dāng)vpath搜索失敗時(shí),轉(zhuǎn)而搜索VPATH指定的文件夾

18.2.vpath對(duì)同一個(gè)patten指定多個(gè)文件夾

問題2:當(dāng)vpath對(duì)同一個(gè)patten指定多個(gè)文件夾時(shí),make會(huì)如何處理?
makefile(07)_路徑搜索

CFLAGS := -I inc

vpath %.c src1
vpath %.c src2

vpath %.h inc

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

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

實(shí)驗(yàn)結(jié)果:makefile(07)_路徑搜索
實(shí)驗(yàn)結(jié)論:當(dāng)vpath對(duì)同一個(gè)patten指定多個(gè)文件夾時(shí),make會(huì)依次自上而下,搜索指定的文件夾,直到找到目標(biāo)。

18.3.目標(biāo)文件位置

問題3:當(dāng)使用VPATH指定搜索路徑后,make如何確定最終目標(biāo)文件的位置?
下面的項(xiàng)目中,將如何生成可執(zhí)行程序?
makefile(07)_路徑搜索
實(shí)驗(yàn)結(jié)論:
當(dāng)app.out完全不存在,make會(huì)在當(dāng)前文件夾下創(chuàng)建app.out
當(dāng)src文件夾下存在app.out:
所有目標(biāo)和依賴的新舊關(guān)系不變,make不會(huì)重新創(chuàng)建app.out
當(dāng)依賴文件被更新,make在當(dāng)前文件夾下創(chuàng)建app.out
問題:當(dāng)依賴關(guān)系改變時(shí),如何使得src下的app.out被更新?

18.4.GPATH變量

上面問題,我們可以使用GPATH特殊變量指定目標(biāo)文件夾來解決。

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

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

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

當(dāng)app.out完全不存在,make默認(rèn)在當(dāng)前文件夾創(chuàng)建app.out
當(dāng)app.out存在于src,并且依賴文件被更新,make在src文件夾中創(chuàng)建目標(biāo)文件
18.5.工程建議:
盡量使用vpath為不同文件指定搜索路徑;
不要在源碼文件夾中生成目標(biāo)文件,為編譯得到的結(jié)果創(chuàng)建獨(dú)立文件夾
盡量避免使用VPATH如果一定要使用,考慮GPATH的使用

19.Make中的路徑搜索_綜合示例

19.1.需求分析

工程項(xiàng)目中不希望源文件夾在編譯時(shí)被改動(dòng)(只讀文件夾)
在編譯時(shí)自動(dòng)創(chuàng)建文件夾(build)用于存放編譯結(jié)果
編譯過程中國能夠自動(dòng)搜索到需要的文件
makefile易于擴(kuò)展,能夠復(fù)用相同類型的項(xiàng)目
支持調(diào)試版本和編譯選項(xiàng)

19.2.項(xiàng)目類型

makefile(07)_路徑搜索

19.3.工具原料:

$(wildcard $(DIR)/ _patten) 獲取$(DIR)文件夾中滿足_patten的文件
$(notdir _names) 去除_names中每一個(gè)文件名的路徑前綴
$(patsubst _patten, replacement, _text) 將_text中符合_patten的部分替換為replacement

19.4.關(guān)鍵技巧:

1.自動(dòng)獲取文件列表(函數(shù)調(diào)用)
SRSC := $(waidcard src/*.c)
2.根據(jù)源文件列表生成目標(biāo)文件列表(變量的替換)
OBJS := $(SRC:.c=.o)
3.替換每一個(gè)目標(biāo)文件的路徑前綴(函數(shù)調(diào)用)
OBJS := $(patsubst src/%, build/%, $(OBJS))

19.5.編譯文件的依賴

makefile(07)_路徑搜索

19.6.最終方案:

.PHONY : all clean

DIR_BUILD := build
DIR_SRC := src
DIR_INC := inc

TYPE_INC := .h
TYPE_SRC := .c
TYPE_OBJ := .o

CC := gcc
LFLAGS :=
CFLAGS := -I $(DIR_INC)
ifeq ($(DEBUG),true)
CFLAGS += -g
endif

MKDIR := mkdir
RM := rm -fr

APP := $(DIR_BUILD)/app.out
HDRS := $(wildcard $(DIR_INC)/*$(TYPE_INC))
HDRS := $(notdir $(HDRS))
OBJS := $(wildcard $(DIR_SRC)/*$(TYPE_SRC))
OBJS := $(OBJS:$(TYPE_SRC)=$(TYPE_OBJ))
OBJS := $(patsubst $(DIR_SRC)/%, $(DIR_BUILD)/%, $(OBJS))

vpath %$(TYPE_INC) $(DIR_INC)
vpath %$(TYPE_SRC) $(DIR_SRC)

all : $(DIR_BUILD) $(APP)
    @echo "Target File ==> $(APP)"

$(DIR_BUILD) :
    $(MKDIR) $@

$(APP) : $(OBJS)
    $(CC) $(LFLAGS) -o $@ $^

$(DIR_BUILD)/%$(TYPE_OBJ) : %$(TYPE_SRC) $(HDRS)
    $(CC) $(CFLAGS) -o $@ -c $<

clean :
    $(RM) $(DIR_BUILD)

問題:
對(duì)于規(guī)模較小的項(xiàng)目,makefile是否也需要使用自動(dòng)變量生成依賴關(guān)系的解決方案?
規(guī)模較小的項(xiàng)目沒必要使用自動(dòng)生成依賴關(guān)系的解決方案,可以直接讓源文件依賴于頭文件(易于維護(hù))

19.7.總結(jié):

工程項(xiàng)目中不希望源碼文件夾在編譯時(shí)被改動(dòng)
模式規(guī)則的靈活運(yùn)用使得makefile具有復(fù)用性
變量的靈活運(yùn)用使得makefile具有可擴(kuò)展性

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

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

AI