我很难找到关于makefile的任何信息,这些信息是真正的初学者级别。即使是问题here,也会使用一些我不理解的符号来呈现,例如$(CC) $(INC) $< $(CFLAGS) -o $(BIN)$@ $(LIBS)
。那让我失望了。
我的makefile如下所示:
cpptest: main.o
g++ -o cpptest main.o
main.o: main.cpp
g++ -c main.cpp
clean:
rm cpptest main.o
这是我知道如何处理makefile的全部限制。它可以工作,但将main.o和cpptest.exe文件放入项目根目录。
我想将main.o文件和cpptest.exe文件放入/ build /目录。但是,如果我在每个main.o和每个cpptest之前放置./build/
,则对象文件将出现在项目根目录中,并且exe文件根本不会出现。
我正在使用Windows上的Sublime Text 3来构建这个东西,这是值得的。
答案 0 :(得分:5)
稍微好一点的解决方案如下:注意,我正在做一些时髦的事情,但我会在路上解释
all: build/cpptest
.PHONY: all
build:
@echo "building directory $@"
mkdir -p $@
build/cpptest: build/main.o | build
@echo building $@
g++ -o $@ $^
build/main.o: main.cpp | build
@echo building $@
g++ -o $@ -c $^
clean:
@echo cleaning...
rm -f build/*
好的,让我们看看第一个和第二个目标:
all: build/cpptest
.PHONY: all
我创建了一个名为all
的默认目标。这是一个虚拟目标(它实际上并没有构建一个名为all
的文件),因此我将all
标记为虚假,使其成为.PHONY
的依赖项。 (这基本上告诉make如果已经存在名为all
的新文件,则不要忽略all
规则。 all
没有配方,因此除了导致其依赖关系被创建外,它不会做任何事情。这可能看起来有点复杂,但它是makefile中的标准做法,因为它使您可以按照您认为有用的任何顺序自由组织下面的规则。
第三个目标:
build:
@echo "building directory $@"
mkdir -p $@
对于第一个目标build,这是您正在创建的目录的名称。 build
是目标,它没有依赖关系,并且有两个配方行。第一个配方行以@
开头。这只是意味着在运行之前不要打印配方。如果您没有这个,您的输出将如下所示:
echo "building directory build"
building directory build
哪个很难看。 @
只有在行的开头才会这样做。您会注意到后面的行$@
。这是不同的。它是一个扩展为目标名称的变量(在本例中为build
)。在适当的时候使用这个变量是一个好习惯,因为它将在以后简化更复杂的makefile。 build
目标的第二个配方创建目录。
第四个目标:
build/cpptest: build/main.o | build
@echo building $@
g++ -o $@ $^
这表示build/cpptest
依赖于build/main.o
和build
(即,在完成其他两个操作之前不要开始构建这些内容)。一个大空洞:注意|
之前的build
符号。这使它成为仅限订单的依赖项。这意味着如果build
目录已存在且其时间戳比build/cpptest
更新,则不要认为build/cpptest
已过期(不重建它)。另一方面,另一个依赖项build/main.o
位于|
符号的左侧。这告诉make如果build/main.o
不存在,或者如果它比build/cpptest
更新,那么make应该重建build/cpptest
。
我们需要|
build
(仅限订单依赖项)的原因是每次添加新文件时都会更新目录的日期。因此,build
将始终具有比build/cpptest
更新的时间戳。这种情况属于高级makefile,但是这是正确的方法,所以我想我会在这里展示它。
正如@Felix指出的那样,在所有版本的make中都没有order-only(GNU make确实支持它)。
对于食谱,我使用了$@
变量和$^
变量。 $^
表示所有非顺序依赖项(在这种情况下为main.cpp
)。这些在规则运行之前进行了扩展。
你可以更进一步,使它真正正确(例如定义一个$(objs)
变量等),这使得makefile在将来更容易维护,但这有望为你提供一个良好的开端