<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    jasmine214--love

    只有當你的內(nèi)心總是充滿快樂、美好的愿望和寧靜時,你才能擁有強壯的體魄和明朗、快樂或者寧靜的面容。
    posts - 731, comments - 60, trackbacks - 0, articles - 0

    .mk知識(Makefile文件)

    Posted on 2010-11-19 14:03 幻海藍夢 閱讀(18525) 評論(0)  編輯  收藏 所屬分類: Linux版本管理

    原文: http://www.chinaunix.net/jh/7/16880.html
    Make 程序最初設(shè)計是為了維護C程序文件防止不必要的重新編譯。在使用命令行編譯器的時 候,修改了一個工程中的頭文件,如何確保包含這個頭文件的所有文件都得到編譯?現(xiàn)在10機的版本生成是使用批處理程序,編譯那些文件依賴于程序的維護者, 在模塊之間相互引用頭文件的情況下,要將所有需要重新編譯的文件找出來是一件痛苦的事情;在找到這些文件之后,修改批處理進行編譯。實際上這些工作可以讓 make程序來自動完成,make工具對于維護一些具有相互依賴關(guān)系的文件特別有用,它對文件和命令的聯(lián)系(在文件改變時調(diào)用來更新其它文件的程序)提供 一套編碼方法。Make工具的基本概念類似于Proglog語言,你告訴make需要做什么,提供一些規(guī)則,make來完成剩下的工作。
    1簡介
    make 工作自動確定工程的哪部分需要重新編譯,執(zhí)行命令去編譯它們。雖然make多用于C程序,然而只要提供命令行的編譯器,你可以將其用于任何語言。實際 上,make工具的應(yīng)用范圍不僅于編程,你可以描述任和一些文件改變需要自動更新另一些文件的任務(wù)來使用它。
    1.1準備工作
    如果要使用 make,你必須寫一個叫做“makefile”的文件,這個文件描述工程中文件之間的關(guān)系,提供更新每個文件的命令。典型的工程是這樣的:可執(zhí)行文件靠 目標文件來更新,目標文件靠編譯源文件來更新。
    Makefile寫好之后,每次更改了源文件后,只要執(zhí)行make就足夠了,所有必要的重新編譯將 執(zhí)行。Make程序利用makefile中的數(shù)據(jù)庫和文件的最后修改時間來確定那個文件需要更新;對于需要更新的文件,make執(zhí)行數(shù)據(jù)庫中記錄的命令。
    可 以提供命令行參數(shù)給make來控制那個文件需要重新編譯。
    1.2Makefile介紹
    Makefile文件告訴make做什么,多數(shù)情況 是怎樣編譯和鏈接一個程序。
    這里有一個簡單的makefile,描述如何編譯鏈接由8個C文件和3個頭文件組成的一個編輯器:
    edit : main.o kbd.o command.o display.o \
         insert.o serach.o files.o utils.o
    cc –o edit main.o kbd.o command.o display.o \ 
              insert.o search.o files.o utils.o
    main.o : main.c defs.h
    cc –c main.c
    kdb.o : kbd.c defs.h command.h
    cc –c kbd.c
    command.o : command.c defs.h command.h
    cc -c command.c
    display.o : display.c defs.h buffer.h
    cc -c display.c
    insert.o : insert.c defs.h buffer.h
    cc -c insert.c
    search.o : search.c defs.h buffer.h
    cc -c search.c
    files.o : files.c defs.h buffer.h command.h
    cc -c files.c
    utils.o : utils.c defs.h
    cc -c utils.c
    clean :
    rm edit main.o kbd.o command.o display.o \
                   insert.o search.o files.o utils.o
    將 長行用\分開便于閱讀,這和使用一個長行的作用是一樣的。使用這個makefile創(chuàng)建可執(zhí)行文件“edit”時運行make就可以了;如果要將可執(zhí)行文 件和目標文件刪除,執(zhí)行make clean
    make重新編譯這個編輯器時,每個更改的C文件必須重新編譯;如果頭文件更改了,每個包含頭文件的 C文件必須重新編譯;每次編譯產(chǎn)生一個對應(yīng)于原文件的目標文件。最終,目標文件鏈接在一起產(chǎn)生新的可執(zhí)行文件。
    1.3規(guī)則簡介
    makefile 中的規(guī)則是這樣的:
    TARGET …  : DEPENDENCIES …
    COMMAND

    目標(TARGET)程序產(chǎn) 生的文件,如可執(zhí)行文件和目標文件;目標也可以是要執(zhí)行的動作,如“clean”。
    依賴(DEPENDENCIES)是用來產(chǎn)生目標的輸入文件, 一個目標通常依賴于多個文件。
    命令(COMMAND)是make執(zhí)行的動作,一個可以有多個命令,每個占一行。注意:每個命令行的起始字符必須為 TAB字符!
    有依賴關(guān)系規(guī)則中的命令通常在依賴文件變化時負責產(chǎn)生target文件,make執(zhí)行這些命令更新或產(chǎn)生target。規(guī)則可以沒有 依賴關(guān)系,如包含target “clean”的規(guī)則。
    規(guī)則解釋如何和何時重做該規(guī)則中的文件,make根據(jù)依賴關(guān)系執(zhí)行產(chǎn)生或更新目標;規(guī)則也 說明如何和何時執(zhí)行動作。有的規(guī)則看起來很復(fù)雜,但都符合上述模式。
    1.4make工作原理
    缺省make從第一個target開始(第一 個非 ’.’ 開始的target),這稱作缺省目標。在上述的makefile中,缺省目標是更新執(zhí)行程序’edit’,將這個目標置于最前面。當執(zhí)行 make的時候,make程序從當前目錄讀入makefile開始處理第一個規(guī)則;在例子中,這個規(guī)則是重新鏈接’edit’;在make處理這個規(guī)則之 前,必須處理’edit’所依賴的那些文件的規(guī)則,例子中是目標文件。這些文件按照他們自己的規(guī)則處理:通過編譯源文件來更新每個’.o’文件;當依賴關(guān) 系中的源文件或頭文件比目標文件新,或目標文件不存在時,必須重新編譯。
    其它的規(guī)則被處理是因為他們的target是目標的依賴,和目標沒有依賴 關(guān)系的規(guī)則不會被處理,除非指定make處理(如make clean)。
    在重新編譯目標文件之前,make會試圖更新它的依賴:源文件和頭文 件。例子中的makefile對源文件和頭文件未指定任何操作:’.c’和’.h’文件不是任何規(guī)則的目標。確認所有的目標文件都是最新的之后,make 決定是否重新鏈接’edit’:如果’edit’不存在,或者任何一個目標文件都比它新,則鏈接工作將進行。
    這樣,如果我們改變insert.c 運行make,make會編譯這個文件來更新’insert.o’,然后鏈接’edit’;如果修改了’command.h’運行 make,’kbd.o’,’command.o’,’files.o’會重新生成,鏈接’edit’。
    1.5使用變量
    在例子中,在規(guī) 則’edit’中,目標文件被列出來兩次:
    edit : main.o kbd.o command.o display.o \
                   insert.o search.o files.o utils.o
    cc -o edit main.o kbd.o command.o display.o \
                        insert.o search.o files.o utils.o
    這 樣的重復(fù)容易出錯:假設(shè)工程中加入了一個新的目標文件,可能只將其加入了一個列表中;通過使用變量可以消除這種風險:變量允許一個預(yù)定義的字符串在多個地 方被替換。
    在makefile中,可以寫這樣一行來定義’object’變量:
    objects = main.o kbd.o command.o display.o \
               insert.o search.o files.o utils.o
    于 是在需要目標文件名列表的地方,使用$(object) 來代替變量的值。以下是使用了變量以后的makefile:
    objects = main.o kbd.o command.o display.o \
         insert.o search.o files.o utils.o
    edit : $(objects)
    cc -o edit $(objects)
    main.o : main.c defs.h
    cc -c main.c
    kbd.o : kbd.c defs.h command.h
    cc -c kbd.c
    command.o : command.c defs.h command.h
    cc -c command.c
    display.o : display.c defs.h buffer.h
    cc -c display.c
    insert.o : insert.c defs.h buffer.h
    cc -c insert.c
    search.o : search.c defs.h buffer.h
    cc -c search.c
    files.o : files.c defs.h buffer.h command.h
    cc -c files.c
    utils.o : utils.c defs.h
    cc -c utils.c
    clean :
    rm edit $(objects)
    1.6 簡化命令
    為每個文件寫出編譯命令不是必要的,因為make可以自己來做;以’.c’文件更新’.o’文件有一個隱含的規(guī)則,使用’cc -c’命 令。Make將利用’cc –c main.c –o main.o’來將main.c編譯為main.o,因此在生成目標文件的規(guī)則中,可以省略命令。
    當’.c’ 文件以這樣的方式使用時,將自動加入到依賴關(guān)系中;由是在省略命令的前提下,可以將’.c’文件從依賴關(guān)系中省略。以下是簡化過的makefile:
    objects = main.o kbd.o command.o display.o \
              insert.o search.o files.o utils.o

    edit : $(objects)
            cc -o edit $(objects)

    main.o : defs.h
    kbd.o : defs.h command.h
    command.o : defs.h command.h
    display.o : defs.h buffer.h
    insert.o : defs.h buffer.h
    search.o : defs.h buffer.h
    files.o : defs.h buffer.h command.h
    utils.o : defs.h
    .PHONY : clean
    clean :
            -rm edit $(objects)
    1.7 另一種風格
    如果makefile中的目標都是以隱含規(guī)則生成,可以將規(guī)則按照依賴關(guān)系分組:
    objects = main.o kbd.o command.o display.o \
              insert.o search.o files.o utils.o

    edit : $(objects)
            cc -o edit $(objects)

    $(objects) : defs.h
    kbd.o command.o files.o : command.h
    display.o insert.o search.o files.o : buffer.h
    這 里’defs.h’作為所有目標文件的依賴。這種風格是好是壞取決于個人喜好,它非常緊湊,但是將每個目標的依賴信息放在一起看起來更清楚一些。
    1.8 清理
    編寫規(guī)則不至于編譯程序。Makefile通常描述如何做其它事情:比如刪除目錄中的目標文件和可執(zhí)行文件來清理目錄。例子中是這樣寫的:
    clean:
            rm edit $(objects)
    實 際情況是,我們需要處理一些意外事件:存在一個叫做’clean’的文件;如果rm出錯,并不希望make過程停止下來,修改過的版本如下:
    .PHONY : clean
    clean :
            -rm edit $(objects)
    這 樣的規(guī)則當然不能放在makefile的開始,因為這并不是我們?nèi)笔∫龅墓ぷ鳌S捎?#8217;clean’并不是’edit’的依賴,在運行make時沒有參數(shù) 時,這條規(guī)則不會執(zhí)行;要執(zhí)行這個規(guī)則,必須運行’make clean’。
    2Makefile
    Makefile中包含五種內(nèi)容:顯式規(guī) 則,隱式規(guī)則,變量定義,指令(directive)和注釋。
    ;顯式規(guī)則描述如何生成規(guī)則的目標,它列出 了目標依賴的文件,指定了產(chǎn)生或更新目標的命令
    ;隱式規(guī)則描述如何生成基于文件名的一類文件,說明目標可 能依賴于和其文件名類似的文件,指定了相應(yīng)的命令。
    ;指令類似與編譯器的偽指令,包含:
    ; 指示make讀入另一個makefile
    ;決定是否忽略makefile中的一部分
    ; 定義一個變量
    ;一行中‘#’開始是注釋,直到行末,除非遇到續(xù)行符號。在’define’和命令中不能有 注釋,其它情況下注釋可出現(xiàn)在任何地方。
    2.1makefile名字
    缺省情況下,make以下列名字查找 makefile:’GNUmakefile’,’makefile’和’Makefile’(注意大小寫)。通常你的makefile應(yīng)叫 做’makefile’或’Makefile’。’GNUmakefile’不推薦,除非你的makefile是為GNU的make定制的,其它的 make不認為該名字是一個makefile的名字。
    如果你使用非標準命名的makefile,必須用命令開關(guān)’-f ’ 或 ’—file’。 參數(shù)’ –f NAME’或’—file NAME’告訴make讀入NAME作為makefile。如果使用多個該開關(guān),所有的文件將按順序連接起來。 如果使用該選項,標準的makefile名字不會自動檢測。
    2.2包含
    ‘include’指令告訴make暫停處理余下的內(nèi)容,讀入其它 makefile。語法如下:
    include FILENAMES …
    這一行起始可以有空格,但TAB字符不允許。如果文件名包含變量或 函數(shù),這些將被擴展。
    2.3‘MAKEFILE’變量
    如果環(huán)境變量’MAKEFILE’已定義,make認為它的值是一系列空格隔開的文 件名,這些文件在處理其它makefile前被make程序讀入。這類似于include指令;這些文件中的目標不會影響缺省目標,而且如果文件未找到的 話,make并不認為是錯誤。
    這個變量的主要用途是遞歸引用make程序時通訊
    2.4如何重新生成makefile
    有時候 makefile是從其它文件生成的,比如RCS或SCCS文件。如果makefile是由其它文件生成的,需要make讀入最新版本的 makefile。
    在讀入所有makefile之后,make認為每個makefile是一個目標,試圖去更新它;如果makefile中有一條 如何更新它的規(guī)則,或者有適用的隱式規(guī)則,需要的更新會進行。所有的makefile檢查完之后,如果有的改變了,make重新開始再讀入(make會試 圖再做更新,但通常不會再改變了,因為已經(jīng)是最新的了)。
    如果一個文件使用雙冒號規(guī)則,提供了命令但沒有依賴關(guān)系,文件始終會被更新。在 makefile的情況下,如果makefile雙冒號規(guī)則,提供了命令但沒有依賴關(guān)系,這樣makefile始終會重新生成,這會導(dǎo)致循環(huán):make只 是在不斷更新makefile,卻不干活。為避免這種情況,make不會重新生成那些只有命令沒有依賴關(guān)系的雙冒號規(guī)則的makefile。
    如果 沒有使用’-f’或’--file’選項,make會嘗試缺省的makefile文件名。和指明’-f’或’--file’選項不同,make不能確定這 些文件是否應(yīng)當存在。然而,如果缺省makefile不存在但可以通過運行make規(guī)則生成,你可能希望這些規(guī)則被運行使得makefile可以使用。
    因 此,如果沒有缺省makefile,make試圖按照makefile名查找的順序生成它,直到成功或名字用完。注意如果make 不能找到或生成 makefile,這并不是錯誤;makefile不總是必需的。
    當使用’-t’或’--touch’選項時,不希望使用過時的makefile 來決定那個目標來touch。所以’-t’選項對makefile更新不起作用;類似’-q’(or ‘—question’)和’-n’(or ’— just-print’)不阻止makefile的更新,因為過時的makefile會產(chǎn)生錯誤的輸出。這 樣’make –f mfile –n foo’會更新’mfile’,讀入它,打印出更新’foo’需要執(zhí)行的命令但不運行這些命令。與’foo’有關(guān) 的命令是更新過的’mfile’中的內(nèi)容。
    但是有時不希望更新makefile,可以將makefile作為命令行的目標,當makefile被 顯式指定為目標時,’-t’選項也適用于它們。
    這樣’make –f mfile –n mfile foo’會讀入’mfile’,打印出更新 執(zhí)行的命令,’foo’的命令是當前的’mfile’中的內(nèi)容。
    2.5重載makefile
    可以使用’include’指令來包含其它 makefile,增加目標的變量定義。然而,make不允許同一個目標有不同的命令,有其它的途徑可以達到目的。
    假設(shè) 有’makefile’ 和’mfile’,’makfile’要包含’mfile’,但都有對于目標’foo’的規(guī)則。這是可以在’makefile’ 中寫一條匹配任意模式的規(guī)則,指明當make在’makefile’中未找到目標時,搜索’mfile’:
    foo:
             frobnicate >; foo
    %: force
             @$(MAKE) -f mfile $@
     force: ;
    當 執(zhí)行’make foo’時,make找到’makefile’,執(zhí)行命令’ frobnicate >; foo’;執(zhí)行’make bar’ 時,在’makefile’中未找到相應(yīng)的規(guī)則,這時模式規(guī)則適用,執(zhí)行命令’make –f mfile bar’,’makefile’中未提及的其 它目標也是類似的。
    這種方法之所有工作是因為模式規(guī)則的模式是’%’,可以匹配任何的目標;這條規(guī)則的依賴是’force’,保證即使目標存在命 令也會執(zhí)行;’force’規(guī)則的命令為空防止’make’為其搜索隱式規(guī)則-這樣會導(dǎo)致依賴循環(huán)。
    3規(guī)則
    makefile中的規(guī)則描述 如何生成特定的文件,即規(guī)則的目標。規(guī)則列出了目標的依賴文件,指定生成或更新目標的命令。
    規(guī)則的次序是不重要的,除非是確定缺省目標:缺省目標 是第一個makefile中的第一個規(guī)則;如果第一個規(guī)則有多個目標,第一個目標是缺省的。有兩個例外:以’.’開頭的目標不是缺省目標;模式規(guī)則對缺省 目標沒有影響。
    通常我們所寫的地一個規(guī)則是編譯整個或makefile中指定的所有程序。
    3.1例子
    foo.o : foo.c defs.h       # module for twiddling the frobs
    cc -c -g foo.c
    它 的目標是’foo.o’,依賴于’foo.c’和’defs.h’,有一個命令’cc –c –g foo.c’。命令行以TAB字符開始標識它是一個命 令。
    這條規(guī)則說明兩件事:
    ;如何決定’foo.o’是舊的:如果它不存在,或者’foo.c’或 者’defs.h’比它新。
    ;如何更新’foo.o’文件:通過運行’cc’程序。命令未提 及’defs.h’,擔可以猜想’foo.c’包含了它,這是’defs.h’被置于依賴關(guān)系中的理由。
    3.2規(guī)則的語法
    語法如下:
    TARGETS : DEPENDENCIES
    COMMAND
    ...
    或 者
    TARGETS : DEPENDENCIES ; COMMAND
    COMMAND
    ...
    TARGETS 是以空格隔開的文件名,統(tǒng)配符可以使用。通常一個規(guī)則只有一個目標,偶爾也有多個。
    命令行以TAB鍵開始。第一條命令可在依賴關(guān)系的下一行;或者 在同一行,在分號后面;兩種方式效果相同。
    因為’$’符號被用做變量引用,如果要在規(guī)則中使用’$’符號,必須寫兩個:’$$’。可以用’\’符 號來分割一個長行,這不是必須的,因為make對行的長度沒有限制。
    3.3通配符
    規(guī)則中的文件名可以包含統(tǒng)配符,如’*’,’?’。
    文 件名前的字符’~’有特殊的含義。單獨使用,或跟隨一個’/’,代表用戶的home目錄,比如’~/bin’擴展為/home/you/bin’;如 果’~’跟隨一個單詞,表示單詞指示的那個用戶的home目錄,如’~john/bin’擴展為’/home/john/bin’。
    通配符在目 標,依賴關(guān)系,命令中自動擴展,其它情況下,統(tǒng)配符的擴展除非顯式使用’wildcard’函數(shù)。通配符的特殊意義可以使用’\’符號關(guān)閉。
    例 子:
    clean:
            rm -f *.o

    print: *.c
        lpr -p $?
            touch print
    通 配符在定義變量時并不擴展,例如:
    objects = *.o
    則objects的值是字符串’*.o’;但是如果你將objects用于 目標,依賴或命令中,擴展會進行。要將objects設(shè)置成擴展過的內(nèi)容,使用:
    objects := $(wildcard *.o)
    3.3.1 通配符的缺陷
    這是一個使用通配符的例子,但結(jié)果不是你所期望的。假設(shè)可執(zhí)行文件’foo’是從當前目錄中的所有’.o’文件生成的:
    objects = *.o

    foo : $(objects)
            cc -o foo $(CFLAGS) $(objects)
    objects 變量的值是字符串’*.o’。通配符擴展在規(guī)則’foo’中進行,于是所有存在的’.o’文件成為’foo’的依賴而且在需要時重新編譯。
    但如果 刪除了所有的’.o’文件呢?當通配符不匹配任何文件時,一切都保持原樣:則’foo’依賴于一個叫做’*.o’的文件;由于這個文件不大可能存 在,’make’程序會報告一個無法生成’*.o’文件的錯誤,這不是期待的結(jié)果。
    實際上可以用通配符獲得期望結(jié)果,但是需要復(fù)雜的技術(shù),包 括’wildcard’函數(shù)和字符串替換函數(shù)。
    3.3.2wildcard函數(shù)
    通配符自動在規(guī)則中進行。但是在變量賦值的和函數(shù)的參數(shù)中 通配符不會擴展,如果在這些情況下需要通配符擴展,必須使用’wildcard’函數(shù)。語法如下:
    $(wildcard PATTERN...)
    這 個在makefile任何地方出現(xiàn)的字符串,會被匹配任何一個文件名格式的以空格隔開的現(xiàn)有文件列表替換。如果沒有任何文件匹配一個模式,這個模式 從’wildcard’的輸出中忽略,注意,這和上述的通配符的處理是不一樣的。
    ‘wildcard’函數(shù)的一個功能是找出目錄中所有的’.c’ 文件:
    $(wildcard *.c)
    可以通過替換后綴’.c’為’.o’從C文件列表得到目標文件的列表:
    $(patsubst %.c,%.o,$(wildcard *.c))
    這 樣,上節(jié)中的makefile改寫為:
    objects := $(patsubst %.c,%.o,$(wildcard *.c))

    foo : $(objects)
            cc -o foo $(objects)
    這 個makefile利用了編譯C程序的隱含規(guī)則,所以不需要對編譯寫出顯式的規(guī)則。(’:=’是’=’的一個變體)
    注意:’PATTERN’是大 小寫敏感的。
    3.4目錄搜索
    對于大的系統(tǒng),通常將源文件和目標文件放在不同的目錄中。目錄搜索功能可以讓make自動在多個目錄中搜尋依 賴文件,當你將文件重新分布是,不需要改變規(guī)則,更改搜索路徑即可。
    3.4.1‘VPATH’
    make變量’VPATH’列出make應(yīng) 當搜索的目錄列表。很多情況下,當前目錄不包含依賴文件,’VPATH’描述一個對所有文件的搜索列表,包含那些是規(guī)則的目標的文件。
    如果一個目 標或者依賴文件在當前目錄沒找到的話,’make’在’VPATH’中列出的目錄中查找同名的文件。如果找到的話,那個文件成為依賴文件;規(guī)則可以象這些 文件在當前目錄中一樣來使用他們。
    在’VPATH’變量中,目錄名以冒號或空格隔開;目錄列出的順序決定make查找的順序。(注:在 pSOSystem 2.5移植到Win32的GNU make目錄名必須使用分號隔開,以下均簡稱Win32 GNU make)。舉例說明:

    VPATH = src:../headers  則 規(guī)則
    foo.o : foo.c 
    被解釋為
    foo.o : src/foo.c
    假設(shè)’foo.c’在當前目錄不存在, 在’src’目錄中可以找到。
    3.4.2選擇性搜索
    與’VPATH’變量相似但更具選擇性的是’vpath’指令(注意是小寫),可以指 定對于符合特定模式文件的查找路徑。這樣可以為不同類型的文件指定不同的搜索路徑。
    ‘vpath’指令共有三中形式:
    ;‘vpath PATTERN DIRECTORIES’
    為 匹配PATTERN的文件名指定搜索路徑DIRECTORIES,目錄的分隔和’VPATH’的相同
    ;‘vpath PATTERN’
    清 除為匹配PATTERN的文件名指定的搜索路徑
    ;‘vpath’
    清除所有以前用’vpath’指 定的搜索路徑
    ‘vpath’的模式是包含’%’的字符串:這個字符串必須匹配需要搜索的依賴文件名,’%’字符匹配0個或多個任意字符。例 如:’%.h’匹配任何以’.h’結(jié)尾的文件(如果沒有%,則PATTERN必須和依賴文件完全一致,這種用法不太多)。
    當當前目錄中不存在依賴 文件時,如果’vpath’中的PATTERN匹配依賴文件名,則指令中DIRECTORIES列出的目錄和’VPATH’中同樣處理。舉例:
    vpath  %.h   ../headers
    告 訴make在當前目錄中未找到的’.h’文件在../headers目錄中查找。
    如果多個’vapth’的模式匹配依賴文件名,make將逐一處 理,在所有指定的目錄中搜索。Make按照’vapth’在makefile中的次序;來處理它們,多個相同模式的’vapth’是相互獨立的。
    vpath  %.c  foo
    vpath  %   blish
    vpath  %.c  bar
    將 按照’foo’,‘blish’,’bar’的次序查找’.c’文件。而
    vpath  %.c  foo:bar
    vpath  %   blish
    按 照’foo’,’bar’,’blish’的順序搜索。
    3.4.3使用自動變量
    目錄搜索的結(jié)果并不改變規(guī)則中的命令:命令按原樣被執(zhí)行。 因此,必須寫出與目錄搜索功相適應(yīng)的命令。這可以通過使用’$^’這樣的自動變量來完成。’$^’表示規(guī)則中的所有依賴文件,包含它們所在的目錄名(參見 目錄搜索);’$@’表示目標。例如:
    foo.o  :  foo.c
    cc  -c  $(CFLAGS)  $^  -o  $@
    通 常情況下,依賴文件也包含頭文件,但命令中并不提及這些文件:變量’$<’表示第一個依賴文件:
    VPATH = src:../headers
    foo.o  : foo.c  defs.h  hack.h
    cc –c $(CFLAGS)  $<  -o $@
    3.4.4 目錄搜索和隱含規(guī)則
    使用’VPATH’和’vpath’指定目錄搜索也會影響隱含規(guī)則。例如:文件’foo.o’沒有顯式規(guī)則,make會考慮隱 式規(guī)則:如果’foo.c’存在則編譯它;如果這個文件不存在,則在相應(yīng)的目錄中查找;如果’foo.c’在任一的目錄中存在,則C編譯的隱式規(guī)則被應(yīng) 用。
    隱式規(guī)則的命令使用自動變量通常是必要的,這樣無需其它努力即可以使用目錄搜索得到的文件名。
    3.5PHONY目標
    Phony 目標并非實際的文件名:只是在顯式請求時執(zhí)行命令的名字。有兩種理由需要使用phony目標:避免和同名文件沖突,改善性能。
    如果編寫一個規(guī)則, 并不產(chǎn)生目標文件,則其命令在每次make該目標時都執(zhí)行。例如:
    clean:
    rm  *.o  temp
    因為’rm’命令并不 產(chǎn)生’clean’文件,則每次執(zhí)行’make clean’的時候,該命令都會執(zhí)行。如果目錄中出現(xiàn)了’clean’文件,則規(guī)則失效了:沒有依賴文 件,文件’clean’始終是最新的,命令永遠不會執(zhí)行;為避免這個問題,可使用’.PHONY’指明該目標。如:
    .PHONY : clean
    這 樣執(zhí)行’make clean’會無視’clean’文件存在與否。
    已知phony目標并非是由其它文件生成的實際文件,make會跳過隱含規(guī)則 搜索。這就是聲明phony目標會改善性能的原因,即使你并不擔心實際文件存在與否。完整的例子如下:
    .PHONY : clean
    clean :
    rm  *.o  temp
    phony 目標不應(yīng)是真正目標文件的依賴。如果這樣,每次make在更新此文件時,命令都會執(zhí)行。只要phony目標不是真正目標的依賴,規(guī)則的命令只有在指定此目 標時才執(zhí)行。
    Phony目標可以有依賴關(guān)系。當一個目錄中有多個程序是,將其放在一個makefile中會更方便。因為缺省目標是 makefile中的第一個目標,通常將這個phony目標叫做’all’,其依賴文件為各個程序:
    all : prog1  prog2  prog3
    .PHONY : all
    prog1 : prog1.o utils.o
            cc -o prog1 prog1.o utils.o
    prog2 : prog2.o
            cc -o prog2 prog2.o
    prog3 : prog3.o sort.o utils.o
            cc -o prog3 prog3.o sort.o utils.o
    這 樣,使用’make’將可以將三個程序都生成了。
    當一個phony目標是另一個的依賴,其作用相當于子程序,例如:
    .PHONY: cleanall cleanobj cleandiff
    cleanall : cleanobj cleandiff
            rm program
    cleanobj :
            rm *.o
    cleandiff :
            rm *.diff
    3.6FORCE 目標
    當規(guī)則沒有依賴關(guān)系也沒有命令,而且其目標不是存在的文件名,make認為此規(guī)則運行時這個目標總是被更新。這意味著如果規(guī)則依賴于此目標, 其命令總是被執(zhí)行。
    clean: FORCE
            rm $(objects)
    FORCE:
    例中目 標’FORCE’滿足這種特殊條件,這樣依賴于它的目標’clean’被強制執(zhí)行其命令。名字’FORCE’沒有特殊含義,只不過通常這樣用而已。這種方 式使用’FORCE’和’.PHONY : clean’效果相同。使用’.PHONY’更加明確高效,擔不是所有的’make’都支持;這樣許多 makefile中使用了’FORCE’。
    3.7空目標
    空目標(empty target)是phony目標的變種:用來執(zhí)行顯式請求的 一個動作。和phony目標不同的是:這個目標文件可以真實存在,擔文件的內(nèi)容無關(guān)緊要,通常是空的。空目標文件的目的是利用其最后修改時間來記錄命令最 近一次執(zhí)行的時間,這是通過使用’touch’命令更新目標文件來達到的。
    print: foo.c bar.c
            lpr -p $?
            touch print
    利 用這條規(guī)則,執(zhí)行’make print’時如果自上次’make print’之后任一文件改變了,’lpr’命令會執(zhí)行。自動變量’$?’是為了只打 印出那些變化了的文件。
    3.8內(nèi)建的特殊目標
    某些名字作為目標存在時有特殊含義。
    ★.PHONY該目標的依賴被認為是phony 目標,處理這些目標時,命令無條件被執(zhí)行,不管文件名是否存在及其最后修改時間
    ★.SUFFIXES該目標的依賴被認為是一個后綴列表,在檢查后 綴規(guī)則時使用
    ★.DEFAULT該目標的規(guī)則被使用在沒有規(guī)則(顯式的或隱含的)的目標上。如果’DEFAULT’命令定義了,則對所有不是規(guī)則 目標的依賴文件都會執(zhí)行該組命令
    ★.PRECIOUS該目標的依賴文件會受到特別對待:如果make被kill或命令的執(zhí)行被中止,這些目標并不 刪除;而且如果該目標是中間文件,在不需要時不會被刪除。可以將隱含規(guī)則的目標模式(如%.o)做為’.PRECIOUS’的依賴文件,這樣可以保存這些 規(guī)則產(chǎn)生的中間文件。
    ★.INTERMEDIATE該目標的依賴文件被當作中間文件;如果該目標沒有依賴文件,則makefile中所有的目標文 件均被認為是中間文件。
    ★.IGNORE在執(zhí)行該目標的依賴規(guī)則的命令時,make會忽略錯誤,此規(guī)則本身的命令沒有意義。如果該規(guī)則沒有依賴關(guān) 系,表示忽略所有命令執(zhí)行的錯誤,這種用法只是為了向后兼容;由于會影響到所有的命令,所以不是特別有用,推薦使用其它更有選擇性忽略錯誤的方法。
    ★.SILENT 在執(zhí)行該目標的依賴規(guī)則的命令時,make并不打印命令本身。該規(guī)則的命令沒有意義。在’.SILIENT’沒有依賴關(guān)系時,表示執(zhí)行makefile中 的所有命令都不會打印,該規(guī)則只是為了向后兼容提供的。
    ★.EXPORT_ALL_VARIABLES只是作為一個目標存在,指示make將所有 變量輸出到子進程中。
    定義的隱含規(guī)則的后綴作為目標時,也認為它是特殊目標;兩個后綴的連接也是一樣,比如’.c.o’。這些目標是后綴規(guī)則,一 中定義隱式規(guī)則的過時方法(但仍然廣泛使用)。后綴通常以’.’開始,所以特殊目標也以’.’開始。
    3.9一個規(guī)則多個目標
    一條有多個目 標的規(guī)則和寫多條規(guī)則,每條一個目標作用是等同的。同樣的命令應(yīng)用于所有目標,但其效用會因?qū)嶋H目標以’$@’代替而不同。規(guī)則中所有目標的依賴關(guān)系是 一樣的。
    這在兩種情況下有用:
    ★只有依賴關(guān)系,不需要命令。例如:
    kbd.o command.o files.o: command.h
    ★ 所有的目標同樣的命令。命令不需要完全相同,因為在命令中可以使用’$@’:
    bigoutput littleoutput : text.g
            generate text.g -$(subst output,,$@) >; $@

    bigoutput : text.g
        generate text.g -big >; bigoutput
    littleoutput : text.g
        generate text.g -little >; littleoutput
    等 同。這里假設(shè)程序’generate’產(chǎn)生兩種輸出:一種使用’-big’選項,一種使用’-little’選項。如果想象使用’$@’變化命令那樣來變 化依賴關(guān)系,不能通過多目標的普通規(guī)則實現(xiàn),但是可以通過模式規(guī)則來實現(xiàn)。
    3.10一個目標多條規(guī)則
    一個文件可以是多條規(guī)則的目標,所有 規(guī)則的依賴關(guān)系被合并。如果目標比任一個依賴文件舊,命令被執(zhí)行。
    一個文件只能有一組命令執(zhí)行。如果多個規(guī)則對于同一個文件都給出了命 令,make使用最后一組并打印錯誤信息(特殊情況:如果文件名以’.’開始,并不打印錯誤信息,這一點是為了和其它make兼容)。沒有任何理由需要將 makefile寫成這樣,這是make給出錯誤信息的理由。
    一條只有依賴關(guān)系的附加規(guī)則可以一次給出許多文件的附加依賴文件。例 如’objects’變量表示系統(tǒng)中編譯器的所有輸出.,說明當’config.h’更改時所有文件必須重做的簡單方法如下:
     objects = foo.o bar.o
     foo.o : defs.h
     bar.o : defs.h test.h
     $(objects) : config.h
    不 用改變實際目標文件生成的規(guī)則,這條規(guī)則可以在需要增刪附加的依賴關(guān)系時插入或提出。另一個訣竅是附加的依賴關(guān)系可以用變量表示,在make執(zhí)行時,可以 給變量賦值:
    extradeps=
    $(objects) : $(extradeps)
    當命令 `make extradeps=foo.h'執(zhí)行時會認為’foo.h’是每個目標文件的依賴文件,但簡單的’make’命令不是這樣。
    3.11 靜態(tài)模式規(guī)則
    靜態(tài)模式規(guī)則(static pattern rules)可以指定多個目標,并且使用目標名字來建議依賴文件的名字;比普通多目標 規(guī)則更通用因為不需要依賴關(guān)系是相同的:依賴關(guān)系必須類似但不需要相同。
    3.11.1語法
    TARGETS ...: TARGET-PATTERN: DEP-PATTERNS ...
            COMMANDS
            ...
    TARGETS 列表指出規(guī)則應(yīng)用的目標,可以包含通配符,于普通規(guī)則的目標相同。TARGET-PATTERN和DEP-PATTERNS來表明目標的依賴關(guān)系如何計 算:匹配TARGET-PATTERN的目標從名字中抽出一部分,叫做詞干(stem),詞干被替換到DEP-PATTERNS來形成依賴文件名。
    每 個模式通常包含一個’%’字符。當TARGET-PATTERN匹配一個目標時,’%’字符可以匹配目標名中的任何部分;這部分即是詞干,模式的其余部分 必須完全匹配。例如’foo.o’匹配’%.o’,’foo’是詞干;目標’foo.c’和’foo.out’并不匹配這個模式。
    目標的依賴文件 名通過將DEP-PATTERNS中的’%’替換為詞干形成:如果依賴模式為’%.c’,在替換詞干’foo’可以得到’foo.c’。依賴模式中不包 含’%’也是合法的,此依賴文件對所有的目標均有效。
    如果需要在模式規(guī)則中使用’%’字符,必須在其前面加’\’字符,如果’%’前的’\’字符 是有實際意義的,必須在其前面加’\’,其它的’\’不必如此處理。如’the\%weird\\%pattern\\’在有效的’%’前 是’the%weird\’,其后是’pattern\\’。最后的’\\’保持原樣是因為其并不影響’%’字符。
    以下例子從相應(yīng)的’.c’文件 編譯’foo.o’和’bar.o’:
    objects = foo.o bar.o
    $(objects): %.o: %.c
            $(CC) -c $(CFLAGS) $< -o $@
    每 個目標必須匹配目標模式,對于不匹配的目標會給出警告。如果列表中只有部分文件匹配模式,可以使用filter函數(shù)移去不匹配的文件名:
    files = foo.elc bar.o lose.o

    $(filter %.o,$(files)): %.o: %.c
            $(CC) -c $(CFLAGS) $< -o $@
    $(filter %.elc,$(files)): %.elc: %.el
            emacs -f batch-byte-compile $<
    例 子中`$(filter %.o,$(files))' 結(jié)果是 `bar.o lose.o’; `$(filter %.elc,$(files))' 的結(jié)果是`foo.elc'。以下例子說明’$*’的使用:
    bigoutput littleoutput : %output : text.g
            generate text.g -$* >; $@
    命 令`generate'執(zhí)行時,’$*’擴展為詞干’big’或’little’。
    3.11.2靜態(tài)模式規(guī)則和隱式規(guī)則
    靜態(tài)模式規(guī)則和隱 式規(guī)則在作為模式規(guī)則是具有很多共同點,都有目標模式和構(gòu)造依賴文件名的模式,不同之處在于make決定何時應(yīng)用規(guī)則的方法。
    隱式規(guī)則可應(yīng)用于匹 配其模式的任何目標,但只限于沒有指定命令的目標,如果有多條可應(yīng)用的隱式規(guī)則,只有一條被使用,取決于規(guī)則的順序。
    反之,靜態(tài)模式規(guī)則適用于規(guī) 則中明確目標列表,不適用于其它目標且總是適用于指定的每個目標。如果有兩條沖突的規(guī)則,且都有命令,這是一個錯誤。
    靜態(tài)模式規(guī)則比隱式規(guī)則優(yōu)越 之處如下:
    ★可為一些不能按句法分類,但可以顯式列出的文件重載隱式規(guī)則
    ★不能判定目錄中的精確內(nèi)容,一些無關(guān)的文件可能導(dǎo)致make適 用錯誤的隱式規(guī)則;最終結(jié)果可能依賴于隱式規(guī)則的次序。適用靜態(tài)模式規(guī)則時,這種不確定性是不存在的:規(guī)則適用于明確指定的目標。
    3.12雙冒號 規(guī)則
    雙冒號規(guī)則(Double-colon rules)的目標后是’::’而不是’:’,當一個目標出現(xiàn)在多條規(guī)則中時,其處理和普通規(guī)則的處 理不同。
    當一個目標出現(xiàn)在多條規(guī)則中時,所有規(guī)則必須是相同類型的:都是普通的或者都是雙冒號的。如果是雙冒號,規(guī)則之間相互獨立;如果目標需要 更新,則規(guī)則的命令被執(zhí)行;結(jié)果可能是沒有執(zhí)行,或者執(zhí)行了其中一些,或者所有的規(guī)則都執(zhí)行了。
    同一目標的雙冒號規(guī)則事實是完全孤立的,每條規(guī)則 被被單獨處理,就象不同目標的規(guī)則一樣;規(guī)則按照在makefile中出現(xiàn)的次序被處理,此類規(guī)則真正有意義的是那些于命令執(zhí)行次序無關(guān)的。
    這種 規(guī)則有時比較晦澀不是特別有用;它提供了一種機制:通過不同依賴文件的更新來對目標進行不同的處理,這種情形很罕見。每個這種規(guī)則應(yīng)當提供命令,如果沒 有,適用的隱式規(guī)則將使用。
    3.13自動生成依賴關(guān)系
    在makefile中,許多規(guī)則都是一些目標文件依賴于一些頭文件。例 如:’main.c’ 通過’#include’使用’defs.h’,這樣規(guī)則:
    main.o: defs.h
    告訴make 在’defs.h’變化時更新’main.o’。在程序比較大時,需要寫許多這樣的規(guī)則;而且當每次增刪’#include’時,必須小心的更新 makefile。許多現(xiàn)代的編譯器可以幫你寫這些規(guī)則,通常這是通過編譯器的’-M’選項,例如命令:
    cc –M main.c
    輸出以 下內(nèi)容:
    main.o : main.c defs.h
    這樣就不必寫這些規(guī)則,有編譯器代勞了。
    注意這樣的依賴關(guān)系中提 及’main.o’,不會被隱式規(guī)則認為是中間文件,這意味這make在使用過它之后不會將其刪除。使用老的’make’程序時,習慣做法是使 用’make depend’命令利用編譯器的功能產(chǎn)生依賴關(guān)系,該命令會產(chǎn)生一個’depend’文件包含所有自動產(chǎn)生的依賴關(guān)系,然后在 makefile中使用’include’將其讀入。
    使用GNU的make時,重新生成makefile的功能使得這種做法變得過時:從不需要顯 式請求更新依賴關(guān)系,因為它總是重新生成任何過時的makefile。
    自動依賴關(guān)系生成推薦的做法是對每個源文件做一個makefile。對每個 源文件’NAME.c’,有一個makefile ’NAME.d’,其中列出了目標文件’NAME.o’依賴的所有文件,這樣在源文件更新時,需要掃描 來產(chǎn)生新的依賴關(guān)系。例子是一個從’NAME.c’產(chǎn)生依賴關(guān)系文件’NAME.d’的模式規(guī)則:
    %.d: %.c
             $(SHELL) -ec '$(CC) -M $(CPPFLAGS) $< \
                           | sed '\''s/\($*\)\.o[ :]*/\1 $@/g'\'' >; $@'
    -e 選項是當$(CC)命令失敗時(exit狀態(tài)非0),shell立刻退出。通常shell的返回值是管道中最后一條命令(sed)的返回值,這樣make 不會注意到編譯器出錯。
    使用GNU的C編譯器時(gcc),可以用’-MM’選項來代替’-M’選項,這樣省略系統(tǒng)頭文件的依賴關(guān)系。’sed’ 命令的目的是將
    main.o : main.c defs.h
    轉(zhuǎn)換為
    main.o main.d : main.c defs.h
    這 樣使得每個’.d’文件依賴于’.o’文件相應(yīng)源文件和頭文件,make則可以在原文間或頭文件變化時更新依賴關(guān)系文件。
    如果定義了生成’.d’ 文件的規(guī)則,可以使用’include’指令來讀入所有的文件:
    sources = foo.c bar.c
    include $(sources:.c=.d)
    例 中使用替換變量來將源文件列表’ foo.c bar.c’轉(zhuǎn)換為依賴關(guān)系文件的列表。因為’.d’文件和其它文件一樣,不需要更多工作,make會在需 要時重新生成它們。
    4編寫命令
    規(guī)則的命令是由一一執(zhí)行的shell命令組成。除了以分號隔開寫在依賴關(guān)系后的命令,每個命令行必須以 tab字符開始空行和注釋行可以出現(xiàn)在命令行中,處理時被忽略(注意:以tab字符開始的空行不是’空’行,是一條空命令)。
    可以在命令中使用任 何程序,但這些程序是由$(SHELL)來執(zhí)行的。
    4.1回顯
    通常make打印出要執(zhí)行的命令,稱之為回顯,這和親自敲命令的現(xiàn)象是一樣 的。當行之前有’@’字符時,命令不再回顯,字符’@’在傳遞給shell前丟棄。典型的用法是只對打印命令有效,比如’echo’命令:
    @echo About to make distribution files
    當 make使用’-n’或’—just-print’選項時,顯示要發(fā)生的一切,但不執(zhí)行命令。只有在這種情況下,即使命令以’@’開始,命令行仍然顯示出 來。這個選項對查看make實際要執(zhí)行的動作很有用。
    ‘-s’或’—silent’選項阻止make所有回顯,就象所有命令以’@’開始一樣;一 條沒有依賴關(guān)系的’.SILENT’規(guī)則有相同的作用,但是’@’更加靈活。
    4.2執(zhí)行
    在需要執(zhí)行命令更新目標時,make為每一行創(chuàng)建 一個子shell來執(zhí)行。這意味著諸如為進程設(shè)置局部變量的shell命令’cd’(改變進程的當前目錄)不會影響以后的命令。如果需要’cd’影響下一 個命令,將它們放在一行上用分號隔開,這樣make認為是一條命令傳遞給shell程序(注意:這需要shell支持):
    foo : bar/lose
            cd bar; gobble lose >; ../foo
    另 一個形式使用續(xù)行符:
    foo : bar/lose
            cd bar;  \
            gobble lose >; ../foo
    shell 程序的名字是通過’SHELL’變量來取得的。
    (*UNIX)不象大多數(shù)變量,’SHELL’變量不是通過環(huán)境來設(shè)置的(即需要在 makefile中設(shè)置),因為’SHELL’環(huán)境是個人選擇的,如果不同人的選擇會影響makefile的功能的話,這樣很糟糕。
    4.3并行執(zhí) 行
    GNU make可以一次執(zhí)行幾條命令。通常make一次執(zhí)行一條命令,等待其返回,再執(zhí)行下一條。使用’-j’或’—jobs’可以同時執(zhí)行 多條命令。如果’-j’后梗一個正數(shù),表示一次可以執(zhí)行的命令條數(shù);如果’-j’之后沒有參數(shù),則不限制可執(zhí)行的命令數(shù)。缺省的數(shù)量是一。
    一個討 厭的問題是如果同時執(zhí)行多條命令,它們的輸出會混在一起;另一個問題是兩個進程不能從同一個設(shè)備獲得輸入。
    4.4錯誤
    每條shell命令 返回時,make會檢查其返回狀態(tài)。如果命令執(zhí)行成功,則下一條命令被執(zhí)行,最后一條命令執(zhí)行完后,規(guī)則執(zhí)行結(jié)束。
    如果有錯誤(返回非0狀 態(tài)),make放棄當前規(guī)則,也可能是所有規(guī)則。
    有時候命令執(zhí)行錯誤并不是問題,比如使用’mkdir’命令確保目錄存在:如果目錄一存在, 則’mkdir’會報告錯誤,但仍希望make繼續(xù)。
    要忽略命令的錯誤,在命令之前使用’-‘字符,’-‘字符在傳遞給shell之前被丟棄:
    clean:
            -rm -f *.o
    如 果使用’-i’或’—ignore-errors’選項,make會忽略所有命令產(chǎn)生的錯誤;一條沒有依賴關(guān)系的’.IGNORE’規(guī)則有相同的作用, 但’-‘更靈活。
    在忽略錯誤時,make將錯誤也認為是成功,只是通知你命令的退出狀態(tài)和和錯誤被忽略。如果make并未告知忽略錯誤,在錯誤發(fā) 生時,表明該目標不能成功更新,直接或間接依賴于此的目標當然也不能成功;這些目標的命令不會被執(zhí)行,因為其先決條件不滿足。
    通常make會立即 以非0狀態(tài)退出。然而,如果給定’-k’或’—keep-going’選項,make在退出前會處理其它的依賴關(guān)系,進行必要的更新。例如,在編譯一個目 標文件遇到錯誤,’make  -k’會繼續(xù)編譯其它的目標文件。
    通常認為你的目的是更新指定的目標,當make知道這是不可能時,會立即報告失 敗;’-k’選項指示真正目的是測試更新程序的更多可能性:在編譯之前找出更多不相關(guān)的問題。
    如果命令失敗了,假設(shè)它更新的目標文件,這個文件是 不完整的不能使用-至少不是完全更新的。但文件的最后修改時間表明停已經(jīng)是最新的,下一次make運行時,不會再更新這個文件。這種情況和命令被kill 相同;則通常情況下在命令失敗時將目標刪除是正確的;當’.DELETE_ON_ERROR’是目標時make幫你做這件事。雖然你總是希望make這么 做,但這不是過去的習慣;所以必須顯式要求make這樣做(其它的make自動這樣做)。
    4.5中斷make
    如果make執(zhí)行命令時遇到 錯誤,可能會刪除命令更新的目標文件: make檢查文件的修改時間是否變化。刪除目標的目的是確保make下次執(zhí)行時重新生成它。為什么這樣做?假設(shè)在 編譯器運行時按了’Ctrl-c’,此時編譯器寫生成目標文件’foo.o’。’Ctrl-c’ kill了編譯器,留下一個不完整的文件,但它的修改時 間比源文件’foo.c’新;此時make也受到’Ctrl-c’信號刪除這個不完整的文件,如果make不這樣做,下次make運行時認 為’foo.o’不需要更新,會在鏈接時出現(xiàn)奇怪的錯誤。
    可以使用’.PRECIOUS’規(guī)則來防止目標文件被刪除。在make更新目標時,會檢 測其是否為’.PRECIOUS’的依賴,決定在命令出錯或中斷時是否刪除該目標。如果你希望目標的更新是原子操作,或是用來記錄修改時間,或必須一直存 在防止其它類型的錯誤,這些理由使得你必須這樣做。
    4.6遞歸使用
    遞歸使用make就是在makefile中使用make命令。這種技術(shù) 在你將一個大系統(tǒng)分解為幾個子系統(tǒng),為每個自系統(tǒng)提供一個makefile時有用處。比如有一個子目錄’subdir’中有自己的makefile,希望 make在自目錄中運行,可以這樣做:
    subsystem:
            cd subdir; $(MAKE)
    或 者
    subsystem:
             $(MAKE) -C subdir
    可以照抄這個;例子來遞歸使用make
    4.6.1‘MAKE’ 變量
    遞歸的make必須使用’MAKE’變量,不是顯式的make命令:
    subsystem:
            cd subdir; $(MAKE)
    該 變量的值是被調(diào)用的make的名字。在命令中使用’MAKE’有特殊的功能:它改變了`-t' (`--touch'), `-n' (`--just- print')和`-q' (`--question')選項的含義。使用上例來考慮’make –t’命令(’-t’選項將目標標記為最新但不運行命 令),更加’-t’選項的功能,該命令將創(chuàng)建一個’subsystem’文件,實際希望的操作是運 行’cd subdir; make –t’;但這會執(zhí)行命令,與’-t’的原意不符。
    這個特殊功能做了期望的工作。當命令行包 含變量’MAKE’時,選項’-t’,’-n’和’-q’并不適用。不管這些導(dǎo)致不會執(zhí)行命令的標志,包含’MAKE’變量的命令始終會執(zhí)行。正常 的’MAKEFLAGS’機制將這些標志傳遞到子make,這樣打印命令的請求被傳播到子系統(tǒng)中。
    4.6.2傳遞變量到子make
    上級 (top-level)make中的變量可以顯式通過環(huán)境傳遞到子make中。在子make中,這些變量被缺省定義,但不會重載子makefile中的定 義除非使用’-e’選項。
    為向下傳遞,或輸出變量,make在運行命令時將其加入到環(huán)境變量中;子make,可以使用環(huán)境變量來初始化變量表。除 非顯式要求,make只輸出初始環(huán)境中或命令行設(shè)置的變量而且變量名只由字母,數(shù)字和下劃線組成。一些shell不能處理有其它字符的環(huán)境變量。
    特 殊變量’SHELL’,’MAKEFLAGS’總是輸出,如果’MAKEFILE’變量有值,也會輸出。Make自動通過’MAKEFLAGS’來輸出命 令行定義的變量。
    如果想要輸出特定變量,使用’export’指令:
    export VARIABLE ...
    如果要阻止輸出一個 變量,使用’unexport’指令:
    unexport VARIABLE ...
    為方便起見,可以在定義變量時輸出它:
    export VARIABLE = value

    VARIABLE = value
    export VARIABLE
    作 用相同。
    如果要輸出所有的變量,使用’export’指令本身就可以了。
    變量’MAKELEVEL’在一級一級傳遞時會改變,這個變量的 值是表示嵌套層數(shù)的字符串,頂級’make’是,變量的值為’0’;子make的值為’1’;子子make的值為’2’,依此類推。
    ‘MAKELEVEL’ 的用途是在條件指令中測試它,這樣寫出在遞歸運行時和直接運行時表現(xiàn)不同的makefile。
    主站蜘蛛池模板: 日木av无码专区亚洲av毛片| 日韩人妻无码精品久久免费一| 亚洲欧洲日本国产| 亚洲午夜无码片在线观看影院猛 | 国产高清免费观看| 亚洲毛片在线免费观看| a级毛片高清免费视频就| 美女裸免费观看网站| 亚洲中文字幕一区精品自拍| 亚洲天堂久久精品| 国产亚洲高清不卡在线观看| 亚洲第一视频在线观看免费| 午夜视频免费观看| 欧美大尺寸SUV免费| 91av免费观看| 一级毛片免费毛片一级毛片免费| 国产成人无码精品久久久久免费| 国产天堂亚洲国产碰碰| 亚洲国产AV无码一区二区三区| 亚洲国产中文在线视频| 日木av无码专区亚洲av毛片| 亚洲国产精品国自产拍AV| 久久久精品国产亚洲成人满18免费网站| 日韩免费视频网站| 无码国模国产在线观看免费| 午夜神器成在线人成在线人免费| 免费做爰猛烈吃奶摸视频在线观看| 57pao国产成永久免费视频| 青青草无码免费一二三区| 在线观看免费无码专区| 国产免费阿v精品视频网址| 99在线视频免费观看| 成全动漫视频在线观看免费高清版下载 | 久久精品国产亚洲AV天海翼| 亚洲首页国产精品丝袜| 中文字幕亚洲综合小综合在线| 亚洲 日韩经典 中文字幕| 亚洲欧洲无码一区二区三区| 亚洲中文无码亚洲人成影院| 亚洲大码熟女在线观看| 小说区亚洲自拍另类|