2012-03-16 116 views
0

我有一個運行二進制文件生成cpp文件的makefile。然後我編譯cpp文件併爲每個cpp文件生成.o文件。如何強制重新生成makefile中的變量

問題是首先被調用的生成文件時,該文件夾是空的,因爲二值尚未調用和

CPP_FILES=$(wildcard $(MY_DIR)/inc/output/*.cpp) 

將是一個空的變量。

所以我改了行,以

CPPFILES=$$(wildcard $(MY_DIR)/inc/output/*.cpp) 
OBJFILES=$$(patsubst $(MY_DIR)/*.cpp,$(MY_DIR)/*.o,$(CPPFILES)) 

//跑到二進制生成cpp文件

.SECONDEXPANSION: 
libEXP.so:$(CPPFILES),$(OBJFILES) 
     $(CC) $(CFLAGS) -I(INC) -L(LIBS) -shared -o $(OBJFILES) [email protected] 

二級擴展失敗說外殼找不到通配符命令。
我在做什麼錯?

回答

3

您所遇到的問題是始終從最終目標BACKWARDS開始工作,然後再開始構建和解決先決條件。先從圖書館開始,然後看看它的先決條件是什麼,然後看到那些先決條件是什麼,然後是那些先決條件等等。

因此,當make擴展$(OBJFILES)值時,即使您延遲第二次擴展,仍然是.cpp文件尚未創建的情況。

你必須解釋一下,有一條規則可以生成.cpp文件。一旦明白這一點,它會爲你調用你的規則。儘管如此,您將無法使用通配符來確定要構建的.cpp文件,除非您想先執行一些操作,如先構建所有.cpp文件,然後遞歸調用make。

編輯:

你問爲什麼第二次膨脹沒有工作。我在第一段中提到過,但可能不夠清楚。製作經歷兩個階段的處理。首先它讀取makefile,其次它貫穿規則並構建事物。次要的擴展步驟會延遲分辨率,直到第二步......但在這種情況下這不會對您有所幫助。

你問make建立libEXP.so。爲此,它需要擴展libEXP.so的先決條件,以便它知道目標依賴於什麼。 這個是當第二次擴展執行時,但是在這裏我們還沒有建立任何.cpp文件,因爲我們不知道我們需要它們,所以通配符擴展到什麼都沒有。 Make不會創建這些.cpp文件,直到它知道需要它們,並且它不知道它需要它們,直到它已經擁有它們,因此它可以生成列表。o libEXP.so的先決條件文件。這顯然不會起作用:)

+0

嗨MadScientist,謝謝你解釋,但這就是爲什麼我使用scendexpansion,如果它沒有重新評估價值並堅持原來的價值,那該怎麼辦。有趣的是,如果我在CPPFILES定義中替換通配符行,通過shell命令「find $ MY_DIR -name」* .cpp「-type f」,正確地得到我的列表,但我仍然遇到patsubst命令的問題。如果secondexapnsion僅適用於shell函數,那麼我想知道如何在secondexpansion上製作文檔,並說它可以與patsubst一起使用。 – learningtocode 2012-03-19 22:43:22

+0

我想我真正要問的是有沒有一種方法可以使用wildacrd函數,而不會抱怨找不到命令通配符。另外,可以遞歸解決這個問題,我認爲先決條件列表中的變量是從讀取階段的所有包含makefile中讀取的? – learningtocode 2012-03-19 23:55:42

+0

其實Madscienist是對的。我把這條規則放在一個makefile文件中,並將這行文件移動到另一個makefile .o文件和庫中。我從第一個makefile遞歸地調用第二個makefile,並且它工作正常!我幾乎已經放棄了。但我仍然不明白gnu中的這個例子如何使文檔工作。反正非常感謝MadScientist和Eldar! – learningtocode 2012-03-21 00:26:06

0

離開CPPFILESOBJFILES像往常一樣遞歸變量:

CPPFILES = $(wildcard $(MY_DIR)/inc/output/*.cpp) 
OBJFILES = $(CPPFILES:%.cpp=%.o) 

而推遲了它的擴展使用雙美元如下:

.SECONDEXPANSION: 
libEXP.so: $$(OBJFILES) 
    $(CC) $(CFLAGS) -I(INC) -L(LIBS) -shared -o $(OBJFILES) [email protected] 

但我想這個問題是擴張在運行cpp文件生成器之前發生。你如何援引它?這是一條規則還是別的?

+0

埃爾達爾,感謝您的回覆:請看看這個鏈接:http://www.gnu.org/software/make/manual /html_node/Secondary-Expansion.html。我遵循了patsubst的例子,該例子使用第二次擴展的方式來使用它。關於調用規則來運行二進制文件,我有一個名爲exp的規則,它被定義爲「exp:genCPP libEXP.so」 – learningtocode 2012-03-19 19:07:56

+0

@learning,啊,我明白了,但它與我提出的代碼具有幾乎相同的效果。另請注意,使用並行Make('-j'選項)時,'exp:genCPP libEXP.so'可能無法正常工作。 呃,實際上,MadScientist已經解釋了問題的原因。 – 2012-03-19 21:57:49

1

爲了明確:你不應該在生成的文件上使用$(wildcard)。如果你想要一個「所有生成文件的列表」,$(wildcard)只會通過運氣給你這個列表(如果所有的文件已經生成)。

如果生成器文件和生成的文件之間存在一對一的對應關係,那麼可以在生成器文件上使用$(wildcard)並轉換結果。

使用谷歌的協議緩衝區爲例(它可以生成從的.cc文件.proto文件)

PROTOSS := $(wildcard *.proto) 
GENERATED_SOURCES := ${PROTOSS:.proto=.cc} 
GENERATED_HEADERS := ${PROTOSS:.proto=.h} 
0

我遇到過這種情況。我嘗試了幾層間接尋址(使用一個叫做罐頭序列的罐頭序列,它使用了wildcard),但是在執行生成文件的配方之前,make總是評估通配符。我的解決方案是編寫一個Perl腳本來收集文件列表並執行我需要執行的操作,然後從makefile中調用腳本。我只希望我早點完成。我一直在想,我想避免引入額外的文件,但總的來說,使用腳本比使用非常重要的makefile配方容易得多,因此從一開始就可以節省大量時間。

0

另一種選擇是在bash使用一個for循環:

target: prereqs 
    for file in files/*; do \ 
     ... \ 
    done