Android.mk(4) 依賴:目標編程的模式

來源:互聯網
上載者:User

標籤:著作權   distrib   bst   hello   perm   cal   c++   mpi   自己   

https://www.jianshu.com/p/3777a585a8d0

 

另一種範式

我一直覺得,Makefile確實是C/C++程式員的良配,因為Makefile所使用的兩種範式都是C/C++程式員不熟悉的,一種是函數式的思想,一種是依賴構成的目標鏈的模式。

Makefile從最基本上來說,可以抽象成下面這樣的:

    target ... : prerequisites ...            command            ...            ...

如大家所熟悉的,這段的意義是:當prerequisites有更新的時候,執行command命令。如果target是一個真實的目標,也就是對應一個真實的檔案,那麼就產生這個檔案。如果是偽目標,可以被用來做為一個入口,比如clean,也可以成為一個真實目標的依賴。
可以明顯地分為兩個部分:一個是target依賴鏈的範式,這與過程式語言的C語言非常不同。用蔣軍的話講,跟Prolog有點像。有著它自己的一套邏輯系統。
後面的command,我們前面講了不少了,我個人是希望大家以函數式的思想來寫。

我們落地到一個實際的例子中:

$(BUILT_SYSTEMIMAGE): $(FULL_SYSTEMIMAGE_DEPS) $(INSTALLED_FILES_FILE)    $(call build-systemimage-target,[email protected])

這個$(BUILT_SYSTEMIMAGE),是個真實的目標,對應了要產生的檔案system.img,如下:

BUILT_SYSTEMIMAGE := $(systemimage_intermediates)/system.img

下面來看看,system.img所依賴目標,先看第一個,結果這一個實際上又是兩個:

FULL_SYSTEMIMAGE_DEPS := $(INTERNAL_SYSTEMIMAGE_FILES) $(INTERNAL_USERIMAGES_DEPS)

然後,我們發現這個依賴在一層層地擴張:

INTERNAL_SYSTEMIMAGE_FILES := $(filter $(TARGET_OUT)/%,     $(ALL_PREBUILT)     $(ALL_COPIED_HEADERS)     $(ALL_GENERATED_SOURCES)     $(ALL_DEFAULT_INSTALLED_MODULES)     $(PDK_FUSION_SYSIMG_FILES)     $(RECOVERY_RESOURCE_ZIP))

擴張還在繼續,比如,對於ALL_PREBUILT,各個模組不斷地把自己的東西增加進去:

ALL_PREBUILT += $(TARGET_OUT)/bin/monkey

其他的目標原理相通,這裡就不多浪費篇幅了。
總而言之,這一大套目標中,只要有任何一個有變化,system.img就要重建了。如何產生?在下一行中寫著呢:調用build-systemimage-target啊。

Makefile寫作指南

目標式和函數式兩種範式都學好了,下面是我們如何組織材料來完成我們的工程的時候了。

  1. 先定義總目標
    Makefile的總的目的是輸出一個或多個結果檔案,先把總的目標定義好。
    然後假設子目標都已經構建好了,下面寫一個將這些中間產品變成最終目標的指令碼。
    比如編譯一個簡單的C程式,總的目標是一個可執行檔,最終加工時的材料是已經編譯好的.o檔案和輸入的第三方的庫檔案等,我們先不管它們是如何編譯的,假設它們已經做好了,我們只要寫一個連結的指令碼就好了。
    像我們上面的system.img的例子,反正依賴多,就分門別類的列吧,最終我們只需要把它們打個包就好了。
  2. 層層分解,逐步完成
    然後去尋找,構成這個大目標的第一層的構件是什麼,像上面我們所看過的一樣,逐層擴張。
    對於C檔案,這時候才考慮每一個.o是如何從源檔案編譯的。
  3. 模組化、函數化
    上面兩步都是目標模式的,這一步開始搞函數模式了。將各目標中可重用的函數抽象出來,該分檔案就分檔案,該整理代碼就整理代碼等
  4. 測試調優
    當一個工程大到一定程度的時候,Makefile的可讀性會嚴重下降。
    這時候我們還是按目標式和函數式兩條主線來降低複雜度。目標是層次式的,我們可以一層一層地調試,比如先調從.c到.o的編譯過程,再調將.o連結起來的總裝部分.
    哪一個子模組出問題,就專門調那一部分的。
    對於功能部分,我們一直強調函數式思想就是希望,對於某一個確實性的輸入,能有一個確定性輸出,沒有副作用,這樣能夠將調試的難度降低,我們可以一個函數一個函數地調試。
    Makefile的調試以打日誌為主,還可以通過make -p來輸出完整的變數和目標列表。
make -p,看看make都做了些什麼

下面是我在cygwin下的make -p的輸出結果的節選

Make工具的資訊

首先是Make工具彙報下自己的基礎情況:

The files is:main.cpp# GNU Make 4.1# Built for x86_64-unknown-cygwin# Copyright (C) 1988-2014 Free Software Foundation, Inc.# License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html># This is free software: you are free to change and redistribute it.# There is NO WARRANTY, to the extent permitted by law.# make 資料基礎,列印在 Tue May  3 17:54:36 2016
變數

下面是變數的列表,包含我們自己定義的,也包含make自動為我們產生的。

# 變數# ‘override‘ directiveGNUMAKEFLAGS := # 自動<D = $(patsubst %/,%,$(dir $<))# 自動?F = $(notdir $?)# 預設.SHELLFLAGS := -c# makefile (from ‘Makefile‘, line 30)result_findString2 := # makefileMAKEFLAGS = p# 預設CWEAVE = cweave# 自動?D = $(patsubst %/,%,$(dir $?))# 環境!:: = ::# 自動@D = $(patsubst %/,%,$(dir [email protected]))# 環境HOMEDRIVE = C:# 自動@F = $(notdir [email protected])# 自動^D = $(patsubst %/,%,$(dir $^))# makefileCURDIR := /cygdrive/d/working/codeBlocks/Hello# makefileSHELL = /bin/sh# 預設RM = rm -f# 預設CO = co...
目錄資訊
# 目錄# SCCS:無法對其進行 stat 操作。# . (裝置 114478965,i-節點 1688849860268365):10 檔案, 19 不可能.# RCS:無法對其進行 stat 操作。# 10 檔案, 19 不可能在 3 目錄中。
隱含規則資訊
# 隱含規則。%.out:%.a:%.ln:%.o:%: %.o#  recipe to execute (內建):    $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o [email protected]%.c:%: %.c#  recipe to execute (內建):    $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o [email protected]%.ln: %.c#  recipe to execute (內建):    $(LINT.c) -C$* $<%.o: %.c#  recipe to execute (內建):    $(COMPILE.c) $(OUTPUT_OPTION) $<%.cc:%: %.cc#  recipe to execute (內建):    $(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o [email protected]%.o: %.cc#  recipe to execute (內建):    $(COMPILE.cc) $(OUTPUT_OPTION) $<%.C:%: %.C#  recipe to execute (內建):    $(LINK.C) $^ $(LOADLIBES) $(LDLIBS) -o [email protected]%.o: %.C#  recipe to execute (內建):    $(COMPILE.C) $(OUTPUT_OPTION) $<%.cpp:%: %.cpp#  recipe to execute (內建):    $(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o [email protected]%.o: %.cpp#  recipe to execute (內建):    $(COMPILE.cpp) $(OUTPUT_OPTION) $<%.p:%: %.p#  recipe to execute (內建):    $(LINK.p) $^ $(LOADLIBES) $(LDLIBS) -o [email protected]%.o: %.p#  recipe to execute (內建):    $(COMPILE.p) $(OUTPUT_OPTION) $<...
檔案目標和假目標
# 檔案# 不是一個目標:.web.p:#  Builtin rule#  對隱含規則的搜尋尚未完成。#  從不檢查修改時間。#  檔案尚未被更新。#  recipe to execute (內建):    $(TANGLE) $<# 不是一個目標:.l.r:#  Builtin rule#  對隱含規則的搜尋尚未完成。#  從不檢查修改時間。#  檔案尚未被更新。#  recipe to execute (內建):    $(LEX.l) $< > [email protected]      mv -f lex.yy.r [email protected]all8:#  假目標 (.PHONY的前提)。#  對隱含規則的搜尋尚未完成。#  檔案不存在。#  檔案尚未被更新。#  recipe to execute (from ‘Makefile‘, line 66):    @echo $(filter-out default interpreter jit optimizing,xoc)    @echo $(filter-out default interpreter jit optimizing,default)all9:#  假目標 (.PHONY的前提)。#  對隱含規則的搜尋尚未完成。#  檔案不存在。#  檔案尚未被更新。#  recipe to execute (from ‘Makefile‘, line 75):    $(eval ARCH_OF_BOOT_OAT := $(lastword $(subst /, ,$(dir $(BOOT_ART_SRC)))))    $(eval OAT_TEMP := $(PRODUCT_OUT)/data/dalvik-cache/temp-oat/system/framework/$(ARCH_OF_BOOT_OAT))    $(eval OAT_SRC := $(patsubst %.art,%.oat,$(BOOT_ART_SRC)))    $(eval OAT_DIST := $(patsubst %.art,%.oat,$(BOOT_ART_DST)))    @echo $(ARCH_OF_BOOT_OAT)    @echo $(OAT_TEMP)    @echo $(OAT_SRC)    @echo $(OAT_DIST)...


Jtag特工
連結:https://www.jianshu.com/p/3777a585a8d0
來源:簡書
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。

Android.mk(4) 依賴:目標編程的模式

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.