Make 教程

代碼的編譯過程:  php

  1. 不管是c , c++ , php , 等 首先須要將源文件編譯成中間代碼文件 (Object File) 此過程 ,美其名曰:編譯
    • windows 下稱爲 .obj 文件
    • unix  下是 .o 文件 
    • 編譯主要檢查語法的正確性
  2. 大量的中間代碼文件 合併成可執行文件  此過程,美其名曰:連接 【也有人叫編排】
    • 主要連接函數和全局變量
    • 連接須要明顯指出中間目標文件名稱

  ps: 當中間文件太多的時候編譯起來就很不方便,一般咱們會將其打包,windows 下叫庫文件(Library File , .lib 文件),Unix 下 是 Archive File , 也就是  .a 文件html

 

Make 概念node


 

  Make 這個詞,英語意思爲「製做」。 Make 命令直接使用了這個意思,就是要作出某個文件出來。 好比我要作出文件  a.txt ,就能夠直接使用   c++

make a.txt

 

  可是,若是你真的輸入這條命令,它不會起到任何做用,由於 Make 自己並不知道,如何作出  a.txt 須要有人告訴它怎麼去作出a.txt 文件。shell

  用例一:windows

   a.txt 文件依賴於  b.txt 和  c.txt 這兩個文件,是後面兩個文件內容的集合。那麼make 須要知道下面的規則。bash

  

a.txt: b.txt c.txt  #第一步
    cat b.txt c.txt > a.txt #第二步

  解析:函數

    第一步:確認 b.txt 和  c.txt 這兩個文件必須已經存在。工具

    第二步:  使用cat 命令將這兩個文件合併起來了,輸出爲新文件。ui

  總結:

  1. 像上面描述的這種規則默認都寫在了一個叫 Makefile 的文件中,而咱們大名鼎鼎的 make 命令就依賴這個文件進行構建。
  2. Makefile 也能夠寫成  makefile 
  3. 若是你實在不想使用makefile 或者 Makefile 來命名你的規則文件,例如使用  aaaa.txt  ,你能夠使用 make  的 -f  參數來指定 :  make  -f  aaaa.txt
  4. make 只是一個根據指定Shell 命令進行構建的工具而已,它的規則:
    • 你規定要構建哪些文件 【 target】
    • 它依賴於哪些源文件 【 prerequisits】
    • 當哪些文件由變更是,如何從新構建它 【 commands】

 

Makefile 文件格式


 

  構建規則都寫在了Makefile 文件中,要學會如何Make 命令,就必須先學會如何編寫Makefile 文件

 

概述:


 

  Makefile 文件由一系列規則構成,格式:

<target>  :<prerequisites>

    <commands>

  解析:

    target  :  目標,必須的

    prerequisites: 前置條件,可選

    commands: 命令,它前面須要跟着一個空格 , 可選

 

目標<target>


  一個目標(target) 就構成了一個規則,目標一般是文件名,指明make 命令所要構建的對象,好比上文的  a.txt 。  目標能夠是一個文件名,也能夠是多個文件名,之間用空格隔開。

  除了文件名,目標還能夠是操做名或任意字母組成的字符串,這類目標稱爲 「僞目標」 (phony target)

  

 

  上面代碼的目標是  bb , 它不是文件名 , 而是一個操做名,屬於「僞目標」 , 做用是列舉根目下的文件或目錄

  ps :  僞目標,系統是不會去檢查bb 文件是否存在的。而是每次執行都執行對應的命令。

  可是,若是目錄中恰好有個文件就叫bb , 那麼bb 也就變成了「目標」了,避免這種狀況,能夠使用以下命令

.PHONY: bb
clean:
  ls /

  經過 ".PHONY" 能夠用來指定僞目標,這種內置目標名還有不少,能夠查看手冊  

 

前置條件   prerequisites


  前置條件一般是一組文件名,之間用空格分隔。它指定了「目標」 , 是否重現構建的判斷標準:只要有一個前置文件不存在或者被更新了,目標就須要從新構建

  用例一:

result.txt:  source.txt
  cp source.txt  result.txt

  

  解析:

    上面的代碼中,構建了目標  result.txt   ,  它的前置條件是  source.txt   已經存在了,那麼 make  result.txt  能夠正常運行,不然必須再寫一條規則,來生成  source.txt 

 

  用例二:

 source.txt:
  echo " hello world" >  source.txt

  解析:

    上面的代碼中,source.txt 後面沒有前置條件 , 這意味着這個「source.txt」目標不依賴其它文件,直接運行它的  commands  就行了。只要source.txt 不存在 , 每次調用  make  source.txt 它都會生成 source.txt

    若是你連續執行兩次  make  source.txt , 它只會執行第一次就不會再執行了

  

  用例三:  

source: a.txt  b.txt  c.txt

  解析:

    source  是一個僞目標 , 它只有三個前置條件 , 沒有任何的 commands 。做用:一次性建立a.txt , b.txt , c.txt 這三個文件。 

 

命令(commands)


 

  命令就是一堆shell  命令組成的,它是構建「目標」 的具體指令,它的運行結果一般就是生成目標文件。每行命令以前必須有一個tab鍵,若是要使用其它鍵,能夠使用內置變量 .RECIPEPREFIX 聲明

  用例一:

.RECIPEPREFIX = >
all:
> echo Hello , world

  解析:

    上面的代碼就是用 .RECIPEPREFIX 來指定了每行命令開頭 是  而再也不是 tab鍵

   

  用例二:

var-lost:
  export foo=bar
  echo "foo=[$$foo]"

  解析:

    commands 中的每條獨自換行的命令都是獨立分開的,不在同一個進程了,因此數據也是不共享的

    第一行的 定義的變量  foo  是不能在  第二行中使用的

    解決辦法就是: 

    1. 將這兩個shell命令合併爲一條,中間用  分號 ";"  隔開 
    2. 若是感受太才了,那麼就就能夠在  分號 後面加個  反斜杆進行轉義  "  \ "
    3. 感受加 \  太扯,那麼你能夠使用 內置命令  .ONESHELL 來指定
var-kept:
  export foo=bar; echo "foo=[$$foo]"

或者

var-kept:
  export foo=bar;\
  echo "foo=[$$foo]"

或者

.ONESHELL
var-kept:
  export foot=bar;
  echo "foo=[$$foo]"

Makefile 文件的語法  


 

 

註釋  : 


 

  在Makefile 文件中 註釋符是:   # 

 

回聲:


 

  正常狀況下 , make 會 打印每條命令 , 而後再執行, 這叫作回聲(echoing).

  若是你想關閉回聲,直接在shell  命令行前面加一個 @  符號就行了

test:
  # this is test
  @echo TODO

  

通配符:


 

  通配符 , 用來指定符合條件的文件名的。 Makefile 的通配符與Bash  一致 , 主要有  *  ,  ?   好比以o 結尾的文件  能夠這樣  *.o

 

模式匹配


 

  Make 命令 容許 對文件名 , 進行相似正則運算的匹配 , 主要用到的匹配符是  %  , 好比須要找到 當前目錄下 有  f1.c  和 f2.c 兩個源碼文件,須要將它們編譯僞對應的對象文件

%.o : %.c

等同於

f1.o :f1.c
f2.o :f2.c

  

變量和賦值符


 

  Makefile 中容許使用   等號 「 = 」 來 自定義變量

bb = Hello  World
test:
  @echo $(bb)
  @echo $$HOME

  解析:

    變量bb  等於 Hello  World  ,  變量調用是經過   $()  來調用的。

    若是你要調用Shell  自帶的一些變量,那麼你須要在  美圓符號前面再加一個美圓符號, 由於  Makefile 中會對美圓符號進行轉義

  

  Makefile 中提供了  4中賦值運算符(  =  ,  :=  , ?=  , += )  :

#執行時擴展, 容許遞歸擴展

key = value 

 

#定義是擴展

key := value

 

#只有在該變量爲空時才設置值

key ?= value

 

#將值追加到變量的尾端

key += value

 

內置變量


 

Make  命令提供了一系列的內置變量,詳情見手冊 

 

自動變量


 

  Make 命令提供了一些自動變量,他們的值與當前規則有關。

  (1)$@ :  

      代指當前目標,就是Make  命令當前構建的那個目標, 好比  make foo  的  $@ 就值  foo

a.txt  b.txt:
  touch $@

等同於

a.txt: 
  touch a.txt

b.txt: 
  touch b.txt

  (2) $<

    代指第一個前置條件

a.txt : b.txt c.txt
  cp $< $@

等同於

a.txt: b.txt c.txt
  cp b.txt a.txt  

  (3) $?

    代指比目標更新的全部前置條件 【即:更新的依賴文件】,好比,  t1: p1 p2 ,  p2 的時間戳比t1 新,那麼 $? 就代指  p2

 

  (4) $^

    代指全部前置條件

  

     (5) $*

    代指匹配符 % 匹配成功的部分 , 好比   %匹配  f1.txt 中的  f1 , 那麼  $* 就表示   f1

 

     (6) $(@D)  和 $(@F)

     $(@D)  和 $(@F) 分別代指:  $@ 的目錄名和文件名

    (7)$(<D)  和  $(<F)

     $(<D)  和  $(<F) 分別代指: $<  的目錄名和文件名

   其它的自動變量請查看手冊 

  

  用例一:

dest/%.txt:  src/%.txt
  @[ -d dest ] || mkdir dest
  cp $< $@

  解析:

    1. 上面的代碼就是將  src  目錄下的  txt 文件 拷貝到 dest  目錄下 。 

    2.  @[-d dest] ||  mkdir dest  :   是說  判斷 dest 目錄是否存在,不存在則建立之 , 而且關閉回聲

    3.  cp $<  $@ :  將 src 中的 txt  拷貝到  dest 目錄下

 

判斷和循環


  Makefile  使用Bash 語法,完成了 判斷和循環

  用例一:

ifeq ($(CC),gcc)
  libs=$(libs_for_gcc)

else
  libs=$(normal_libs)
endif

  

  用例二:

   

LIST = one  two three
test:
  for i in $(LIST); do \
    echo $$i; \
  done

等同於

test:
  for i in one two three; do \
    echo $i; \
  done

  

函數


 

  Makefile 還能夠使用函數 , 它許多內置函數  見手冊

  格式:

$(function arguments)

或者

${function arguments}

  

 

Makefile 實例


 

  編譯 c語言項目

edit: main.o  kbd.o  command.o  display.o
  cc -o edit main.o kbd.o command.o display.o
main: 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
  cc -c display.c
clean:
  rm edit main.o kbd.o command.o display.o
.PHONY: edit clean
相關文章
相關標籤/搜索