真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

makefile(05)_自動(dòng)生成依賴(lài)關(guān)系-創(chuàng)新互聯(lián)

11.自動(dòng)生成依賴(lài)關(guān)系_上

11.0. 實(shí)驗(yàn)原料

本節(jié)實(shí)驗(yàn)所需的源文件和頭文件:
原文件:func.c

成都創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括敘州網(wǎng)站建設(shè)、敘州網(wǎng)站制作、敘州網(wǎng)頁(yè)制作以及敘州網(wǎng)絡(luò)營(yíng)銷(xiāo)策劃等。多年來(lái),我們專(zhuān)注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,敘州網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶(hù)以成都為中心已經(jīng)輻射到敘州省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶(hù)的支持與信任!
#include "stdio.h"
#include "func.h"
void foo()
{
    printf("void foo() : %s\n", HELLO);
}

原文件:main.c

#include 
#include "func.h"
int main()
{
    foo();

    return 0;
}

頭文件func.c

#ifndef FUNC_H
#define FUNC_H

#define HELLO "Hello D.T."

void foo();

#endif

11.1.問(wèn)題和方案

問(wèn)題:

  1. 目標(biāo)文件.o是否只依賴(lài)于源文件.c?編譯器如何編譯源文件和頭文件?
    編譯器處理頭文件中的代碼直接插入源文件中,編譯器只通過(guò)預(yù)處理后的原文件產(chǎn)生目標(biāo)文件,因此,規(guī)則中以源文件為依賴(lài),命令可能無(wú)法執(zhí)行。
  2. 下面Makefile有沒(méi)有問(wèn)題?
    makefile(05)_自動(dòng)生成依賴(lài)關(guān)系
OBJS := func.o main.o

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

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

此時(shí)看似可以編譯成功,但存在潛在隱患。
存在問(wèn)題:目標(biāo)文件只依賴(lài)于.c文件,而沒(méi)有關(guān)注.h文件,這樣當(dāng).h文件的內(nèi)容更新時(shí),不會(huì)重新編譯.c文件。
解決方案:
我們將.h文件也作為依賴(lài)寫(xiě)到Makefile中。

OBJS := func.o main.o

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

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

上述解決方案問(wèn)題:
頭文件作為依賴(lài)出現(xiàn)于每一個(gè)目標(biāo)文件對(duì)應(yīng)的規(guī)則中,當(dāng)頭文件改動(dòng),任何源文件都會(huì)被重新編譯(編譯低效),而且當(dāng)項(xiàng)目中頭文件數(shù)量巨大時(shí),Makefile件很難維護(hù)。

11.2.實(shí)現(xiàn)自動(dòng)依賴(lài)

通過(guò)命令自動(dòng)生成對(duì)頭文件的依賴(lài),將生成的依賴(lài)自動(dòng)包含進(jìn)入Makefile中,當(dāng)頭文件改動(dòng)后,自動(dòng)確認(rèn)需要重新編譯的文件。
預(yù)備工作:
1.Linux命令sed,sed時(shí)一個(gè)流編輯器,用于流文本的修改(增、刪、查、改),文件替換,格式為:sed ‘s/abc/xyz/g’;
Sed可以支持正則表達(dá),sed ‘s/(.).o[ :]/objs/\1.o : /g’ 正則匹配目標(biāo)((.).o[ :]),替換值(objs/\1.o : )
2.編譯器選項(xiàng),生成依賴(lài)關(guān)系
gcc -MM 獲取目標(biāo)的完整依賴(lài)關(guān)系
gcc -M 獲取目標(biāo)的部分依賴(lài)關(guān)系
3.Makefile中目標(biāo)拆分技巧,將目標(biāo)的完整依賴(lài)拆分為多個(gè)部分依賴(lài)
makefile(05)_自動(dòng)生成依賴(lài)關(guān)系

.PHONY : test a b c

test : a b

test : b c

test : 
        @echo "$^"

輸出結(jié)果:a b c

思考:如果使用上面的預(yù)備工作實(shí)現(xiàn)頭文件的自動(dòng)依賴(lài)?

12.自動(dòng)生成依賴(lài)關(guān)系_中

12.1.Include

Make中的include關(guān)鍵字,類(lèi)似于C語(yǔ)言中的關(guān)鍵字,在處理是將所包含的文件的內(nèi)容原封不動(dòng)的搬到當(dāng)前文件。
語(yǔ)法:include filename
Eg: include foo.make *.mk $(var)
Make對(duì)include關(guān)鍵字的處理方式,在當(dāng)前目錄搜索或者指定目錄搜索目標(biāo)文件,搜索成功:將文件內(nèi)容搬入當(dāng)前Makefile中;搜索失敗,以文件名作為目標(biāo)查找并執(zhí)行對(duì)應(yīng)規(guī)則。當(dāng)文件名對(duì)應(yīng)的規(guī)則不存在時(shí),產(chǎn)生錯(cuò)誤。
下面的代碼怎么執(zhí)行,為什么?

.PHONY : all

include test.txt

all : 
    @echo "this is all"

test.txt :
    @echo "test.txt"
    @touch test.txt

初次執(zhí)行文件,自然搜索不到test.txt文件,然后會(huì)test.txt文件名作為目標(biāo)查找并執(zhí)行對(duì)應(yīng)規(guī)則,輸出結(jié)果:
makefile(05)_自動(dòng)生成依賴(lài)關(guān)系
注意:在include關(guān)鍵字前面加上-,可以消除警告。

12.2.命令執(zhí)行機(jī)制

1.Makefile中的命令執(zhí)行時(shí),每一條命令默認(rèn)都是一個(gè)新的進(jìn)程;(這樣當(dāng)我們希望使用上一個(gè)命令的執(zhí)行結(jié)果,繼續(xù)執(zhí)行命令時(shí)往往得不到結(jié)果,譬如下面的代碼);

.PHONY : all

all :
    set -e;
    mkdir test;
    cd test;
    mkdir subtest

輸出結(jié)果:
makefile(05)_自動(dòng)生成依賴(lài)關(guān)系
很顯然,沒(méi)有達(dá)到我們與其的目的(在test文件夾中創(chuàng)建subtest文件夾)
2.可以通過(guò)接續(xù)符(;)將多個(gè)命令組合成為一個(gè)命令,組合的命令一次在同一個(gè)進(jìn)程中被執(zhí)行;
3.可以使用set -e指定發(fā)生錯(cuò)誤時(shí)立即退出。

.PHONY : all

all :
        set -e; \
        mkdir test; \
        cd test; \
        mkdir subtest

輸出結(jié)果:
makefile(05)_自動(dòng)生成依賴(lài)關(guān)系

12.3.實(shí)現(xiàn)自動(dòng)生成依賴(lài)

1.通過(guò)gcc -MM 和sed命令得到.dep文件(目標(biāo)的部分依賴(lài)),并使用接續(xù)符使得命令可以連續(xù)執(zhí)行;
2.通過(guò)include指令包含所有的.dep依賴(lài)文件(當(dāng).dep文件不存在時(shí),查找與.dep文件同名的規(guī)則并執(zhí)行)

.PHONY : all clean

MKDIR := mkdir
RM := rm -fr
CC := gcc

SRCS := $(wildcard *.c)
DEPS := $(SRCS:.c=.dep)

-include $(DEPS)

all :
        @echo "all"

%.dep : %.c
        @echo "Creating $@ ..."
        @set -e; \
        $(CC) -MM -E $^ | sed 's,\(.*\)\.o[ :]*,objs/\1.o : ,g' > $@

clean :
        $(RM) $(DEPS)

輸出結(jié)果:
makefile(05)_自動(dòng)生成依賴(lài)關(guān)系
我們此時(shí)已經(jīng)成功的生成了依賴(lài)文件main.dep和func.dep并在文件中記錄了目標(biāo)和依賴(lài)的關(guān)系。
思考:如果組織依賴(lài)文件相關(guān)的規(guī)則與源碼編譯相關(guān)的規(guī)則,進(jìn)而形成功能完整的Makefile?

13.自動(dòng)生成依賴(lài)關(guān)系_下

13.1.遺留問(wèn)題

如何在makefile中組織.dep文件到指定目錄?
解決思路:
當(dāng)include 發(fā)現(xiàn).dep文件不存在時(shí),通過(guò)規(guī)則和命令創(chuàng)建deps文件夾,將所有的.dep文件創(chuàng)建到deps文件夾,并在.dep文件中記錄目標(biāo)文件的依賴(lài)關(guān)系。

$(DIR_DEPS) :
    $(MKDIR) $@

$(DIR_DEPS)/%.dep : $(DIR_DEPS)  %.c
    @echo "Creating $@ ..."
    @set -e; \
    $(CC) -MM -E  $^  | sed 's,\(.*\)\.o[ :]*,objs/\1.o : ,g' > $@

這樣做確實(shí)解決了上述問(wèn)題,生成了deps文件夾:
makefile(05)_自動(dòng)生成依賴(lài)關(guān)系
但同時(shí)我們看到兩個(gè)問(wèn)題:
1.因?yàn)橐蕾?lài)中包含deps文件夾,以deps文件夾作為 gcc -MM 的輸入時(shí)沒(méi)有意義的,會(huì)報(bào)告warning,所以使用下面的方法過(guò)濾掉deps文件夾

$(CC) -MM -E $(filter %.c, $^) | sed 's,\(.*\)\.o[ :]*,objs/\1.o : ,g' > $@

2.func.dep被重復(fù)創(chuàng)建了多次?
問(wèn)題本質(zhì)分析:
deps文件夾的時(shí)間屬性會(huì)因?yàn)橐蕾?lài)文件創(chuàng)建而發(fā)生改變,make發(fā)現(xiàn)deps文件夾比對(duì)于的目標(biāo)更新時(shí),會(huì)觸發(fā)相應(yīng)規(guī)則的重新解釋和命令的執(zhí)行。
解決方案:使用ifeq動(dòng)態(tài)決定.dep目標(biāo)的依賴(lài);

ifeq ("$(wildcard $(DIR_DEPS))", "")
$(DIR_DEPS)/%.dep : $(DIR_DEPS) %.c
else
$(DIR_DEPS)/%.dep : %.c
endif

13.2.Include黑暗操作

1.使用- 不但關(guān)閉了include發(fā)出的警告,同時(shí)關(guān)閉了錯(cuò)誤,當(dāng)發(fā)生錯(cuò)誤時(shí),make將忽略這些錯(cuò)誤。
2.如果include 觸發(fā)規(guī)則創(chuàng)建了文件則會(huì)發(fā)生下面的事情:

// 使用include 時(shí)的暗黑操作
if(如果目標(biāo)文件不存在)
{
    //以文件名為規(guī)則查找并執(zhí)行,
    if(查找到的規(guī)則中創(chuàng)建了文件)
    {
        //將創(chuàng)建成功的目標(biāo)文件包含進(jìn)當(dāng)前makefile
    }
}
else // 如果目標(biāo)文件存在
{
    // 將目標(biāo)文件包含進(jìn)當(dāng)前makefile
    if(以目標(biāo)文件名查找是否有相應(yīng)的規(guī)則)
    {
        if(比較規(guī)則的依賴(lài)關(guān)系,決定是否執(zhí)行規(guī)則的命令)
        {
            // (依賴(lài)文件更新,則執(zhí)行)
        }
        else
        {
            // 無(wú)操作
        }
    }
    else
    {
        // 無(wú)操作
    }
}

實(shí)驗(yàn)1:include包含的目標(biāo)文件不存在,并且以文件名為目標(biāo)的規(guī)則存在,并在規(guī)則中創(chuàng)建了文件

.PHONY : all

-include test.txt

all : 
    @echo "this is all"

test.txt :
    @echo "creating $@ ..."
    @echo "other : ; @echo "this is other" " > test.txt

我們期望了輸出結(jié)果因該是:this is all,因?yàn)閍ll是第一個(gè)(默認(rèn))目標(biāo)。
運(yùn)行結(jié)果:
makefile(05)_自動(dòng)生成依賴(lài)關(guān)系
原因在于當(dāng)出現(xiàn)上面的情況時(shí):以文件名為規(guī)則查找并執(zhí)行,同時(shí)如果查找到的規(guī)則中創(chuàng)建了文件,將創(chuàng)建成功的目標(biāo)文件包含進(jìn)當(dāng)前makefile,此時(shí)在makefile中第一個(gè)目標(biāo)變成了other
實(shí)驗(yàn)2:

.PHONY : all

-include test.txt

all : 
    @echo "this is all"

test.txt : b.txt
    @echo "creating $@ ..."

當(dāng)不存在b.txt時(shí)的運(yùn)行結(jié)果:
makefile(05)_自動(dòng)生成依賴(lài)關(guān)系
當(dāng)存在b.txt,但b.txt文件比test.txt文件舊時(shí)的運(yùn)行結(jié)果:
makefile(05)_自動(dòng)生成依賴(lài)關(guān)系
當(dāng)存在b.txt,但b.txt文件比test.txt文件新時(shí)的運(yùn)行結(jié)果:
makefile(05)_自動(dòng)生成依賴(lài)關(guān)系
結(jié)論:如果目標(biāo)文件存在:將目標(biāo)包含進(jìn)當(dāng)前makefile,以目標(biāo)文件名查找是否有相應(yīng)的規(guī)則
如果有則比較規(guī)則的依賴(lài)關(guān)系,決定是否執(zhí)行規(guī)則的命令(依賴(lài)文件更新,則執(zhí)行),如果規(guī)則中的命令更新了目標(biāo)文件,替換之前包含了的內(nèi)容。未更新,則無(wú)操作。
以目標(biāo)文件名查找是否有相應(yīng)的規(guī)則,不能找到,則無(wú)操作
實(shí)驗(yàn)3:

.PHONY : all

-include test.txt

all : 
    @echo "$@ : $^"

test.txt : b.txt
    @echo "creating $@ ..."
    @echo "all : c.txt" > test.txt

a.txt內(nèi)容:

all : a.txt

當(dāng)該文件中所需的所有文件都存在,并且test.txt的內(nèi)容為最新時(shí),make all輸出結(jié)果:
makefile(05)_自動(dòng)生成依賴(lài)關(guān)系
當(dāng)b.txt文件最新時(shí),make all輸出結(jié)果:
makefile(05)_自動(dòng)生成依賴(lài)關(guān)系

14.自動(dòng)生成依賴(lài)關(guān)系_續(xù)

經(jīng)過(guò)前面的技巧學(xué)習(xí),我們現(xiàn)可以去完成這個(gè)自動(dòng)生成依賴(lài)關(guān)系的想法了
注意:
思考:我們?cè)?3節(jié)中最終創(chuàng)建出來(lái)的makefile是否存在問(wèn)題?
當(dāng).dep文件生成后,如果動(dòng)態(tài)的改變文件間的依賴(lài)關(guān)系,那么make可能無(wú)法檢測(cè)到這個(gè)改變,進(jìn)而做出錯(cuò)誤的判斷。
實(shí)例:

輸出結(jié)果:

解決方案:
將依賴(lài)文件的文件名作為目標(biāo)加入自動(dòng)生成的依賴(lài)關(guān)系中,通過(guò)include加載依賴(lài)文件時(shí)判斷是否執(zhí)行規(guī)則,在規(guī)則執(zhí)行時(shí)重新生成依賴(lài)關(guān)系文件,最后加載新的依賴(lài)文件。
舉個(gè)栗子:當(dāng)我們前面編譯過(guò)之后(生成了依賴(lài)文件),又添加了新的頭文件,這時(shí)根據(jù)include的暗黑操作,要去檢查與include所包含的依賴(lài)文件同名的規(guī)則是否存在,如果存在,則檢查這個(gè)目標(biāo)所對(duì)應(yīng)的依賴(lài)是否被更新,如果更新,則執(zhí)行相應(yīng)規(guī)則。
最終方案:

.PHONY : all clean rebuild

MKDIR := mkdir
RM := rm -fr
CC := gcc

DIR_DEPS := deps
DIR_EXES := exes
DIR_OBJS := objs

DIRS := $(DIR_DEPS) $(DIR_EXES) $(DIR_OBJS)

EXE := app.out
EXE := $(addprefix $(DIR_EXES)/, $(EXE))

SRCS := $(wildcard *.c)
OBJS := $(SRCS:.c=.o)
OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
DEPS := $(SRCS:.c=.dep)
DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))

all : $(DIR_OBJS) $(DIR_EXES) $(EXE)

ifeq ("$(MAKECMDGOALS)", "all")
include $(DEPS)
endif

ifeq ("$(MAKECMDGOALS)", "")
include $(DEPS)
endif

$(EXE) : $(OBJS)
    $(CC) -o $@ $^
    @echo "Success! Target => $@"

$(DIR_OBJS)/%.o : %.c
    $(CC) -o $@ -c $(filter %.c, $^)
#   $(CC) -o $@ -c $(filter %.c, $^)

$(DIRS) :
    $(MKDIR) $@

ifeq ("$(wildcard $(DIR_DEPS))", "")
$(DIR_DEPS)/%.dep : $(DIR_DEPS) %.c
else
$(DIR_DEPS)/%.dep : %.c
endif
    @echo "Creating $@ ..."
    @set -e; \
    $(CC) -MM -E $(filter %.c, $^) | sed 's,\(.*\)\.o[ :]*,objs/\1.o $@ : ,g' > $@

clean :
    $(RM) $(DIRS)

rebuild :
    @$(MAKE) clean
    @$(MAKE) all

總結(jié):
Makefile中可以將目標(biāo)的依賴(lài)拆分寫(xiě)到不同的地方;
include關(guān)鍵字能夠觸發(fā)相應(yīng)的規(guī)則的執(zhí)行;
如果規(guī)則的執(zhí)行導(dǎo)致依賴(lài)更新,可能導(dǎo)致再次解釋執(zhí)行相應(yīng)的規(guī)則;
依賴(lài)文件可需要依賴(lài)源文件得到正確的編譯決策
自動(dòng)生成文件的依賴(lài)關(guān)系能夠提高M(jìn)akefile的移植性。

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)cdcxhl.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性?xún)r(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專(zhuān)為企業(yè)上云打造定制,能夠滿(mǎn)足用戶(hù)豐富、多元化的應(yīng)用場(chǎng)景需求。


網(wǎng)頁(yè)題目:makefile(05)_自動(dòng)生成依賴(lài)關(guān)系-創(chuàng)新互聯(lián)
分享地址:http://weahome.cn/article/dcsjcg.html

其他資訊

在線咨詢(xún)

微信咨詢(xún)

電話(huà)咨詢(xún)

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部