2009-09-02 58 views
9

我有一個使用GNU Make的C++小型項目。我希望能夠把下面的源文件:使用GNU Make製作平面目標文件目錄結構輸出

src/ 
    a.cpp 
    b/ 
    b.cpp 
    c/ 
    c.cpp 

到下面的輸出結構(我在這一點不擔心重複):

build/ 
    a.o 
    b.o 
    c.o 

到目前爲止,我有下面,不幸的是放的.o和.D緊挨着的.cpp:

OBJS   :=  $(foreach file,$(SRCS),$(file).o) 
DEPS   :=  $(patsubst %.o,%.d,$(OBJS)) 
sinclude $(DEPS) 

$(OBJS) : %.o : %.cpp 
     @echo Compiling $< 
     $(CC) $(CC_FLAGS) $(INCS) -MMD -o [email protected] $< 

我知道了$(notdir ...)的功能,但在這一點上我的努力,用它過濾對象失敗。任何人都可以對此有所瞭解嗎?這似乎是相當合理的事情。

回答

8

至少有兩種方法可以做到這一點。首先(以及我推薦的)是,您可以將構建目錄添加到目標名稱(即使在使用模式規則時)。例如:

$(OBJS) : build/%.o : %.cpp 

其次,您可以使用VPATH變量告訴make以搜索不同的目錄以獲取先決條件。這可能是更常用(過)使用的方法。它至少有一個嚴重的缺點,那就是如果你使用它,然後遇到「重複」問題,那麼就無法解決問題。使用前一種方法,您可以始終鏡像構建目錄下的源目錄結構,以避免重複衝突。

編輯︰我以前的答案是在細節上有點缺乏,所以我會擴大它,以表明這實際上是廣告作品。下面是一個完整的工作示例Makefile,它使用上述第一種技術來解決問題。只需將其粘貼到Makefile中並運行make - 它將完成剩下的工作,並顯示這確實可行。

編輯:我無法弄清楚如何得到如此,讓我的答覆文件製表符(它用空格代替它們)。複製並粘貼此示例後,您需要將命令腳本中的前導空格轉換爲製表符。

BUILD_DIR := build 

SRCS := \ 
    a.c \ 
    b.c \ 
    c.c \ 
    a/a.c \ 
    b/b.c \ 
    c/c.c 

OBJS := ${SRCS:%.c=${BUILD_DIR}/%.o} 

foo: ${OBJS} 
    @echo Linking [email protected] using $? 
    @touch [email protected] 

${BUILD_DIR}/%.o: %.c 
    @mkdir -p $(dir [email protected]) 
    @echo Compiling $< ... 
    @touch [email protected] 

${SRCS}: 
    @echo Creating [email protected] 
    @mkdir -p $(dir [email protected]) 
    @touch [email protected] 

.PHONY: clean 
clean: 
    rm -f foo 
    rm -f ${OBJS} 

特別要注意的有重名(交流轉換器和A /交流轉換器,b.c和b/b.c等)的源文件,並且這不會導致任何問題。還請注意,沒有使用VPATH,我建議您避免使用VPATH,因爲它有其固有的侷限性。

+0

好的,使用這種方法我可能需要一個額外的規則來創建輸出文件夾中的子文件夾? – Justicle 2009-09-02 01:29:14

+0

我最終走下了這條路 - 因爲無論如何我需要製作特定於目標和配置的構建文件夾,所以很容易在「構建文件夾」步驟中添加另外幾個文件夾。謝謝! – Justicle 2009-09-02 05:28:43

+0

生成文件夾的單獨規則應該可以正常工作。但是,我通常所做的只是在命令腳本中添加一個「@mkdir -p $(dir $ @)」行來創建輸出目錄(如果它尚不存在)作爲創建目標文件的一部分( S)。 – 2009-09-02 13:17:38

2
vpath %.cpp src src/b src/c 

然後參考沒有它們的目錄名稱的源文件; Make將搜索vpath

1

按照初始請求創建平面目錄結構。

是否使用vpath來追蹤源文件,但是所有bookeeping都是從SRC列表中自動完成的。

SRC = a/a.c a/aa.c b/b.c 
TARGET = done 

FILES = $(notdir $(SRC)) 
#make list of source paths, sort also removes duplicates 
PATHS = $(sort $(dir $(SRC))) 

BUILD_DIR = build 
OBJ = $(addprefix $(BUILD_DIR)/, $(FILES:.c=.o)) 
DEP = $(OBJ:.o=.d) 

# default target before includes 
all: $(TARGET) 

include $(DEP) 

vpath %.c $(PATHS) 

# create dummy dependency files to bootstrap the process 
%.d: 
    echo a=1 >[email protected] 

$(BUILD_DIR)/%.o:%.c 
    echo [email protected]: $< > $(patsubst %.o,%.d,[email protected]) 
    echo $< >[email protected] 

$(TARGET): $(OBJ) 
    echo $^ > [email protected] 

.PHONY: clean 
clean: 
    del $(BUILD_DIR)/*.o 
    del $(BUILD_DIR)/*.d 

對不起醜陋echo的,但我只有我贏盒測試它。

0

你可能不喜歡格外這種方法,但是:

AUTOMAKE_OPTIONS = 

的伎倆相當不錯的Makefile.am。只是說'你不需要手寫所有東西。

1

這是用於Win32 mingw32-make。其作品。 最重要的部分是

-mkdir $(patsubst %/,%,$(dir [email protected]))

爲Win32。我們需要去除trailing/for win32。

GENERATED_DIRS = a b 

# Dependency generator function 
mkdir_deps =$(foreach dir,$(GENERATED_DIRS),$(dir)/.mkdir.done) 

# Target rule to create the generated dependency. 
# And create the .mkdir.done file for stop continuous recreate the dir 
%/.mkdir.done: # target rule 
    -mkdir $(patsubst %/,%,$(dir [email protected])) 
    echo $(patsubst %/,%,$(dir [email protected])) >[email protected] 

all: $(mkdir_deps) 
    @echo Begin 

clean: 
    @echo Cleaning