2010-12-14 51 views
8

這是我之前的問題的後續:SO 4403861,因爲建議的解決方案打破了依賴關係,使得makefile無用。我無法弄清楚爲什麼。取決於目錄中的製造

我使用了GNU make 3.82 我如果obj的目錄已創建一個可行的規則:

objdir:=../obj 
$(objdir)/%.o: %.C 
    $(COMPILE) -MM -MT$(objdir)/$(notdir [email protected]) $< -o $(DEPDIR)/$(notdir $(basename $<).d) 
    $(COMPILE) -o $(objdir)/$(notdir [email protected]) -c $< 

但是,如果obj的目錄不存在,使失敗。我想使按需自動創建../obj,所以我說我的想法很簡單:

$(objdir)/%.o: %.C $(objdir) 
    $(COMPILE) -MM -MT$(objdir)/$(notdir [email protected]) $< -o $(DEPDIR)/$(notdir $(basename $<).d) 
    $(COMPILE) -o $(objdir)/$(notdir [email protected]) -c $< 

$(objdir): 
    if [ ! -d $(objdir) ] ; then mkdir $(objdir) ; fi 

當我這樣做,使部隊始終編譯,每一次。爲什麼?除非沒有目錄,否則mkdir不應該發生?爲什麼依賴被這個簡單的改變破壞了?

+0

正如我在迴應我的回答您的問題/評論評論4403861:_「你的規則說,該目標文件依賴於對象目錄 - 這意味着如果因爲對象文件的對象目錄已經更改是最後建立的(例如,因爲你編譯了另一個文件),那麼你的文件需要重建。您的總體構建目標取決於存在的對象目錄; 「# – 2010-12-15 19:45:40

回答

2

如已回答,您不能將具有輸出文件的目錄作爲依賴項,因爲它每次都會更新。

一個解決方案(如上所述)是要放的mkdir -p每個版本之前,像這樣:

objdir:=../obj 
$(objdir)/%.o: %.C 
    @mkdir -p $(objdir) $(DEPDIR) ... 
    $(COMPILE) -MM -MT$(objdir)/$(notdir [email protected]) $< -o $(DEPDIR)/$(notdir $(basename $<).d) 
    $(COMPILE) -o $(objdir)/$(notdir [email protected]) -c $< 

但我不喜歡這個解決方案,因爲它迫使運行一個額外的過程很多很多的時代。然而,知道了錯誤的原因,還有另外一種方法:

exe: dirs $(OBJ) 

在主要目標中,一個創建可執行文件,只需要插入對象之前的目標迪爾斯。由於它的打擊順序:

dirs: 
    @mkdir -p $(objdir) $(DESTDIR) ... 

而這只是整個建設做一次,而不是每一次文件。

+2

這是一個衆所周知的煩惱,但不能在並行make中使用'mkdir -p',原因是如果folders/a/b/c和/ a/b/cc是並行創建的,當mkdir -p檢查一個目錄是否存在,然後創建它時,會出現競爭狀態。另一個進程(make job)可以在兩者之間創建目錄檢查和操作,以便第一個作業在EEXIST創建目錄時失敗 – 2011-01-05 17:42:00

+1

如前所述,對目錄的依賴關係必須是僅限訂單的 – 2011-01-05 17:42:34

+0

如前所述,此解決方案在'-j'你可以使用'mkdir -p',但你必須正確地獲得依賴關係,基本上你必須讓所有的_objects_依賴於dir,並且由於dir改變時間而停止重新編譯,使用sentinel文件(和模式規則)。見下文(I無法在此框中輸入解決方案,grrrr。)。 – bobbogo 2011-01-06 10:39:36

11

正如其他人所說的,問題在於,無論何時添加或刪除目錄成員,都會將目錄視爲「已更改」,因此make會看到您的輸出目錄始終在更改,並重新運行您已告知的所有編譯內容。在輸出目錄中。

作爲其他人描述的解決方法的替代方法,最近的GNU make版本支持「僅訂購先決條件」。 The description of order-only prerequisites in the manual包括如何使用它們進行目錄創建的示例。

+2

我不說,這是相當真實的。當任何成員被添加,刪除或重命名時,目錄都會改變。 (一個目錄是一個包含文件名到文件映射的文件。) – reinierpost 2010-12-15 00:00:40

+0

我在這裏解釋一下:http://stackoverflow.com/questions/3477418/suppress-make-rule-error-output/3554442#3554442 – 2010-12-15 04:47:29

+0

reinierpost:thanks ,糾正了答案。 – slowdog 2010-12-15 18:58:09

21

您也可以嘗試用訂單僅先決條件link

有你的問題的一個類似的例子,可用。

OBJDIR := objdir 
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o) 

$(OBJDIR)/%.o : %.c 
     $(COMPILE.c) $(OUTPUT_OPTION) $< 

all: $(OBJS) 

$(OBJS): | $(OBJDIR) 

$(OBJDIR): 
     mkdir $(OBJDIR) 
3

某種定點文件將解決這一相當不錯。允許您編寫單個模式規則來創建所有文件夾,不存在任何流氓重新編譯問題,並且安全。

OBJDIR := objdir/ 
OBJS := $(addprefix ${OBJDIR},foo.o bar.o baz.o) 

all: ${OBJS} 

${OBJDIR}%.o : %.c ${OBJDIR}.sentinel 
    ${COMPILE.c} ${OUTPUT_OPTION} $< 

# A single pattern rule will create all appropriate folders as required 
.PRECIOUS: %/.sentinel # otherwise make (annoyingly) deletes it 
%/.sentinel: 
    mkdir -p ${@D} 
    touch [email protected]