簡體   English   中英

當依賴項列表更改時重新鏈接 Makefile 目標

[英]Relink Makefile target when list of dependencies changes

我在 Makefile 中看到的一個常見問題是,當依賴項列表更改時,不一定要重新鏈接可執行文件(和庫)。 例如:

SRCS=$(wildcard *.c)
CPPFLAGS=-MMD -MP
target: $(SRCS:.c=.o)
        $(CC) $(LDFLAGS) $^ -o $@
-include $(SRCS:.c=.d)

到目前為止,一切都很好:它會自動處理對源文件及其包含的依賴項的任何更改。 如果添加了一個文件(由於通配符,這意味着只需將其添加到目錄中,但顯式列表將具有相同的問題),make 會看到它並重新鏈接目標。 然而,當一個源文件被刪除時,make 並不知道目標文件需要重建。

我如何讓 make(特別是 gmake)來處理這種情況?

誠然,這並不完全是一種常見情況,因為刪除文件很可能意味着也必須更改其他文件,這無論如何都會強制重新鏈接,但我以前見過這種情況。

我提出了兩種解決方案,但都不是理想的。 首先,如果我們使源列表顯式而不是通配符,我們可以使目標依賴於 Makefile。 更改 Makefile 以刪除源文件會導致目標重新鏈接。 這有兩個問題。 首先,您必須在鏈接之前從 $^ 中刪除 Makefile,這有點難看(但可以通過過濾器刪除)。 其次,這個 Makefile 旨在成為一個模板,包含在其他 Makefile 中(指定源和目標)——我們必須讓目標依賴於那個Makefile。 啊。

第二種解決方案是包含一些類似如下的邏輯:

SRCS=$(wildcard *.c)
CPPFLAGS=-MMD -MP
target: $(SRCS:.c=.o)
        $(CC) $(LDFLAGS) $^ -o $@
        @echo '$$(if $$(filter-out $$(SRCS:.c=.o), $(SRCS:.c=.o)), .PHONY:target)' > target.d
-include $(SRCS:.c=.d)
-include target.d

這將生成一個 target.d 文件,用於跟蹤依賴項列表並在刪除任何內容時強制重建目標。 它有效,但它很丑陋。 它也不能解釋由包含的 Makefile 指定的任何其他非源依賴項。

有沒有官方的方法可以做到這一點,或者至少有更好的方法?

(順便說一句,如果可能的話,我還想在刪除源文件時清理關聯的對象和依賴項文件。通過擴展我的第二個解決方案並使其更加丑陋,這可能是可能的。)

要正確地做到這一點,您可能不得不求助於Paul Smith 的 Advanced Auto-Dependency Generation Paul 是 GNU make 的當前維護者,並描述了所有與依賴生成相關的常見問題(及其解決方案!)。

還推薦了他網站上的其他白皮書。

我使用他的技巧和竅門已經好幾年了,而且——即使它偶爾會變得有點復雜——研究它們每一秒都是值得的。

您需要更智能的 gmake 版本。 ElectricMake 是一個與 gmake 兼容的替代品,它包括一個分類帳功能,它基本上使最新檢查比僅僅檢查輸出比輸入新更復雜。 特別是,分類帳將散列目標的輸入列表,如果該列表發生更改,它將導致重建輸出:

# cat Makefile
out: a b c
        @echo out from $^
        @touch out
# emake --emake-ledger=timestamp
out from a b c
# emake --emake-ledger=timestamp
make: `out' is up to date.
# vi Makefile ;# Remove 'c' from the prereq list.
# cat Makefile
out: a b
        @echo out from $^
        @touch out
# emake --emake-ledger=timestamp
out from a b

如果你想嘗試一下,你可以得到一個 eval copy

理想情況下,應該只有一個 make 模式規則來完成所有鏈接(好吧,一個用於可執行文件,一個用於共享庫,一個用於存檔)。 就像是:

# rules.mk
$(BUILD_DIR}/exe/% : rules.mk
    g++ -o $@ $(filter-out %.mk,$^)

接下來,當您定義構建目標時,使它們依賴於自己的 makefile:

# project_a.mk
$(BUILD_DIR}/exe/a : project_a.mk ${a_obj}

通常,此依賴項將包含在宏中:

define EXE_TARGET
  $(BUILD_DIR}/exe/${1} : ${2}
  $(BUILD_DIR}/exe/${1} : $(lastword $(MAKEFILE_LIST))
endef

所以在 project_a.mk 中它會做:

# project_a.mk
$(eval $(call EXE_TARGET,a,${a_obj}))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM