1. 程式人生 > >Shell 指令碼中如何使用make命令

Shell 指令碼中如何使用make命令

     (最近開發的專案中需要編寫Shell指令碼對整個工程進行自動化編譯,即在Shell指令碼中使用make命令來進行編譯,下面回顧一下Shell指令碼中如何使用make命令)

        在開發一個系統時,一般是將一個系統分成幾個模組,這樣做提高了系統的可維護性,但由於各個模組間不可避免存在關聯,所以當一個模組改動後,其他模組也許會有所更新,當然對小系統來說,手工編譯連線是沒問題,但是如果是一個大系統,存在很多個模組,那麼手工編譯的方法就不適用了。為此,在Linux系統中,專門提供了一個make命令來自動維護目標檔案,與手工編譯和連線相比,make命令的優點在於他只更新修改過的檔案(在Linux中,一個檔案被建立或更新後有一個最後修改時間,make命令就是通過這個最後修改時間來判斷此檔案是否被修改),而對沒修改的檔案則置之不理,並且make命令不會漏掉一個需要更新的檔案。

       檔案和檔案間或模組或模組間有可能存在倚賴關係,make命令也是依據這種依賴關係來進行維護的,所以我們有必要了解什麼是依賴關係;make命令當然不會自己知道這些依賴關係,而需要程式設計師將這些依賴關係寫入一個叫makefile的檔案中。

       下面是詳細解析:

一、Make命令

1、make命令基礎概念

    Make這個詞,英語的意思是”製作”。Make命令直接用了這個意思,就是要做出某個檔案。比如,要做出檔案a.txt,就可以執行下面的命令。

$ make a.txt
       但是,如果你真的輸入這條命令,它並不會起作用。因為Make命令本身並不知道,如何做出a.txt,需要有人告訴它,如何呼叫其他命令完成這個目標。

       比如,假設檔案a.txt 依賴於b.txt 和 c.txt ,是後面兩個檔案連線(cat命令)的產物。那麼,make 需要知道下面的規則。

a.txt: b.txt c.txt
    cat b.txt c.txt > a.txt
       也就是說,make a.txt 這條命令的背後,實際上分成兩步:第一步,確認 b.txt 和 c.txt 必須已經存在,第二步使用 cat 命令 將這個兩個檔案合併,輸出為新檔案。

       像這樣的規則,都寫在一個叫做Makefile的檔案中,Make命令依賴這個檔案進行構建。Makefile檔案也可以寫為makefile, 或者用命令列引數指定為其他檔名。

$ make -f rules.txt # 或者 $ make --file=rules.txt
      上面程式碼指定make命令依據rules.txt檔案中的規則,進行構建。

2、make命令使用方法

     Make命本身可帶有四種引數:標誌、巨集定義、描述檔名和目標檔名。其標準形式為:

  Make [flags] [macro definitions] [targets]

  Unix系統下標誌位flags選項及其含義為:
 
  -f file  指定file檔案為描述檔案,如果file引數為"-"符,那麼描述檔案指向標準輸入。如果沒有"-f"引數,則系統將預設當前目錄下名為makefile或者名為Makefile的檔案為描述檔案。在Linux中, GNU make 工具在當前工作目錄中按照GNUmakefile、makefile、Makefile的順序搜尋 makefile檔案。

  -i   忽略命令執行返回的出錯資訊。 
  -s   沉默模式,在執行之前不輸出相應的命令列資訊。 
  -r   禁止使用build-in規則。 
  -n   非執行模式,輸出所有執行命令,但並不執行。 
  -t   更新目標檔案。 
  -q   make操作將根據目標檔案是否已經更新返回"0"或非"0"的狀態資訊。 
  -p   輸出所有巨集定義和目標檔案描述。 
  -d   Debug模式,輸出有關檔案和檢測時間的詳細資訊。

  Linux下make標誌位的常用選項與Unix系統中稍有不同,下面我們只列出了不同部分:

  -c dir   在讀取 makefile 之前改變到指定的目錄dir。 

  -I dir   當包含其他 makefile檔案時,利用該選項指定搜尋目錄。 
  -h   help文擋,顯示所有的make選項。 
  -w   在處理 makefile 之前和之後,都顯示工作目錄。

  通過命令列引數中的target ,可指定make要編譯的目標,並且允許同時定義編譯多個目標,操作時按照從左向右的順序依次編譯target選項中指定的目標檔案。如果命令列中沒有指定目標,則系統預設target指向描述檔案中第一個目標檔案。

  通常,makefile 中還定義有 clean 目標,可用來清除編譯過程中的中間檔案,例如:

  clean: 
  rm -f *.o

  執行 make clean 時,將執行 rm -f *.o 命令,最終刪除所有編譯過程中產生的所有中間檔案。

  隱含規則

  在make 工具中包含有一些內建的或隱含的規則,這些規則定義瞭如何從不同的依賴檔案建立特定型別的目標。Unix系統通常支援一種基於副檔名即檔名字尾的隱含規則。這種字尾規則定義瞭如何將一個具有特定檔名字尾的檔案(例如.c檔案),轉換成為具有另一種檔名字尾的檔案(例如.o檔案):
 
  .c:.o 
  $(CC) $(CFLAGS) $(CPPFLAGS) -c -o [email protected] $< 

  系統中預設的常用副檔名及其含義為: 

  .o  目標檔案 
  .c  C原始檔 
  .f  FORTRAN原始檔 
  .s  彙編原始檔 
  .y  Yacc-C源語法 
  .l  Lex源語法

  在早期的Unix系統系統中還支援Yacc-C源語法和Lex源語法。在編譯過程中,系統會首先在makefile檔案中尋找與目標檔案相關的.C檔案,如果還有與之相依賴的.y和.l檔案,則首先將其轉換為.c檔案後再編譯生成相應的.o檔案;如果沒有與目標相關的.c檔案而只有相關的.y檔案,則系統將直接編譯.y檔案。
  而GNU make 除了支援字尾規則外還支援另一種型別的隱含規則--模式規則。這種規則更加通用,因為可以利用模式規則定義更加複雜的依賴性規則。模式規則看起來非常類似於正則規則,但在目標名稱的前面多了一個 % 號,同時可用來定義目標和依賴檔案之間的關係,例如下面的模式規則定義瞭如何將任意一個 file.c 檔案轉換為 file.o 檔案:

  %.c:%.o 
  $(CC) $(CFLAGS) $(CPPFLAGS) -c -o [email protected] $< 

二、Makefile檔案

1、概述

     Makefile檔案由一系列規則(rules)構成。每條規則的形式如下。

<target> : <prerequisites> [tab] <commands>

     上面第一行冒號前面的部分,叫做”目標”(target),冒號後面的部分叫做”前置條件”(prerequisites);第二行必須由一個tab鍵起首,後面跟著”命令”(commands)。

     “目標”是必需的,不可省略;”前置條件”和”命令”都是可選的,但是兩者之中必須至少存在一個

      每條規則就明確兩件事:構建目標的前置條件是什麼,以及如何構建。

2、 目標(target)

      一個目標(target)就構成一條規則。目標通常是檔名,指明Make命令所要構建的物件,比如 a.txt 。目標可以是一個檔名,也可以是多個檔名,之間用空格分隔

      除了檔名,目標還可以是某個操作的名字,這稱為”偽目標”(phony target)

clean: rm *.o

    上面程式碼的目標是clean,它不是檔名,而是一個操作的名字,屬於”偽目標 “,作用是刪除物件檔案。

$ make  clean

    但是,如果當前目錄中,正好有一個檔案叫做clean,那麼這個命令不會執行。因為Make發現clean檔案已經存在,就認為沒有必要重新構建了,就不會執行指定的rm命令

    為了避免這種情況,可以明確宣告clean是”偽目標”,寫法如下。

.PHONY: clean
clean: rm *.o temp
    宣告clean是”偽目標”之後,make就不會去檢查是否存在一個叫做clean的檔案,而是每次執行都執行對應的命令。像.PHONY這樣的內建目標名還有不少,可以檢視手冊。

    如果Make命令執行時沒有指定目標,預設會執行Makefile檔案的第一個目標。

    $ make

    上面程式碼執行Makefile檔案的第一個目標。

例:執行多個目標

.PHONY: cleanall cleanobj cleandiff

cleanall : cleanobj cleandiff
        rm program

cleanobj : rm *.o

cleandiff : rm *.diff

三、shell 指令碼各種執行方式(source ./*.sh, . ./*.sh, ./*.sh)的區別

結論一: ./*.sh的執行方式等價於sh ./*.sh或者bash ./*.sh,此三種執行指令碼的方式都是重新啟動一個子shell,在子shell中執行此指令碼。

結論二: .source ./*.sh和 . ./*.sh的執行方式是等價的,即兩種執行方式都是在當前shell程序中執行此指令碼,而不是重新啟動一個shell 而在子shell程序中執行此指令碼

驗證依據:沒有被export匯出的變數(即非環境變數)是不能被子shell繼承的

驗證結果:

[[email protected] ~]#name=dangxu       //定義一般變數  
[[email protected] ~]# echo ${name}  
dangxu  
[[email protected] ~]# cat test.sh      //驗證指令碼,例項化標題中的./*.sh  
#!/bin/sh  
echo ${name}  
[[email protected] ~]# ls -l test.sh    //驗證指令碼可執行  
-rwxr-xr-x 1 root root 23 Feb  6 11:09 test.sh  
[[email protected] ~]# ./test.sh        //以下三個命令證明了結論一  
  
[[email protected] ~]# sh ./test.sh  
  
[[email protected] ~]# bash ./test.sh  
  
[[email protected] ~]# . ./test.sh     //以下兩個命令證明了結論二  
dangxu  
[[email protected] ~]# source ./test.sh  
dangxu  
[[email protected] ~]#  


相關推薦

Shell指令碼make命令的使用

    (最近開發的專案中需要編寫Shell指令碼對整個工程進行自動化編譯,即在Shell

shell 指令碼獲取命令的輸出

這個主要介紹的方法是獲取命令的輸出內容,而不是命令執行成功與否的返回值。 通常情況下,在shell指令碼中需要獲取命令的輸出內容,然後根據輸出內容判斷下一步的執行操作。 比較常用的一種方式就是, 匹配命令輸出的內容中是否存在某些關鍵字,選擇執行的不同動作。 比較常用的一種方式就是

解決 shell指令碼SCP命令需要輸入密碼的問題

本文轉自:https://blog.csdn.net/u012454773/article/details/72779439 使用金鑰檔案,兩臺機器建立信任 這裡假設主機A(192.168.100.3)用來獲得主機B(192.168.100.4)的檔案。 在主機A上執行如下命令來生成配對金鑰:

linux下shell指令碼sed命令使用變數

用linpack做測試,寫了一個指令碼, 因為每次可修改的引數寫在了配置檔案裡,所以腳本里用sed命令來修改配置檔案#測試次數echo “Input Number of tests:”read numt#每次測試的資料規模,測試次數有多少次,這裡應該又多少組數字,中間以空格隔

Shell指令碼cd命令使用

在寫shell指令碼的時候發現cd切換目錄的時候無法切換,程式碼是下面的。 #!/bin/bash #changedir.sh cd /home/firefox pwd我仔細一想,我執行的時候是./changedir.sh來執行的,這樣執行的話終端會產生一個子shell,子

Linux shell指令碼執行命令結果賦值給變數&&echo輸出變數是否包含換行符的問題

Linux shell指令碼中執行命令結果賦值給變數&&echo輸出變數是否包含換行符的問題 echo $ret 和 echo "$ret" 區別: 如果是echo $ret,輸出結果為一行,沒有換行符 如果是echo "$ret",輸出結果為多行,有換行符

shell指令碼cd命令無效的解決方案

在學習的時候,經常要切換到固定的資料夾,於是寫了個shell指令碼用cd命令切換卻發現目錄切換不了。 程式碼如下: #! /bin/bash # c.sh cd /mnt/hgfs/vmsha

linux shell指令碼cd命令無效的解決方法

      今天需要快速切換目錄,然後在sh腳本里面加入cd,但發現執行後無效。原因就不深究了。然後查了一下,有三種解決方案。       方案一、source ./    格式   例如:so

Shell 指令碼如何使用make命令

     (最近開發的專案中需要編寫Shell指令碼對整個工程進行自動化編譯,即在Shell指令碼中使用make命令來進行編譯,下面回顧一下Shell指令碼中如何使用make命令)         在開發一個系統時,一般是將一個系統分成幾個模組,這樣做提高了系統的可維護性,

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

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

linux的shell指令碼執行多個命令的方法

第一種是以分號(;)進行劃分:表示:各命令的執行的果,不會影響其它命令的執行。換句話說,各個命令都會執行,但不保證每個命令都執行成功。 第二種命令之間&&隔開 表示:若前面的命令執

shell指令碼使用getopts處理多命令列選項

在Linux系統中,許多命令都提供了選項,使用不同的選項就會得到不通的執行結果例如:ls命令,ls命令提供了多個選項:-l、-a、-A、-h、-i等等,每個選項具有不同的功能,我們自己寫指令碼時也可以定義選項,提示使用者如何使用,本文介紹如何使用getopts命令來處理命令選

shell 指令碼獲取執行系統命令的輸出結果

這個主要介紹的方法是獲取命令的輸出內容,而不是命令執行成功與否的返回值。通常情況下,在shell指令碼中需要獲取命令的輸出內容,然後根據輸出內容判斷下一步的執行操作。比較常用的一種方式就是, 匹配命令輸出的內容中是否存在某些關鍵字,選擇執行的不同動作。比較常用的一種方式就是採

shell指令碼如何呼叫hadoop 命令

我們在shell指令碼中可能會用到hadoop或者其他命令,而這些命令可能是一個整體,如果我們只是簡單的寫入到shell指令碼中,可能會被分解成其他的各個子欄位,即有可能會分成兩部分去執行,這樣就會導致命令執行失敗。 hadoop fs -get /XX

shell指令碼使用ls命令的注意事項

請對比如下兩個測試: $ for i in `ls /etc`;do echo $i;done adjtime adobe appstream.conf arch-release asound.conf avahi bash.bash_logout bas

十六週二次課 2018.02.05 shell指令碼介紹、shell指令碼結構和執行、date命令用法、shell指令碼的變數

20.1 shell指令碼介紹微信公眾號部落格,20.2 shell指令碼結構和執行建立目錄,然後我們進去在裡面寫指令碼第一行是他表示接下來的命令是通過這一個直譯器操作解析的的,通常都是/bin/bash(如果你是在本機上執行那麼不用寫也行,因為它知道接下來的命令能夠在這臺機

linux利用shell指令碼條件執行命令

在linux環境中,我們總會有一些命令需要經常用,例如經常跳轉到某些目錄下或者執行某些命令,輸入一連串的命令是很煩的,此時我們可以預先寫一些指令碼然後根據我們的選擇自動執行命令,那豈不是完美,本指令碼就是為此而生的(以跳轉不同的目錄舉例,當然也可以執行其他命令,

Shell】關於shell指令碼執行cd命令無效的分析

###Date: 2017/1/7 ###Author: SoaringLee ###Content:關於shell指令碼中執行cd命令無效的分析 ===========================================================

20.1 shell指令碼介紹 20.2 shell指令碼結構和執行 20.3 date命令用法 20.4 shell指令碼的變數

20.1 shell指令碼介紹20.2 shell指令碼結構和執行20.3 date命令用法20.4 shell指令碼中的變數shell指令碼介紹shell是一種指令碼語言可以使用邏輯判斷、迴圈等語法可以自定義函式shell是系統命令的集合shell指令碼可以實現自動化運維,

Shell 指令碼跟蹤除錯命令的執行

shell 指令碼除錯系列 本系列的前面部分清晰地闡明瞭另外兩種 shell 指令碼除錯模式:詳細模式和語法檢查模式,並用易於理解的例子展示瞭如何在這些模式下啟用 shell 指令碼除錯。 概述 shell 跟蹤簡單的來說就是跟蹤 sh