2015-06-15 131 views
1

我想建立一個功能到我的makefile,讓我來指定庫某個庫取決於生成文件庫的依賴 - 解決循環依賴

名單這將允許一個圖書館的家屬被自動如果該庫的依賴關係被重建,則重建,並且還將鏈接添加到鏈接行。

我問的SO here一個相關的問題,並通過給答案的工作,我想出了下面的測試

uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1))) 
expand-deps = $1 $(foreach _,$1, $(call expand-deps,$($__deps))) 
make-dep-list = $(call uniq,$(call expand-deps,$1)) 

define make-lib 
    $(warning $1_deps: $2) 
    # capture the list of libraries this library depends on 
    $1_deps = $2 
endef 

define make-bin 
    # show the fully expanded list of libraries this binary depends on 
    $(warning $1 dep-list: [$(call make-dep-list,$2)]) 
endef 

#$(eval $(call make-lib, thread, log utils)) circular-dependency log->thread; thread->log 
$(eval $(call make-lib, thread, utils)) 
$(eval $(call make-lib, log, thread)) 
$(eval $(call make-lib, order, log)) 
$(eval $(call make-lib, price, log)) 
$(eval $(call make-bin, test, order price)) 

運行上面的makefile產生以下結果:

$ make 
makefile:15: thread_deps: utils 
makefile:16: log_deps: thread 
makefile:17: order_deps: log 
makefile:18: price_deps: log 
makefile:19: test dep-list: [order price log thread utils ] 
make: *** No targets. Stop. 

庫可能具有循環依賴關係。

舉個例子:日誌庫是多線程的,所以需要線程庫。線程庫可以發出日誌語句,所以需要日誌庫。

如果我取消了具有循環依賴

$(eval $(call make-lib, thread, log utils)) 
$(eval $(call make-lib, log, thread)) 

生成文件將陷入無限循環線路。

我該如何讓用戶指定循環依賴關係並跳出無限循環?

+0

只是一個樣式:最好不要在'$(call ...)'(或者在_make_函數中的任何逗號後面)逗號後留空格。這些空間不會消失 - 它們最終會在參數的開始處('$ 1','$ 2'等)出現。這會讓你感到困惑(例如,連接標識符時)。只要戒除習慣! – bobbogo

+1

是的,圖書館可以有圓形圖案,但有點臭。如果你能避免它,不要這樣做。在鏈接時,您需要讓鏈接器重複鏈接,直到滿足所有依賴關係。 VisualC++ _link_默認執行此操作。 _ld_需要使用'--start-group'和'--end-group'來括號化庫(如果你正在從_gcc_驅動鏈接,那麼使用'gcc -Wl, - start-group libs .. 。-W1, - 結束組)。 – bobbogo

+0

問題是,這些庫以何種方式相互依賴?他們是共享庫還是靜態庫?如果是靜態的,他們根本就沒有相互依賴的_build-time_(也就是說,你不需要liblog.a來成功創建libthread.a)。它們只有一個_link-time_依賴項......所以make並不關心這個依賴項,只有鏈接器纔會這樣做。這意味着你不需要聲明庫之間的先決條件排序,你只需要確保它們都是在你嘗試鏈接它們之前構建的。讓鏈接線順序正確是另一個問題。 – MadScientist

回答

1

所以,你的問題是,你遞歸地擴大lib_deps(說)。在這樣做的時候,你再次開始擴展lib_deps。無限循環(呃,堆棧崩潰)。爲了阻止自己,你需要保留一個你已經擴展的東西的列表。掉落的功能風格,保持了答案,在全球expansion(啊!),這樣的:

expand-deps = \ 
    $(foreach _,$1, \ 
    $(if $(filter $_,${expansion}),, \ 
     $(eval expansion += $_)$(call expand-deps,${$__deps}))) 

make-dep-list = $(eval expansion :=)$(call expand-deps,$1)${expansion} 

define make-lib 
    $(warning $1_deps: $2) 
    # capture the list of libraries this library depends on 
    $1_deps := $2 
endef 

define make-bin 
    # show the fully expanded list of libraries this binary depends on 
    $(warning $1 dep-list: [$(call make-dep-list,$2)]) 
endef 

$(eval $(call make-lib,thread,log utils))#circular-dependency log->thread; thread->log 
#$(eval $(call make-lib,thread,utils)) 
$(eval $(call make-lib,log,thread)) 
$(eval $(call make-lib,order,log)) 
$(eval $(call make-lib,price,log)) 
$(eval $(call make-bin,test,order price)) 

(作爲練習,你可能會喜歡函數式改寫這一點,即擺脫了全球$expansion的用一個傳過來的參數替換它。)