9

我有一个使用 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 ...) 函数,但此时我使用它来过滤对象的努力失败了。任何人都可以对此有所了解吗?这似乎是相当合理的事情。

4

5 回答 5

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}

特别要注意的是,有些源文件名称重复(ac 和 a/ac、bc 和 b/bc 等),这不会导致任何问题。另请注意,没有使用 VPATH,由于其固有的限制,我建议避免使用它。

于 2009-09-02T00:51:21.947 回答
2
vpath %.cpp src src/b src/c

然后引用不带目录名的源文件;Make 将搜索vpath

于 2009-09-02T00:47:33.160 回答
1

按照最初的要求创建平面目录结构。

确实用于vpath追踪源文件,但所有的簿记都是从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的,但我只有我的胜利盒来测试它。

于 2009-11-26T09:14:44.463 回答
1

这适用于 Win32 mingw32-make。其作品。最重要的部分是

-mkdir $(patsubst %/,%,$(dir $@))

对于win32。我们需要为 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
于 2012-06-12T12:49:17.547 回答
0

您可能并不特别喜欢这种方法,但是:

AUTOMAKE_OPTIONS =

在 Makefile.am 中做得很好。只是说你不需要手写所有的东西。

于 2011-09-23T11:29:55.433 回答