我试图设置一个Makefile来处理来自一组源的两个不同的目标,而且我的元素有点偏离。绝大多数都可以正常工作,但是我的依赖结构已被清除,因此我每次都被迫进行完全重新编译。减少的样本如下:
first: OBJDIR = obj
second: OBJDIR = obj-2
SRCS = $(wildcard src/*.cc)
OBJECTS = $(patsubst %.cc,$(OBJDIR)/%.o,$(SRCS))
first: CFLAGS = -g -Wall -Wextra -std=c++11 -MMD
second: CFLAGS = -g -Wall -Wextra -std=c++11 -MMD -DCOMPILE_FLAG
$(OBJDIR)/%.o: %.cc
@mkdir -p $(OBJDIR)/src
clang++ -c $(CFLAGS) -o $(OBJDIR)$@ $<
#DEPENDENCIES AREN'T WORKING PROPERLY
-include $(OBJECTS:.o=.d)
first: $(OBJECTS)
clang++ -o gen/first $(OBJECTS)
second: $(OBJECTS)
clang++ -o gen/second $(OBJECTS)
如果我在@echo $(OBJECTS:.o=.d)
可执行文件生成下first:
(或在编译步骤中使用它),它会正确扩展为/obj/src/filename.d
。但是,当它在包含行中时,它只显示为/src/filename.d
。显然,.d
文件不存在于该位置,因此它无法找到它们并进行完全重新编译。
Makefiles不是我经验丰富的东西,所以如果有更好的方法可以做任何事情,我全都耳朵。但关键是能够从同一来源获得两组目标文件和两组依赖项。
-
为了澄清最终目标,我所拥有的是一组源文件,用于构建两个单独的可执行文件,差异通过#ifdef
来处理。
我想从makefile结构中获取的是一个包含两个目标的makefile。每个目标生成自己的.o / .d文件,这样当对源进行更改时,我可以运行make first
和make second
来生成两个新的可执行文件,而无需从头开始重新编译所有内容。我以前通过使用两个单独的makefile来处理这个问题,但这似乎是错误的。
答案 0 :(得分:0)
您错过了与目标特定变量相关的GNU make manual中的关键句:
与自动变量一样,这些值仅在目标配方
的上下文中可用
这意味着您无法在目标列表或先决条件列表中使用特定于目标的变量:在此处使用的任何变量将始终具有全局值,而不是特定于目标的值。类似地,在读入makefile时解析include
行:这里根本没有目标上下文,因此使用全局值。
此外,只要您在makefile中看到任何规则创建的文件不完全是$@
,而是对其进行了一些修改,那就是红旗,您知道自己遇到了问题:-o $(OBJDIR)$@
错了。
一般来说,这个makefile存在很多错误,并且它并不完全清楚你在这里尝试做什么。也许如果你退后一步并描述你想要实现的目标,我们可以给你一些指示。
答案 1 :(得分:0)
我相信答案只是重新思考我这样做的方式。在阅读了大量的Makefile文档并考虑了MadScientist的一些评论后,我将makefile重写为如下(修剪掉了不相关的内容):
CC = clang++
SRCS = $(wildcard src/*.cc)
OBJECTS = $(patsubst %.cc,$(OBJDIR)/%.o,$(SRCS))
CFLAGS = -g -Wall -Wextra -std=c++11 -MMD
.PHONY: all clean run
all: $(EXECUTABLE)
-include $(OBJECTS:.o=.d)
$(EXECUTABLE): $(OBJECTS)
@mkdir -p gen
$(CC) -o gen/$(EXECUTABLE) $(OBJECTS)
$(OBJDIR)/%.o: %.cc
@mkdir -p $(@D)
$(CC) -c $(CFLAGS) $(CMDFLAGS) -o $@ $<
clean:
rm -rf obj obj-2 gen
run:
cd gen && ./$(EXECUTABLE)
从那里,我在.bash_profile中创建了一些别名:
alias mfirst="make OBJDIR=obj EXECUTABLE=first"
alias msecond="make OBJDIR=obj-2 CMDFLAGS=-DCOMPILE_FLAG EXECUTABLE=second"
因为变量现在设置在任何目标规范之外,所以一切都很好。它使目标文件和依赖项保持分离,并且别名仍允许快速使用(例如,包括mfirst run
)。
请在此处指出任何缺陷,但我对结果非常满意。