2009-09-02 70 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