1. 程式人生 > >Makefile----shell函式和make的執行

Makefile----shell函式和make的執行

一 shell函式

shell函式也不像其它的函式。顧名思義,它的引數應該就是作業系統Shell的命令。它
和反引號“`”是相同的功能。這就是說,shell函式把執行作業系統命令後的輸出作為函
數返回。於是,我們可以用作業系統命令以及字串處理命令awk,sed等等命令來生成
一個變數,如:

    contents := $(shell cat foo)

    files := $(shell echo *.c)

注意,這個函式會新生成一個Shell程式來執行命令,所以你要注意其執行效能,如果你
的Makefile中有一些比較複雜的規則,並大量使用了這個函式,那麼對於你的系統性能
是有害的。特別是Makefile的隱晦的規則可能會讓你的shell函式執行的次數比你想像的
多得多。
二 控制make的函式

make提供了一些函式來控制make的執行。通常,你需要檢測一些執行Makefile時的執行
時資訊,並且根據這些資訊來決定,你是讓make繼續執行,還是停止。

$(error ;)

    產生一個致命的錯誤,;是錯誤資訊。注意,error函式不會在一被使用
就會產生錯誤資訊,所以如果你把其定義在某個變數中,並在後續的指令碼中使用這個變
量,那麼也是可以的。例如:

    示例一:
    ifdef ERROR_001
    $(error error is $(ERROR_001))
    endif

    示例二:
    ERR = $(error found an error!)
    .PHONY: err
    err: ; $(ERR)

    示例一會在變數ERROR_001定義了後執行時產生error呼叫,而示例二則在目標err被
執行時才發生error呼叫。

$(warning ;)

     這個函式很像error函式,只是它並不會讓make退出,只是輸出一段警告資訊,而
make繼續執行。
make的執行:

一般來說,最簡單的就是直接在命令列下輸入make命令,make命令會找當前目錄的
makefile來執行,一切都是自動的。但也有時你也許只想讓make重編譯某些檔案,而不
是整個工程,而又有的時候你有幾套編譯規則,你想在不同的時候使用不同的編譯規
則,等等。本章節就是講述如何使用 make命令的。
一、make的退出碼
make命令執行後有三個退出碼:
    0 —— 表示成功執行。
    1 —— 如果make執行時出現任何錯誤,其返回1。
    2 —— 如果你使用了make的“-q”選項,並且make使得一些目標不需要更新,那麼返回2。
Make的相關引數我們會在後續章節中講述。
二、指定Makefile
前面我們說過,GNU make找尋預設的Makefile的規則是在當前目錄下依次找三個檔案——
“GNUmakefile”、“makefile”和“Makefile”。其按順序找這三個檔案,一旦找到,就開始
讀取這個檔案並執行。
當前,我們也可以給make命令指定一個特殊名字的Makefile。要達到這個功能,我們要
使用make的“-f”或是“--file”引數(“--makefile”引數也行)。例如,我們有個
makefile的名字是“hchen.mk”,那麼,我們可以這樣來讓make來執行這個檔案:
    make –f hchen.mk
如果在make的命令列是,你不只一次地使用了“-f”引數,那麼,所有指定的makefile將
會被連在一起傳遞給make執行。
三、指定目標
一般來說,make的最終目標是makefile中的第一個目標,而其它目標一般是由這個目標
連帶出來的。這是make的預設行為。當然,一般來說,你的makefile中的第一個目標是
由許多個目標組成,你可以指示make,讓其完成你所指定的目標。要達到這一目的很簡
單,需在make命令後直接跟目標的名字就可以完成(如前面提到的“make clean”形式)
任何在makefile中的目標都可以被指定成終極目標,但是除了以“-”打頭,或是包含了
“=”的目標,因為有這些字元的目標,會被解析成命令列引數或是變數。甚至沒有被我們
明確寫出來的目標也可以成為make的終極目標,也就是說,只要make可以找到其隱含規
則推導規則,那麼這個隱含目標同樣可以被指定成終極目標。
有一個make的環境變數叫“MAKECMDGOALS”,這個變數中會存放你所指定的終極目標的列
表,如果在命令列上,你沒有指定目標,那麼,這個變數是空值。這個變數可以讓你使
用在一些比較特殊的情形下。比如下面的例子:
    sources = foo.c bar.c
    ifneq ( $(MAKECMDGOALS),clean)
    include $(sources:.c=.d)
    endif
基於上面的這個例子,只要我們輸入的命令不是“make clean”,那麼makefile會自動包
含“foo.d”和“bar.d”這兩個makefile。
使用指定終極目標的方法可以很方便地讓我們編譯我們的程式,例如下面這個例子:
    .PHONY: all
    all: prog1 prog2 prog3 prog4
從這個例子中,我們可以看到,這個makefile中有四個需要編譯的程式——“prog1”,
“prog2”, “prog3”和  “prog4”,我們可以使用“make all”命令來編譯所有的目標(如
果把all置成第一個目標,那麼只需執行“make”),我們也可以使用 “make prog2”來單
獨編譯目標“prog2”。
即然make可以指定所有makefile中的目標,那麼也包括“偽目標”,於是我們可以根據這
種性質來讓我們的makefile根據指定的不同的目標來完成不同的事。在Unix世界中,軟
件釋出時,特別是GNU這種開源軟體的釋出時,其makefile都包含了編譯、安裝、打包等
功能。我們可以參照這種規則來書寫我們的makefile中的目標。
     “all”
        這個偽目標是所有目標的目標,其功能一般是編譯所有的目標。
     “clean”
        這個偽目標功能是刪除所有被make建立的檔案。
     “install”
        這個偽目標功能是安裝已編譯好的程式,其實就是把目標執行檔案拷貝到指定
的目標中去。
     “print”
        這個偽目標的功能是例出改變過的原始檔。
     “tar”
        這個偽目標功能是把源程式打包備份。也就是一個tar檔案。
     “dist”
        這個偽目標功能是建立一個壓縮檔案,一般是把tar檔案壓成Z檔案。或是gz檔案。
     “TAGS”
        這個偽目標功能是更新所有的目標,以備完整地重編譯使用。
     “check”和“test”
        這兩個偽目標一般用來測試makefile的流程。
當然一個專案的makefile中也不一定要書寫這樣的目標,這些東西都是GNU的東西,但是
我想,GNU搞出這些東西一定有其可取之處(等你的 UNIX下的程式檔案一多時你就會發
現這些功能很有用了),這裡只不過是說明了,如果你要書寫這種功能,最好使用這種
名字命名你的目標,這樣規範一些,規範的好處就是——不用解釋,大家都明白。而且如
果你的makefile中有這些功能,一是很實用,二是可以顯得你的makefile很專業(不是
那種初學者的作品)。
四、檢查規則
有時候,我們不想讓我們的makefile中的規則執行起來,我們只想檢查一下我們的命
令,或是執行的序列。於是我們可以使用make命令的下述引數:
    “-n”
    “--just-print”
    “--dry-run”
    “--recon”
    不執行引數,這些引數只是列印命令,不管目標是否更新,把規則和連帶規則下的
命令打印出來,但不執行,這些引數對於我們除錯makefile很有用處。
    “-t”
    “--touch”
    這個引數的意思就是把目標檔案的時間更新,但不更改目標檔案。也就是說,make
假裝編譯目標,但不是真正的編譯目標,只是把目標變成已編譯過的狀態。
    “-q”
    “--question”
    這個引數的行為是找目標的意思,也就是說,如果目標存在,那麼其什麼也不會輸
出,當然也不會執行編譯,如果目標不存在,其會打印出一條出錯資訊。
    “-W ;”
    “--what-if=;”
    “--assume-new=;”
    “--new-file=;”
    這個引數需要指定一個檔案。一般是是原始檔(或依賴檔案),Make會根據規則推
導來執行依賴於這個檔案的命令,一般來說,可以和“-n”引數一同使用,來檢視這個依
賴檔案所發生的規則命令。
另外一個很有意思的用法是結合“-p”和“-v”來輸出makefile被執行時的資訊(這個將在
後面講述)。

相關推薦

Makefile----shell函式make執行

一 shell函式 shell函式也不像其它的函式。顧名思義,它的引數應該就是作業系統Shell的命令。它 和反引號“`”是相同的功能。這就是說,shell函式把執行作業系統命令後的輸出作為函 數返回。於是,我們可以用作業系統命令以及字串處理命令awk,sed等等命令來生成

python用map()函式執行緒threading、Thread採集注意事項

import re import requests from threading import Thread def getUrl(): url = 'http://www.xiaohuar

c++函式物件建構函式operator()執行關係

函式物件常用在stl的演算法中,用於特殊的匹配定製功能。 在執行的函式物件中建構函式和過載()函式的關係先後順序 如下程式碼: find_if(v.begin(), v.end(), search

什麼是Linux的Shell指令碼怎麼執行指令碼?

一、什麼是Shell?         shell是外殼的意思,就是作業系統的外殼。我們可以通過shell命令來操作和控制作業系統,比如Linux中的Shell命令就包括ls、cd、pwd等等。總結來說,Shell是一個命令直譯器,它通過接受使用者輸入的Shell命令來啟動

JavaScript佇列函式非同步執行

編輯注:在Review別人的JavaScript程式碼時曾看到過類似的佇列函式,不太理解,原來這個是為了保證函式按順序呼叫。讀了這篇文章之後,發現還可以用在非同步執行等。假設你有幾個函式fn1、fn2和fn3需要按順序呼叫,最簡單的方式當然是:fn1(); fn

時間函式定時執行緒(linux C )

1.日期時間輸出格式: printf("%04d-%02d-%02d\n",year,month,day); 輸出:1994-02-07  d表示輸出整數、2表示寬度、0表示不足兩位前面補0,右對齊。 2.signal函式: signal(SIGALRM,statis

Shell函式的定義、執行、傳參遞迴函式

 Bash(Bourne Againshell)也跟其他程式語言一樣也支援函式,一般在編寫大型指令碼中需要用到,它可以將Shell指令碼程式劃分成一個個功能相對獨立的程式碼塊,使程式碼的模組化更好,結構更加清晰,並可以有效地減少程式的程式碼量。但是bash作為一種解釋性

linux c之通過popenpclose函式建立管道執行shell 執行命令使用總結

1、函式介紹  popen 和 pclose 函式        操作是建立一個管道連結到另一個程序,然後讀其輸出或向其輸入端傳送資料。標準 I/O 庫提供了兩個函式 popen 和 pclose 函式,這兩個函式實現的操作是:建立一個管道,呼叫 fork 建立一個子程序

01: Shell概述 編寫及執行指令碼 、 Shell變數 總結答疑

Top NSD SHELL DAY01 案例1:Shell基礎應用 案例2:簡單Shell指令碼的設計 案例3:使用Shell變數 案例4:變數的擴充套件應用 1 案例1:Shell基礎應用 1.1 問題 本案例要求熟悉Linux Shell環境

Linux可重入函式執行緒安全的區別與聯絡(轉)

*****可重入函式      函式被不同的控制流程呼叫,有可能在第一次呼叫還沒返回時就再次進入該函式,這稱為重入。      當程式執行到某一個函式的時候,可能因為硬體中斷或者異常而使得在使用者正在執行的程式

makemakefile函式庫檔案

一、簡單的靜態庫書寫編譯和測試 檔案目錄如下所示: . ├── Makefile ├── MakefileTest ├── include.c ├── include.h └── main.c 0 directories, 5 files 其中main.c函式裡面會呼叫includ

Shell 指令碼中的檔名匹配命令執行

理解下 shell 指令碼中的檔名匹配和命令執行的順序與結果。我們學習這個的目的是可以熟悉的在 shell 指令碼中寫出快速的找到檔案的命令。它可以匹配檔名中的任何字串,匹配檔名中的單個字元以及匹配檔名中的字母或數字符號。         首先我們來看看匹配檔案的符號

sqlserver 只有函式擴充套件儲存過程才能從函式內部執行

一個SQLServer的自定義函式中呼叫一個自定義的儲存過程,執行此函式後發出如下提示:“只有函式和擴充套件儲存過程才能從函式內部執行"。原因:函式只能使用簡單的sql語句,邏輯控制語句,複雜一點的儲存過程是不能呼叫的,在函式裡也不能使用execute sp_executesql 或者execute 。解決方

Shell陣列函式

陣列中可以存放多個值。Bash Shell 只支援一維陣列(不支援多維陣列)。 Shell 陣列用括號來表示,元素用"空格"符號分割開,語法格式如下: array_name=(value1 ... valuen) 2.陣列常用操作 1)定義一個數組: myarray=(1 2 3 4 5);

開發筆記之詳述 JAVA 建構函式程式碼塊本身及其執行細節

今天在JAVA的研究學習當中發現了建構函式這個神奇但是麻煩的東西, 他在給我感覺很像OC語言中的initWith..., 但是在細節上有很多的不同, 而程式碼塊這個東西更是讓我這個敲iOS的眼前一亮, 後來針對程式碼塊這個東西的功能和執行的順序深究了一番. 首先說說建構函式 開頭說道這個

執行函式匿名函式

所謂匿名函式就是沒有名字的函式,形式如下: function () { } 既然沒有名字,那麼如何呼叫呢: var b=function () { } b() 可以將匿名函式付給一個變數,這個變數現在就充當了這個函式的名稱,但是記住,這個不是名稱,我只

程序間的資料共享、程序池的回撥函式執行緒初識、守護執行

一、程序的資料共享 程序間資料是獨立的,可以藉助於佇列或管道實現通訊,二者都是基於訊息傳遞的 雖然程序間資料獨立,但可以通過Manager實現資料共享。 把所有實現了資料共享的比較便捷的類都重新又封裝了一遍,並且在原有的multiprocessing基礎上增加了新

JS根據id執行函式一般函式

document.getElementById("Btn").onclick = function(){} 和 function Btn(){} 本質的區別是根據ID執行的函式一定要在文字載入

SHELL訓練營--day8__shell函式陣列

函式 shell 中,將實現特定功能的程式碼組合起來,即為函式體。函式格式如下: [ function ] funname [()] { action; [return int;] } 注意函式定義:1.function 和(),在函式定義時,至少要保留一個。2.函式

AIX_環境下SHELL指令碼設定成crontab排程手動執行的某些不同

有些時候,寫好的shell指令碼手工執行很正常,但一旦把其配置在crontab上排程就會出現這樣或那樣的問題。本人就遇到到如下幾種情況。 1、在呼叫oracle的sqlplus、sqlldr等命令工具