我有一个使用GNU Make的C ++小项目。我希望能够打开以下源文件:
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 $@ $<
我知道$(notdir ...)函数,但此时我使用它来过滤对象的努力失败了。任何人都可以对此有所了解吗?这似乎是合理的事情。
答案 0 :(得分:9)
至少有两种方法可以做到这一点。首先(以及我建议的)是您可以将构建目录添加到目标名称(即使使用模式规则)。例如:
$(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 $@ using $?
@touch $@
${BUILD_DIR}/%.o: %.c
@mkdir -p $(dir $@)
@echo Compiling $< ...
@touch $@
${SRCS}:
@echo Creating $@
@mkdir -p $(dir $@)
@touch $@
.PHONY: clean
clean:
rm -f foo
rm -f ${OBJS}
请注意,有些文件名重复(a.c和a / a.c,b.c和b / b.c等),这不会导致任何问题。另请注意,没有使用VPATH,我建议由于其固有的限制而避免使用。
答案 1 :(得分:2)
vpath %.cpp src src/b src/c
然后引用没有目录名的源文件; Make将搜索vpath。
答案 2 :(得分: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 >$@
$(BUILD_DIR)/%.o:%.c
echo $@: $< > $(patsubst %.o,%.d,$@)
echo $< >$@
$(TARGET): $(OBJ)
echo $^ > $@
.PHONY: clean
clean:
del $(BUILD_DIR)/*.o
del $(BUILD_DIR)/*.d
对于丑陋的echo
感到抱歉,但我只有我的胜利盒来测试它。
答案 3 :(得分:1)
这是针对Win32 mingw32-make的。其作品。 最重要的部分是
-mkdir $(patsubst %/,%,$(dir $@))
for win32。我们需要剥离trailling / 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 $@))
echo $(patsubst %/,%,$(dir $@)) >$@
all: $(mkdir_deps)
@echo Begin
clean:
@echo Cleaning
答案 4 :(得分:0)
您可能不太喜欢这种方法,但是:
AUTOMAKE_OPTIONS =
在Makefile.am中做得很好。只是说'你不需要手工编写所有东西。