我正在编写一个Makefile
并且我想将构建目录和源目录分开。我最初的想法只是“哦,我可以编写规则,将源路径添加到文件名并完成它。”</p>
问题是这个解决方案会超级重复并且看起来不太好。Makefile
为自己编写一个将目标存储在与保存我的源的目录不同的目录中的最佳方法是什么。
我正在编写一个Makefile
并且我想将构建目录和源目录分开。我最初的想法只是“哦,我可以编写规则,将源路径添加到文件名并完成它。”</p>
问题是这个解决方案会超级重复并且看起来不太好。Makefile
为自己编写一个将目标存储在与保存我的源的目录不同的目录中的最佳方法是什么。
程序bsdmake对将构建的目标存储在与保存源的目录不同的目录中有很好的支持。使用Makefile
这个功能可能有点难写,所以我将在我的回答中回顾最重要的技术。
内置变量.OBJDIR
包含构建目标的目录的名称。它是这样确定的(摘自man
页面):
.OBJDIR A path to the directory where the targets are built. Its
value is determined by trying to chdir(2) to the follow‐
ing directories in order and using the first match:
1. ${MAKEOBJDIRPREFIX}${.CURDIR}
(Only if ‘MAKEOBJDIRPREFIX’ is set in the environ‐
ment or on the command line.)
2. ${MAKEOBJDIR}
…
6. ${.CURDIR}
该程序make
将在执行任何目标之前设置到该chdir(2)
目录.OBJDIR
。PWD
在没有任何充分准备的情况下.OBJDIR
,因此我们需要在运行构建目标.CURDIR
之前创建所需的目录或树结构。make
假设,您选择依赖第一个机制来设置.OBJDIR
,然后您可以组织您的构建系统,以便在运行make
构建目标之前,
MAKEOBJDIRPREFIX
设置为合适的值。make
目标)在${MAKEOBJDIRPREFIX}
.我们考虑了一种简单Makefile
并描述了先前设置正常工作所必需的安排。
program : a.o b.o c.o
cc a.o b.o c.o -o program
a.o b.o c.o : defs.h
a.o : a.c
cc -c a.c
b.o : b.c
cc -c b.c
c.o : c.c
cc -c c.c
manual.html: manual.css
manual.html: a.c b.c c.c defs.h
manualtool -c manual.css -o manual.html a.c b.c c.c defs.h
在构建a.o
程序之前,make
将从该目录运行编译器。由于源位于另一个目录中,编译器将找不到它,编译将失败。这个问题是通过使用定义的局部变量来解决的,因此前面的转换为:chdir(2)
${.OBJDIR}
cc
a.c
cc
make
Makefile
program : a.o b.o c.o
cc ${.ALLSRC} -o program
a.o b.o c.o : defs.h
a.o : a.c
cc -c ${.ALLSRC:M*.c}
b.o : b.c
cc -c ${.ALLSRC:M*.c}
c.o : c.c
cc -c ${.ALLSRC:M*.c}
manual.html: manual.css
manual.html: a.c b.c c.c defs.h
manualtool -c ${.ALLSRC:M*.css} -o manual.html ${.ALLSRC:N*.css}
请注意在最后一个秘籍中如何使用通配模式来适当地选择命令行不同位置的源片段。
freebsd的构建系统——可能还有netbsd和openbsd——使用这个功能能够同时为各种体系结构构建操作系统。(它也使清理更容易!)您可以研究这些 Makefile 以更好地理解所涉及的技术。
我用于bdsmake的便携式宏bsdowl也支持此功能,您可以查看文件和ocaml示例。bsdmake
bps.objdir.mk