linux:make命令與makefile文件

1. 作用

通俗的來講:
其實和 shell 腳本差不多,只不過有一些自己的規則可以讓你使用起來更方便,比如你寫 shell 腳本的話,只能寫在一個文件裏然後執行這個文件,makefile 可以讓你執行這個裏面的某一條命令。

2. 格式

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

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

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

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

2.1 目標

當目標是文件名的時候,比如這時的目標是a.txt:

a.txt: b.txt c.txt
    cat b.txt c.txt > a.txt

當目標爲一個操作的名字時,比如這個clean,稱爲‘僞目標’,但是當你執行 make clean 的時候,如果正好有一個文件叫做clean,那麼這個命令不會執行。因爲Make發現clean文件已經存在,就認爲沒有必要重新構建了,就不會執行指定的rm命令。

clean:
      rm *.o

所以,一般我們會明確聲明clean是"僞目標":

.PHONY: clean
clean:
        rm *.o temp

多個僞目標直接用空格隔開

像.PHONY這樣的內置目標名還有不少,可以查看手冊

2.2 前置條件

2.3 命令

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

上面代碼執行後(make var-lost),取不到foo的值。因爲兩行命令在兩個不同的進程執行。一個解決辦法是將兩行命令寫在一行,中間用分號分隔。

  1. 兩行命令寫在一行,中間用分號分隔。
  2. 換行符前加反斜槓轉義。
  3. 加上.ONESHELL:
var-kept:
    export foo=bar; echo "foo=[$$foo]"
var-kept:
    export foo=bar; \
    echo "foo=[$$foo]"
.ONESHELL:
var-kept:
    export foo=bar; 
    echo "foo=[$$foo]"

3. 語法

3.1 註釋

用 #

3.2 回聲

make會打印每條命令,然後再執行,這就叫做回聲(echoing)。
在命令的前面加上@,就可以關閉回聲。
注:通常只在註釋和純顯示的echo命令前面加上@。

test:
    @# 這是測試
    @echo TODO

3.3 通配符

*、? 、[…]

3.4 變量與賦值

txt = Hello World
test:
    @echo $(txt)

用Shell變量,需要在美元符號前,再加一個美元符號,這是因爲Make命令會對美元符號轉義。

test:
    @echo $$HOME
VARIABLE = value
# 在執行時擴展,允許遞歸擴展。

VARIABLE := value
# 在定義時擴展。

VARIABLE ?= value
# 只有在該變量爲空時才設置值。

VARIABLE += value
# 將值追加到變量的尾端。

3.5 自動變量

1、$@
$@指代當前目標,就是Make命令當前構建的那個目標。比如,make foo的 $@ 就指代foo。

2、$<
<t:p1p2< 指代第一個前置條件。比如,規則爲 t: p1 p2,那麼< 就指代p1。

等等…

3.6 判斷與循環

ifeq ($(CC),gcc)
  libs=$(libs_for_gcc)
else
  libs=$(normal_libs)
endif
LIST = one two three
all:
    for i in $(LIST); do \
        echo $$i; \
    done

# 等同於

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

3.7 函數

$(function arguments)
# 或者
${function arguments}

Makefile提供了許多內置函數,可供調用。下面是幾個常用的內置函數。
1、shell 函數:
用來執行 shell 命令

srcfiles := $(shell echo src/{00..99}.txt)

2、call 函數:

$(call variable,param,param,…)
$(1),$(2)等等表示param,param,…

等等…還有好多函數

最後的實踐

我項目中的一些實踐:

SHELL := /bin/bash

.PHONY: prerequ-program client server prod_server prod_client


install:|prerequ-program

define require_install
	if test "$(shell which $(1))" = ""; \
	then \
		brew install $(2); \
	else \
		echo $(1) is exists. skip install; \
	fi
endef

prerequ-program:
	@$(call require_install,mongod,mongo)
	mkdir -p ./db/
	if [ "${shell pgrep mongod}" = "" ]; then mongod --bind_ip 127.0.0.1 --fork --dbpath ./db/ --logpath ./db/mongod.log; fi
	@echo "start mongod success!"

# 開發模式
server:
	cd server && npm install && npm run dev

client:
	cd client && npm install && npm run dev

# 生產模式
prod_server:
	cd server && npm install && npm start

prod_client:
	cd client && npm install && npm run build

比如我的項目要安裝 mongodb,那麼調用shell函數判斷一下有沒有 mongod,沒有的話就 brew install mongo,否則在當前目錄下新建文件 mkdir -p ./db/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章