1. 程式人生 > >從頭開始寫專案Makefile(六):引數傳遞、條件判斷、include

從頭開始寫專案Makefile(六):引數傳遞、條件判斷、include

在多個Makefile巢狀呼叫時,有時我們需要傳遞一些引數給下一層Makefile。比如我們在頂層Makefile裡面定義的開啟除錯資訊變數DEBUG_SYMBOLS,我們希望在進入子目錄執行子Makefile時該變數仍然有效,這是需要將該變數傳遞給子Makefile,那怎麼傳遞呢?這裡有兩種方法:
1.     在上層Makefile中使用”export”關鍵字對需要傳遞的變數進行宣告。比如:
DEBUG_SYMBOLS = TRUE
export DEBUG_SYMBOLS
當不希望將一個變數傳遞給子 make 時,可以使用指示符 “unexport”來宣告這個變數。
export一般用法是在定義變數的同時對它進行宣告。如下:
export DEBUG_SYMBOLS = TRUE
2.     在命令列上指定變數。比如:
$(MAKE) -C xxx DEBUG_SYMBOLS = TRUE
這樣在進入子目錄xxx執行make時該變數也有效。
 
像程式語言一樣,Makefile也有自己的條件語句。條件語句可以根據一個變數值來控制make的執行邏輯。比較常用的條件語句是ifeq –else-endif、ifneq-else-endif、ifdef-else-endif。
ifeq關鍵字用來判斷引數是否相等。
比如判斷是否生成除錯資訊可以這麼用:
ifeq ($(DEBUG_SYMBOLS), TRUE)
>---CFLAGS += -g -Wall -Werror -O0
else
>---CFLAGS += -Wall -Werror -O2
endif
Ifneq和ifeq作用相反,此關鍵字是用來判斷引數是否不相等。
ifdef關鍵字用來判斷一個變數是否已經定義。
後兩個關鍵字用法和ifeq類似。
 
現在我們繼續改進我們上一節的Makefile,上一節的Makefile完成Makefile的巢狀呼叫,每一個模組都有自己的Makefile。其實每個模組的Makefile都大同小異,只需要改改最後編譯成生成的目標名稱或者編譯連結選項,規則都差不多,那麼我們是否可以考慮將規則部分提取出來,每個模組只需修改各自變數即可。這樣是可行的,我們將規則單獨提取出來,寫一個Makefile.rule,將他放在頂層Makefile同目錄下,其他模組內部的Makefile只需要include該Makefile就可以了。如下:
include $(SRC_BASE)/Makefile.rule
include類似於C語言的標頭檔案包含,你把它理解為為本替換就什麼都明白了。
這樣以後規則有修改的話我們直接修改該Makefile就可以了,就不用進入每一個模組去修改,這樣也便於維護。
這樣我們今天頂層Makefile稍作修改:
# Top Makefile for C program                                                                                                                                                             
# Copyright (C) 2014 shallnew \at 163 \dot com
 
export DEBUG_SYMBOLS = TRUE
 
DIR = src
MODULES = $(shell ls $(DIR))
# MODULES = ipc main tools
 
all : $(MODULES)
 
$(MODULES):
>---$(MAKE) -C $(DIR)/

[email protected]
 
main:tools ipc
 
clean :
>[email protected] subdir in $(MODULES); \
>---do $(MAKE) -C $(DIR)/$$subdir [email protected]; \
>---done
 
distclean:
>[email protected] subdir in $(MODULES); \
>---do $(MAKE) -C $(DIR)/$$subdir [email protected]
; \
>---done
 
tags:
>---ctags -R
 
help:
>[email protected] "===============A common Makefilefor c programs=============="
>[email protected] "Copyright (C) 2014 liuy0711 \at 163\dot com"
>[email protected] "The following targets aresupport:"
>[email protected]

>[email protected] " all              - (==make) compile and link"
>[email protected] " clean            - clean target"
>[email protected] " distclean        - clean target and otherinformation"
>[email protected] " tags             - create ctags for vimeditor"
>[email protected] " help             - print help information"
>[email protected]
>[email protected] "To make a target, do 'make[target]'"
>[email protected] "========================= Version2.2 ======================="
 
.PHONY : all clean distclean tags help
目前我們頂層目錄下的目錄樹為:
.
├── include
│   ├── common.h
│   ├── ipc
│   │   └── ipc.h
│   └── tools
│       ├── base64.h
│       ├── md5.h
│       └── tools.h
├── libs
├── Makefile
├── Makefile.rule
└── src
    ├── ipc
    │  ├──inc
    │  ├──Makefile
    │  └──src
    │       └── ipc.c
    ├── main
    │  ├──inc
    │  ├──Makefile
    │  └──src
    │       ├── main.c
    │       └── main.c~
    └── tools
        ├── inc
        ├── Makefile
        └── src
            ├── base64.c
            ├── md5.c
            └── tools.c
 
14 directories, 16 files
每個子模組下的Makefile刪除規則後修改為如下:
 
SRC_BASE = ../..
 
CFLAGS +=
CPPFLAGS += -I. -I./inc -I$(SRC_BASE)/include
 
# SRC_OBJ = $(patsubst %.c, %.o, $(wildcard *.c))
SRC_FILES = $(wildcard src/*.c)
SRC_OBJ = $(SRC_FILES:.c=.o)
SRC_LIB = libtools.a
 
include $(SRC_BASE)/Makefile.rule
而處於頂層目錄下的Makefile.rule專門處理各模組編譯連結時需要的規則。內容如下:
# Copyright (C) 2014 shallnew \at 163 \dot com                                                                                                                                           
 
ifeq ($(DEBUG_SYMBOLS), TRUE)
>---CFLAGS += -g -Wall -Werror -O0
else
>---CFLAGS += -Wall -Werror -O2
endif
 
all : $(SRC_BIN) $(SRC_LIB)
 
ifneq ($(SRC_BIN),)
$(SRC_BIN) : $(SRC_OBJ)
>---$(CC) -o [email protected] $^ $(LDFLAGS)
endif
 
ifneq ($(SRC_LIB),)
$(SRC_LIB) : $(SRC_OBJ)
>---$(AR) rcs [email protected] $^
>---cp [email protected] $(SRC_BASE)/libs
endif
        
# clean target
clean:
>---$(RM) $(SRC_OBJ) $(SRC_LIB) $(SRC_BIN)$(SRC_BIN).exe
 
distclean:
>---$(RM) $(SRC_OBJ) $(SRC_LIB) $(SRC_BIN)$(SRC_BIN).exe $(SRC_BASE)/libs/* $(SRC_BASE)/tags *~
 
.PHONY : all clean disclean
~
我們將Makefile.rule放在頂層有可能會一不小心在命令列上面執行了該Makefile,如下:
# make -f Makefile.rule
make: Nothing tobe done for `all'.
#
由於我們沒有定義變數$(SRC_BIN)和$(SRC_LIB),偽目標all沒有任何依賴,所以編譯是無法成功的。這裡我們我們應該禁止直接執行該Makefile。
在make裡面有這樣一個變數:MAKELEVEL,它在多級呼叫的 make 執行過程中。變數代表了呼叫的深度。在 make 一級級的執行過程中變數MAKELEVEL的值不斷的發生變化,通過它的值我們可以瞭解當前make 遞迴呼叫的深度。頂層的MAKELEVEL的值為“0” 、下一級時為“1” 、再下一級為“2”.......,所以我們希望一個子目錄的Makefile必須被上層 make 呼叫才可以執行,而不允許直接執行,我們可以判斷變數MAKELEVEL來控制。所以我們這一節最終的Makefile.rule為:

# Copyright (C)2014 shallnew \at 163 \dot com
 
ifeq ($(DEBUG_SYMBOLS),TRUE)
>---CFLAGS +=-g -Wall -Werror -O0
else
>---CFLAGS +=-Wall -Werror -O2
endif
 
ifeq($(MAKELEVEL), 0)                                                                                                                                                                   
all : msg
else
all : $(SRC_BIN)$(SRC_LIB)
endif
 
ifneq ($(SRC_BIN),)
$(SRC_BIN) :$(SRC_OBJ)
>---$(CC) -o [email protected]$^ $(LDFLAGS)
endif
 
ifneq($(SRC_LIB),)
$(SRC_LIB) :$(SRC_OBJ)
>---$(AR) [email protected] $^
>---cp [email protected]$(SRC_BASE)/libs
endif
 
msg:
>[email protected]"You cannot directily execute this Makefile! This Makefile should calledby toplevel Makefile."
 
# clean target
clean:
>---$(RM)$(SRC_OBJ) $(SRC_LIB) $(SRC_BIN) $(SRC_BIN).exe
 
distclean:
>---$(RM)$(SRC_OBJ) $(SRC_LIB) $(SRC_BIN) $(SRC_BIN).exe $(SRC_BASE)/libs/*$(SRC_BASE)/tags *~
 
.PHONY : all cleandisclean 
此時再直接執行該Makefile:

# make -f Makefile.rule
You cannot directily execute this Makefile! This Makefile should called by toplevel Makefile.
#
--------------------- 
作者:shallnet 
來源:CSDN 
原文:https://blog.csdn.net/shallnet/article/details/37657597 
版權宣告:本文為博主原創文章,轉載請附上博文連結!