如何使用目标和源的不同目录编写Makefile

如何使用目标和源的不同目录编写Makefile,makefile,bsdmake,freebsd,netbsd,openbsd,bdsmake,ocaml,Makefile,Bsdmake,Freebsd,Netbsd,Openbsd,Bdsmake,Ocaml,我正在写一个Makefile,我想把构建目录和源目录分开。我最初的想法是“哦,我可以在文件名的源路径前面写我的规则,然后处理它。” 问题是,这个解决方案将是超级重复的,看起来不是很好。为自己编写一个Makefile的最佳方法是什么?该文件将目标存储在与保存源代码的目录不同的目录中。该程序非常支持将构建目标存储在与保存源代码的目录不同的目录中。使用此功能编写Makefile可能有点困难,因此我将在回答中回顾最重要的技术 选择用于存储生成目标的目录 内置变量.OBJDIR包含构建目标的目录的名称。它

我正在写一个
Makefile
,我想把构建目录和源目录分开。我最初的想法是“哦,我可以在文件名的源路径前面写我的规则,然后处理它。”

问题是,这个解决方案将是超级重复的,看起来不是很好。为自己编写一个
Makefile
的最佳方法是什么?该文件将目标存储在与保存源代码的目录不同的目录中。

该程序非常支持将构建目标存储在与保存源代码的目录不同的目录中。使用此功能编写
Makefile
可能有点困难,因此我将在回答中回顾最重要的技术

选择用于存储生成目标的目录 内置变量
.OBJDIR
包含构建目标的目录的名称。它是这样确定的(摘自
man
页面):

程序
make
chdir(2)
设置为
.OBJDIR
,并在之前将
PWD
设置为该目录 执行任何目标。在没有任何充分准备的情况下,
.OBJDIR
.CURDIR
,因此我们需要在运行
make
构建目标之前创建所需的目录或树结构

假设,您选择依赖第一种机制来设置
.OBJDIR
,然后可以组织构建系统,以便在运行
make
构建目标之前

  • 将环境变量
    MAKEOBJDIRPREFIX
    设置为合适的值
  • 特殊脚本(可能是
    make
    目标)准备
    ${MAKEOBJDIRPREFIX}
    下的必要目录
制作文件安排

我们考虑了一个简单的<代码> Auffic文件,并描述了前一个设置所需的工作安排。

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}
请注意,在上一个配方中,如何使用globbing模式在命令行的各个位置适当地选择源代码片段

例子 构建系统(可能是和)使用此功能,以便能够同时构建各种体系结构的操作系统。(这也使清洁变得更容易!)您可以研究这些makefile,以更好地了解所涉及的技术


我的便携式宏也支持此功能的
bsdmake
,您可以查看文件
bps.objdir.mk
和示例。

使用变量和
vpath
。它起作用了吗?你能举个有代表性的例子吗?我们可以向您展示如何整理makefile,但如果我们必须猜测您正在尝试做什么,则更难。您可以使用foreach将目录路径附加到相应的文件名集合。。。。这很愚蠢,但很简单,而且很管用fine@Beta看,问题是我还没有写我的makefile,因为我想正确地开始。我的目录结构最好是
/src/
/build/
/tests/
在哪里运行Make?我假定您希望将源代码和头放在
/src/
中,并在
/build/
中生成对象和可执行文件。那
/tests/
呢?我并不特别关心我在哪里打电话。我正在编写一个库,因此
build
将是实际的库,
tests
将类似于单元测试,而不是库。我真的只想遵循典型的惯例
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}