2017-08-02 90 views
0

我試圖創建一個依賴的文件列表上的目錄中的目標名稱目標:目標通配符shell命令

bin/%.out: src/%/ $(shell find src/%/* -type f -iname '*.cpp' -o -iname '*.hpp') 
# Build stuff here 

然而shell find src/%/* ...最終擴展到shell find src//* ...。起初,我認爲這是因爲我只能有1個目標通配符,但即使在刪除src/%/依賴關係之後,它也會出現同樣的問題。

更多的上下文:我的目錄包含一個'src'目錄,其中包含目錄。 'src'的每個子目錄我被視爲「項目」。當我構建時,所有的目標文件應該在out/src/projname。我試圖使用find以遞歸方式獲取每個項目的所有源文件和頭文件。所有二進制文件將在bin/projname.out中進行,因此,主要依賴項爲bin中的.out文件,它們的名稱與其項目名稱相同。 (如果src/abc存在,bin/abc.outall的依賴關係)。

因此,對於src中的每個子目錄,將編譯所有源文件,並將目標文件移動到out/projname,最終這些文件將鏈接到bin/projname.out

  • SRC
    • proj0
      • CPP/HPP文件
    • proj1
      • CPP/HPP文件
    • SRC
      • proj0
        • 目標文件
      • proj1
        • 目標文件
    • proj0.out
    • proj1。出

目前獲得的項目和輸出文件的清單列表如下:

SRCS := $(shell find src/* -maxdepth 0 -type d) 
SRCS_OUT := $(patsubst src/%,bin/%.out,$(SRCS)) 
... 
all: out/ bin/ $(SRCS_OUT) 

項目可以包含子目錄和這樣的,這就是爲什麼我在使用find代碼在最上面。

+0

我可以使用宏並傳遞%給它,只是從宏返回整個部分? – Matthew

+0

這不起作用。你可以使用一些技巧來填充你想要的所有源文件的變量,但是如果你可以給出一些上下文,我認爲會有更好的/更乾淨的解決方案。 –

+0

好吧,我已經更新了這個問題,希望提供一些更有用的信息。 – Matthew

回答

2

我沒有看到如何做到你想要的標準,便攜,使功能。但它是可行的具有先進的GNU做出特色:

define PROJECT_rule 
CPPS_$(1) := $$(shell find src/$(1) -type f -iname '*.cpp') 
HPPS_$(1) := $$(shell find src/$(1) -type f -iname '*.hpp') 
OBJS_$(1) := $$(patsubst src/$(1)/%.cpp,out/src/$(1)/%.o,$$(CPPS_$(1))) 

$$(OBJS_$(1)): out/src/$(1)/%.o: src/$(1)/%.cpp $$(HPPS_$(1)) 
    <compile recipe> 

bin/$(1).out: $$(OBJS_$(1)) 
    <link recipe> 
endef 

PRJS := $(patsubst src/%,%,$(shell find src/* -maxdepth 0 -type d)) 

$(foreach p,$(PRJS),$(eval $(call PROJECT_rule,$(p)))) 

我們首先定義一個make變量,將作爲您的任何項目的模板(PROJECT_rule);在此模板中,$(1)將代表您的項目名稱。然後,我們計算項目列表(PRJS),最後,我們迭代項目併爲其中的每個項目處理我們的模板(foreach-eval-call)。

注:

  1. 我認爲一個項目的每個目標文件依賴於同一項目的所有頭文件。如果不是這種情況,你將不得不重做一次。

  2. 重要的是要明白的是:

    • PROJECT_rule變量首先由call處理,以替代$(1)與項目的名稱。
    • 然後通過eval遞歸和完全擴展(包括食譜)。遞歸意味着,如果我們有:

      FOO = foo 
      BAR = FOO 
      BAZ = $($(BAR)) 
      QUX = $$(BAZ) 
      

      $($(BAR))被擴展爲foo$$(BAZ)被擴展爲$(BAZ)。完全意味着PROJET_rule變量的所有部分都被擴展了,甚至最後被用作配方的東西(當解析Makefile時,它通常會將配方的擴展推遲到後面的階段)。

    • 結果將被實例化爲常規的make構造,也就是說,它會在被評估之前被再次擴展爲常規構造(而不是配方)。

  3. 所以,會出現PROJECT_rule二擴展,一些$標誌必須進行轉義($$)。請在編寫自己的<compile recipe><link recipe>時記住這一點。例如,如果您想使用自動變量[email protected]$^,請不要忘記編寫[email protected]。例如:如果你的編譯食譜是:

    $(CPP) $(CPPFLAGS) $(INCLUDES) -c $< -o [email protected] 
    

    寫:

    $$(CPP) $$(CPPFLAGS) $$(INCLUDES) -c $$< -o [email protected] 
    
    PROJECT_rule定義

    。第一次擴建將改變它:

    $(CPP) $(CPPFLAGS) $(INCLUDES) -c $< -o [email protected] 
    

    同時,如果你寫:

    $(CPP) $(CPPFLAGS) $(INCLUDES) -c $< -o [email protected] 
    

    ,第一膨脹將改變它是這樣的:

    g++ -O3 -Iincludes/foobar -c -o 
    

    需要注意的是,除非CPPCPPFLAGSINCLUDES具有特定的與目標相關的定義,您還可以編寫:

    $(CPP) $(CPPFLAGS) $(INCLUDES) -c $$< -o [email protected] 
    

    因爲第一次擴張將改變它是這樣的:

    g++ -O3 -Iincludes/foobar -c $< -o [email protected] 
    

    這也是正確的。

  4. 有點更詳細的說明:對每一個項目(例如proj0),foreach會產生:

    $(eval $(call PROJECT_rule,proj0)) 
    

    call將在PROJECT_rule定義替代$(1)proj0,使得eval參數將是:

    CPPS_proj0 := $$(shell find src/proj0 -type f -iname '*.cpp') 
    HPPS_proj0 := $$(shell find src/proj0 -type f -iname '*.hpp') 
    OBJS_proj0 := $$(patsubst src/proj0/%.cpp,out/src/proj0/%.o,$$(CPPS_proj0)) 
    
    $$(OBJS_proj0): out/src/proj0/%.o: src/proj0/%.cpp $$(HPPS_proj0) 
        <compile recipe> 
    
    bin/proj0.out: $$(OBJS_proj0) 
        <link recipe> 
    

    eval將遞歸地擴展它並完成伊利,導致:

    CPPS_proj0 := $(shell find src/proj0 -type f -iname '*.cpp') 
    HPPS_proj0 := $(shell find src/proj0 -type f -iname '*.hpp') 
    OBJS_proj0 := $(patsubst src/proj0/%.cpp,out/src/proj0/%.o,$(CPPS_proj0)) 
    
    $(OBJS_proj0): out/src/proj0/%.o: src/proj0/%.cpp $(HPPS_proj0) 
        <expanded compile recipe> 
    
    bin/proj0.out: $(OBJS_proj0) 
        <expanded link recipe> 
    

    (各$$變得$即使在配方)。然後eval會將結果實例化爲常規make結構,並將它們解析爲常規make語法。也就是說,(簡單的)變量會立即被擴展,目標和先決條件也會被擴展,但不會是食譜。食譜將在第二階段擴展,就在被傳遞到殼體並執行之前(如果是的話)。

  5. 編譯規則是靜態模式規則。如果你還不知道,你可以閱讀GNU make文檔的this section

  6. 練習:在PROJECT_rule的定義,你可以取代由$(shell...$$(shell...但不是由$(patsubst...$$(patsubst...。爲什麼?

+0

是的,它確實有效,但我最終可能會爲每個項目設定一個目標,以便使它更具可移植性(如果我在Windows計算機上運行,​​我不確定msys的make是否可以使用它)。 – Matthew

+1

[Paul的規則編號1](http://make.mad-scientist.net/papers/rules-of-makefiles/):*使用GNU make。不要爲編寫便攜式makefiles而煩惱,請使用便攜式make!* GNU make將在Windows下移植。 –

+0

好吧,這很公平。 – Matthew