乙個適用於層級目錄結構的makefile模版

2021-09-07 00:22:17 字數 3740 閱讀 4964

今天寫了個層次化的makefile模版,用來自動化編譯專案,這個模版應當包含以下功能:

我的程式的目錄結構是這樣的:

1. 源檔案目錄src,模組***放在src/***下,主程式在src/main下面

2.公共標頭檔案放在include目錄下,模組***的標頭檔案放在include/***目錄下

3.模組輸出的鏈結庫放在lib目錄下

4.可執行檔案放在bin目錄下

先來看一下makefile.env,這個類似於c的標頭檔案,包含了所有makefile的公共部分,

###########  makefile.env  ##########

# top level pattern, include by makefile of child directory

# in which variable like topdir, target or lib may be needed

cc=gcc

make=make

ar=ar cr

rm = -rm -rf

cflags+=-wall

dirs:=$(shell find . -maxdepth 1 -type d)

dirs:=$(basename $(patsubst ./%,%,$(dirs)))

dirs:=$(filter-out $(exclude_dirs),$(dirs))

subdirs := $(dirs)

srcs=$(wildcard *.c)

objs=$(srcs:%.c=%.o)

depends=$(srcs:%.c=%.d)

all:$(target) $(lib) subdirs

$(lib):$(objs)

$(ar) $@ $^

cp $@ $(libpath)

subdirs:$(subdirs)

for dir in $(subdirs);\

do $(make) -c $$dir all||exit 1;\

done

$(target):$(objs)

$(cc) -o $@ $^ $(ldflags)

cp $@ $(exepath)

$(objs):%.o:%.c

$(cc) -c $< -o $@ $(cflags)

-include $(depends)

$(depends):%.d:%.c

set -e; rm -f $@; \

$(cc) -mm $(cflags) $< > $@.$$$$; \

sed 's,\($*\)\.o[:]*,\1.o $@:,g' < $@.$$$$ > $@; \

rm $@.$$$$

clean:

for dir in $(subdirs);\

do $(make) -c $$dir clean||exit 1;\

done

$(rm) $(target) $(lib) $(objs) $(depends)

當前目錄下的子目錄是通過shell命令自動得到的,subdirs:$(subdirs) 這塊會進入每個子目錄執行make,當然有些子目錄並不需要編譯,可以通過exclude_dirs指定,比如頂層目錄的exclude_dirs=bin lib include。

$(depends):%.d:%.c 這塊作用是自動生成標頭檔案依賴,這部分包括5條命令,看起來很複雜,其實原理很簡單,假設main.c,包含標頭檔案depend.h, 解析過程如下:

1. @set –e 命令設定當前shell程序狀態為:如果執行的任何一條命令的退出狀態非零則立刻終止當前程序。

2. rm -f $@ 刪除原來的main.d檔案

3. gcc的-mm引數能夠生成檔案的依賴關係main.o:main.c depend.h,寫入檔案main.d. $$$$,$$是程序號

4. sed命令作用是將main.o:main.c depend.h替換成main.o main.d:main.c depend.h, 並寫入main.d檔案

5. rm -f $@.$$$$刪除臨時檔案

include $(srcs:.c=.d)將main.d包含進來後,makefile增加了以下依賴

main.o main.d:main.c depend.h

不管是main.c還是depend.h的變化都會更新main.o 以及main.d,main.d的更新又反過來更新上面這條依賴關係。

這條依賴下面並沒有對應的命令,為什麼會更新目標檔案呢?這跟makefile的執行步驟有關係,引用下陳浩先生的《跟我一起寫makefile》

gnu的 make 工作時的執行步驟如下:

1、讀入所有的 makefile。

2、讀入被 include 的其它 makefile。

3、初始化檔案中的變數。

4、推導隱晦規則,並分析所有規則。

5、為所有的目標檔案建立依賴關係鏈。

6、根據依賴關係,決定哪些目標要重新生成。

7、執行生成命令。

所以1-5 步為第乙個階段,形成了所有的依賴關係鏈,6-7 為第二個階段,決定了所有需要生成的目標檔案後,執行對應的命令。上面的依賴關係雖然沒有命令,但是確定了main.o要重新生成,就會找到以下編譯模組生成目標檔案

$(objs):%.o:%.c

$(cc) -c $< -o $@ $(cflags)

假設有乙個模組first,原始檔都放在src/first下,makefile如下

topdir=./../..

lib=libfirst.a

incpath=$(topdir)/include/first

libpath=$(topdir)/lib

cflags= -i$(incpath)

include $(topdir)/makefile.env

topdir是相對於頂層目錄的相對路徑,lib是要生成的鏈結庫,這樣只要幾行命令就可以完成當前模組的編譯了,而且first下面還可以新增子模組。

假設main.c在src/main目錄下,呼叫了first模組,makefile如下

topdir=./../..

target=main

libpath=$(topdir)/lib

exepath=$(topdir)/bin

cflags= -i$(topdir)/include/first

ldflags= -lfirst

include $(topdir)/makefile.env

target是生成的可執行檔名,在libpath目錄下尋找鏈結庫,生成的可執行檔案會被mv到exepath目錄下

src下沒有原始檔,只有目錄,所以makefile非常簡單

topdir=./..

include $(topdir)/makefile.env

頂層目錄下的makefile也很簡單,相對增加了exclude_dirs,排除不需要編譯的目錄

topdir=.

exclude_dirs= include bin lib

include $(topdir)/makefile.env

現在只需要在頂層目錄下make一下,src下所有目錄都會編譯,生成的鏈結庫放在lib下,可執行檔案在bin目錄中。如果要增加新的功能模組,只要在src/目錄下新建目錄,增加乙個類似first下的makefile即可,是不是很方便?

出處:

開放乙個適用於管理模組的應用開發框架

管理模組是應用開發過程中最常見的交付成果,大部分的資訊應用都是針對某個場景,開發一些管理模組。每乙個應用的開發,都會使用到框架,每乙個應用的開發,都需要重複開發一些基礎模組。當個人或者小型企業,希望能夠去開發幾個模組時,總會遇到一座大山,那就是基礎模組及架構遠遠比需要開發的模組多得多,對於個人來說,...

適用於python的ATOM外掛程式選擇(純個人喜好)

20180401新增 24.vim mode plus,vim模式 20180404新增 25.django templates,如果你跟我一樣用django,那麼這個外掛程式應該適合你,這個外掛程式解決了django模板語言嵌入html檔案的問題,不過我們需要按照readme的內容進行相應設定,主...

四個適用於企業的採購策略

很多企業主通常需要身兼多職,各種各樣的需求 人員配備,財務,庫存管理,市場營銷和客戶服務 迅速消耗了他們的時間 精力和日常運營。所以,採購往往是事後才考慮的事情 而這應該從戰略上進行。企業用於採購投入物佔銷售收入的45 65 因此,應將採購視為降低成本和提高效率的可行機會。有關企業購買行為的研究表明...