2010-10-27 89 views
16

我正在研究一箇中等規模的項目,該項目包含幾個相互依賴的庫,我最近使用非遞歸makefile進行了轉換。我的下一個目標是同時在同一個源代碼樹中構建調試版本和發佈版本(進行調試;發佈)。我的第一步是使調試和發佈目標包含正確的構建標誌。我這樣做是使用目標特定的變量,就像這樣: CXXFLAGS = -Wall -Wextra -Werror -DLINUX使用GNU Make同時構建調試目標和發佈目標

CXX_DEBUG_FLAGS=-g3 -DDEBUG_ALL 
CXX_RELEASE_FLAGS=-O3 

.PHONY: debug 
debug: CXXFLAGS+=$(CXX_DEBUG_FLAGS) 
debug: build 

.PHONY: release 
release: CXXFLAGS+=$(CXX_RELEASE_FLAGS) 
release: build 

這工作得很好,但你只能建立調試,或釋放,不能同時在同一時間。同時,我並不是指在同一個版本中,我的意思是在同一個源代碼樹中進行調試(make debug; make release)。爲了做到這一點,我需要將目標文件放在一個調試/版本特定的目錄中,這樣它們不會互相覆蓋,我需要用'D'來調試目標二進制名稱。我以爲這將是容易,因爲我可以再次使用目標特定的變量,就像這樣: CXXFLAGS = -Wall -Wextra -Werror -DLINUX

CXX_DEBUG_FLAGS=-g3 -DDEBUG_ALL 
CXX_RELEASE_FLAGS=-O3 

.PHONY: debug 
debug: CXXFLAGS+=$(CXX_DEBUG_FLAGS) 
debug: MODULE_BLD_TYPE=D 
debug: OUT_DIR=debug_obj 
debug: build 

.PHONY: release 
release: CXXFLAGS+=$(CXX_RELEASE_FLAGS) 
release: MODULE_BLD_TYPE:= 
release: OUT_DIR=release_obj 
release: build 

.PHONY: build 
build: TARGET_NAME=HelloWorld$(MODULE_BLD_TYPE) 
build: TARGET_BUILD_DIR=$(PROJECT_ROOT_DIR)/$(OUT_DIR) 
build: TARGET_BUILD_OBJS=$(addprefix $(TARGET_BUILD_DIR)/,$(SOURCES:.cpp=.o)) 
build: $(TARGET_NAME) 

你讓專家閱讀這已經知道這會不會是因爲工作您不能使用目標特定變量來創建實際目標。他們爲我的CXXFLAGS var正常工作,因爲該變量未用於目標名稱。

是否存在使用非遞歸makefile管理調試/發佈版本的設計模式和/或最佳實踐?具體而言,如何構建目標文件目錄路徑和目標名稱(根據目標構建目標)?

+0

在先決條件中如何分配變量? – Michael 2012-09-26 20:10:49

+0

不出所料,該文檔有一個答案:https://www.gnu.org/software/make/manual/html_node/Target_002dspecific.html – 2015-09-13 22:18:25

回答

12

Make的一個最常見的問題是它無法一次處理多個通配符。沒有真正乾淨的方式去做你所要求的事情(不採用遞歸方式,我認爲這並不是那麼糟糕)。這是一種合理的方法:

CXXFLAGS=-Wall -Wextra -Werror -DLINUX 
CXX_DEBUG_FLAGS=-g3 -DDEBUG_ALL 
CXX_RELEASE_FLAGS=-O3 

.PHONY: debug 
debug: CXXFLAGS+=$(CXX_DEBUG_FLAGS) 
debug: HelloWorldD 

.PHONY: release 
release: CXXFLAGS+=$(CXX_RELEASE_FLAGS) 
release: HelloWorld 

DEBUG_OBJECTS = $(addprefix $(PROJECT_ROOT_DIR)/debug_obj/,$(SOURCES:.cpp=.o)) 
RELEASE_OBJECTS = $(addprefix $(PROJECT_ROOT_DIR)/release_obj/,$(SOURCES:.cpp=.o)) 

HelloWorldD: $(DEBUG_OBJECTS) 
HelloWorld: $(RELEASE_OBJECTS) 

# And let's add three lines just to ensure that the flags will be correct in case 
# someone tries to make an object without going through "debug" or "release": 

CXX_BASE_FLAGS=-Wall -Wextra -Werror -DLINUX 
$(DEBUG_OBJECTS): CXXFLAGS=$(CXX_BASE_FLAGS) $(CXX_DEBUG_FLAGS) 
$(RELEASE_OBJECTS): CXXFLAGS=$(CXX_BASE_FLAGS) $(CXX_RELEASE_FLAGS) 
+0

這是一個有趣的解決方案,我會考慮它,看看我是否可以將其應用於實際問題。這就是將複雜問題歸結爲一個簡單例子的問題。所以我不能馬上說出這是否有用,但它看起來很有希望。 – Richard 2010-10-27 18:58:30

+0

@Richard:如果它不起作用,請發佈更新,我們會再試一次。 – Beta 2010-10-27 20:25:59

+0

我相信我有一些工作。一旦你確認我所做的只是不工作,我就退後一步,採取了不同的方法。您對使用遞歸的評論提醒我,我的makefile被更高級別的makefile包裝,它會遞歸地調用我的makefile,所以我只是將構建目錄路徑的邏輯移到它似乎正在工作的邏輯中。不過,我現在已經將我的'乾淨'目標複雜化了,因爲它必須清理調試和發佈目標文件,但這似乎是一個更簡單的問題。 – Richard 2010-10-28 14:27:25

2

使用VPATH進行調試和發佈版本使用同一套源文件。調試和發佈版本可以有自己的目錄,這意味着它們將分離它們的目標文件。

或者,使用一種構建工具,該工具本身支持源代碼構建,如automake或(ugh)cmake。

如果啓用automake選項subdir-objects(如AM_INIT_AUTOMAKE([foreign subdir-objects])),則可以編寫非遞歸Makefile.am

+0

不幸的是,其他構建工具現在不是一個選項。我已經使用VPATH(儘管我沒有在我的示例中顯示)來查找我的源文件。但是,我不清楚這是如何幫助我在何處放置我的對象文件。在選擇「調試」或「發佈」目標之前,運行時間將不知道將哪個目錄放入obj文件。不過,我想我有一個正在工作的解決方案。看到我以前的評論。 – Richard 2010-10-28 14:22:40

+2

在生成調試和發佈文件的目錄中創建單獨的生成文件。使用VPATH將它們指向公共源。根據'debug'或'release'目標,使用頂層makefile來決定遞歸調用哪個makefile。 – 2010-10-28 20:05:42