2014-10-18 31 views
0

我的Makefile:的Makefile:無法獲得基本名稱與patsubst工作

compiler=g++ 
cflags=-g -Wall -I. 
src=$(shell find . -name *.cc) #find all .cc files, with path name 
srcBaseName=$(shell basename -a $(src)) # extract base names by stripping off the path 
header=$(shell find . -name *.h) # all header files 
obj=$(patsubst %.cc, %.o, $(srcBaseName)) # Problematic line 
bin=bin/myProgram 

all: $(bin) 

$(bin): $(obj) 
    $(compiler) $^ -o [email protected] 

%.o: %.cc 
    $(compiler) $(cflags) -c $^ -o [email protected] 


clean: 
    rm $(obj) $(bin) 

導致以下錯誤:

make: *** No rule to make target 'SomeObjectFile.o', needed by 'bin/myProgram'. Stop.

問題的行:

obj=$(patsubst %.cc, %.o, $(srcBaseName)) 

如果我改變$(srcBaseName)爲$(src),然後一切都很好。但在這種情況下,.o文件將被分散到相應的.cc文件中,我不想要這些文件。

我想有一個專用的(obj /)文件夾來存儲所有的.o文件。

我該怎麼辦?

首先嚐試:

obj=$(patsubst %.cc, %.o, obj/$(srcBaseName)) 

第二個嘗試:

obj=$(patsubst %.cc, %.o, obj\/$(srcBaseName)) 

他們爲什麼不工作?

/**********************編輯於2015年2月16日****************** ****/

基於對答案的建議,我更新了我的Makefile是這樣的:

compiler=g++ 

# source compilation flags 
cflag=-g -Wall -std=gnu++0x -I./header/ 
# source link flags 
lflag= 
# lib used by proj 
lib= 


tflag=-g -Wall -std=gnu++0x 
# test link flags 
tlflag= 
# test libs 
testLib=lib/libgtest.a 

# source code 
src=$(shell find "./src" -name "*.cc") 
srcBaseName=$(shell basename -a $(src)) 
obj=$(addprefix obj/, $(patsubst %.cc, %.o, $(srcBaseName))) 
vpath %.cc $(dir $(src)) 

# header files 
header=$(shell find "./header" -name "*.h") 

# test files 
testSrc=$(shell find "./test" -name "*.cc") 
testSrcBase=$(shell basename -a $(testSrc)) 
testObj=$(addprefix obj/, $(patsubst %.cc, %.o, $(testSrcBase))) 
vpath %.cc $(dir $(testSrc)) 

# binary files 
bin=bin/Driver 
testBin=bin/Test 





all: prog test 


prog: $(bin) 
$(bin): $(obj) 
    $(compiler) $(lflag) $^ $(lib) -o [email protected] 

#$(obj): $(src) $(header) 
obj/%.o: %.cc $(header) 
    $(compiler) $(cflag) -c $< -o [email protected] 



test: $(testBin) 

$(testBin): $(testObj) 
    $(compiler) $(tlflag) $^ $(testLib) -o [email protected] 

obj/%.o: %.cc 
    $(compiler) $(tflag) -c $< -o [email protected] 




clean: 
    rm $(obj) $(bin) $(testObj) $(testBin) 

這裏的化妝背後的意圖:

化妝PROG:

make應找到./src目錄下的所有源文件(.cc),並使用相同的命令生成.o文件文件名在./obj目錄中,對子目錄的級別不敏感,這樣我就可以自由添加新的cc文件而無需更新Makefile。每個.o文件都依賴於相應的(只是具有相同名稱的文件,而不是全部).cc文件和所有頭文件(make不會自動知道cc文件包含哪些頭文件而不解析該文件;如果您有聰明的方法來實現這一點,請讓我知道!)。例如,./src/subdirectory1/sample1.cc應該生成./obj/sample1.o,./obj/sample1.o取決於./src/subdirectory1/sample1.cc + ./header/sample1.h +。 /header/sample2.h + ...

化妝測試:

它應該做類似的事情來測試源文件的文件夾./test,不同之處在於有沒有參與頭。如果這個細節有幫助,我使用Google測試。

然而,我的Makefile倒不以預期的方式工作,因爲它具有以下問題:

1,如果我跑make test,配方$(compiler) $(tflag) -c $< -o [email protected]不執行(tflag手段「測試編譯標誌」,這沒有-I./header/部分; cflag表示'源代碼編譯標誌',它有-I./header/部分)。相反,執行phony prog $(compiler) $(cflag) -c $< -o [email protected]中的配方。這個觀察結果來自'-I./header/'出現的輸出。我猜這是因爲phony prog中的cflag模式規則會覆蓋虛假測試中的tflag嗎?我隱約記得讓挑選最好的匹配模式規則 - 兩者基本上是相同的(我有這樣的意圖,即在假冒僞劣被執行時,特定假冒模式下的模式規則應該被執行,這似乎不可行?),所以總會選擇第一個。這個結論通過交換Makefile中兩個模式規則的順序來驗證,並且這次tflag規則總是被選中。 所以一個自然而然的問題是,當手機執行時,如何在特定的假冒模式下執行模式規則?

2,假設在第一點做我想做的事情是不可行的,我開始考慮替代方案。我可以做些什麼:#$(obj): $(src) $(header),這樣我就可以擺脫模式規則來解決方式選擇模式規則。但是,這顯然不正確,因爲它說$(obj)中的每個.o文件都取決於所有src文件和所有頭文件。 這是一個正確的方向嗎?

非常感謝,期待您的迴音。

3個關鍵問題以粗體和斜體標出。

回答

0

的主要問題是,make不能使用模式規則

%.o: %.cc 
    $(compiler) $(cflags) -c $^ -o [email protected] 

打造obj因爲它無法找到你的.o文件和.cc的文件,以便與%之間的共同造成的。解決這個問題的簡單方法是通過vpath指令告訴make這些文件在哪裏,例如,加入

vpath %.cc $(dir $(src)) 
vpath %.o obj/  #not a good idea for .o files though, see below 

和變着花樣規則(通過使用vpath %.o需要)到

%.o: %.cc 
    $(compiler) $(cflags) -c $^ -o obj/[email protected] 

編輯:MadScientist取得了一個非常好的問題,我完全錯過,在此基礎上,一個更好的解決方案,不涉及vpath %.o

vpath %.cc $(dir $(src)) 
obj=$(addprefix obj/,$(patsubst %.cc, %.o, $(srcBaseName))) 
obj/%.o: %.cc 
    $(compiler) $(cflags) -c $^ -o [email protected] 
+0

嗨,下坡來自這裏:謝謝你的回答。關於vpath指令: 1,是每個Makefile特有的vpath設置(也就是我在每個make上設置的路徑)還是系統中所有Makefiles共享的全局指令(例如,我的操作系統中的其他項目的Makefiles將會選擇它也是)? 2,我假設,爲了讓vpath被所有make命令看到(假設我以後決定除了make all之外還要爲子系統編寫其他構建目標),我需要用變量設置vpath像Makefile開頭的src/cflags,是嗎? – h9uest 2014-10-19 11:20:56

+0

嗨,不客氣。 1.我非常肯定它對於特定的make調用是本地的,但我不知道如果在Makefile中調用另一個make會發生什麼。 2.不完全確定你的意思,但是,我通常將它設置在Makefile的開頭。 – downhillFromHere 2014-10-19 12:12:49

+2

請注意,您不應該使用'vpath%.o'。 VPATH僅用於查找_source_文件(「make」不會自行構建但已經存在的文件)。它不會使用它來查找派生文件('make'構建的文件)。我應該說:它會在那個make中找到它們,但它不會工作,因爲你的makefile不會正常工作。 – MadScientist 2014-10-19 14:57:55

1

你的問題是這樣的一行:

%.o: %.cc

那行告訴make創造一些/路徑/ file.o你會使用一些/路徑/ file.cc。

如果你想要在一個單一的目錄中的所有.o文件,但仍然希望源文件在不同的目錄中,每個源目錄需要一個這樣的規則。或者,你可以全部目錄添加到VPATH變量,像:

VPATH=$(dir $(src))

或許更好:

VPATH=$(dir $(SRC))

Usuing爲您的變量在一個Makefile大寫字母是一個好辦法以避免將它們與函數名稱混淆。

+0

感謝很多答案^ _^ – h9uest 2014-10-19 19:26:24

+0

亨裏克嗨,我是我已經更新了我的問題,如果你能夠點亮它,我將不勝感激 - 非常感謝! – h9uest 2015-02-16 18:37:15

1

我會盡我所能來也回答您的新問題:

1)當您使用gnu編譯器時,可以在.c文件中自動查找.h文件的依賴關係。你可以像這樣的規則添加到您的Makefile:

# Where .d-files will be created for dependencies 
DEP=dep 

# Dependency files 
DEPS = $(srcBaseName:%.cc=$(DEP)/%.d) 

# Before compiling object file, also make sure dependency file is 
# created to test the need for future recompilation 
obj/%.o: %.cc $(DEP)/%.d 
    $(compiler) $(cflags) -c $< -o [email protected] 

# Use gnu compiler to create dependency files 
$(DEPS): $(DEP)/%.d: %.cc $(filter-out $(wildcard $(DEP)), $(DEP)) 
    $(compiler) -MM $(cflags) -MT [email protected] $< > [email protected] 

# Create directories which might be needed 
$(DEP) $(OBJ) $(BIN) $(MO): 
    mkdir -p [email protected] 

# Let Makefile use any generated dependency files 
ifneq ($(wildcard $(DEPS)),) 
include $(wildcard $(DEPS)) 
endif 

請注意,在編譯規則我$<取代$^,因爲我們不希望編譯依賴文件。

2)我會避免看起來相同的兩個模式規則。相反,我會根據目標改變CFLAG,這樣的事情:

ifeq ($(MAKECMDGOALS),debug) 
CFLAGS += -g 
else 
CFLAGS += -O2 
endif 

我希望這些問題的答案將引導您正確的方向

+0

太棒了!你是男人。 – h9uest 2015-02-17 09:54:27

+0

嗨Henrik。只是爲了與大家分享:我做了一些進一步的搜索並找到了「靜態模式」來滿足我的要求。這比我的情況下的常規模式規則要好。 http://www.gnu.org/software/make/manual/make.html#Static-Pattern – h9uest 2015-02-17 11:11:41

+0

是的,我應該也想到靜態模式。在我上面的示例中,創建依賴文件的規則使用靜態模式。這可能是您的tflag vs cflag的最佳解決方案。 – 2015-02-17 19:38:11