Make 在 FreeBSD 下启动错误的目录

Make starts in wrong directory under FreeBSD

我有一个非常简单的 Makefile,它只是 shell 到另一个 Makefile:

all:
    cd src && make all

我的目录结构(Makefile在顶级目录):

[I] mqudsi@php ~/bbcp> tree -d
.
├── bin
│   └── FreeBSD
├── obj
│   └── FreeBSD
├── src
└── utils

这在 Linux 下工作得很好,但在 FreeBSD 下,它给出了关于 src 找不到的错误。

为了调试,我将 Makefile 命令更新为 pwd; cd src && make all 并且我发现 不知何故 当我在顶部 运行 make级目录,它正在 ./obj 下执行,这意味着它正在寻找 ./obj/src/cd

除了我不知道它为什么这样做之外,我确信在 FreeBSD 下调用 gmake 而不是 make 会处理它,但事实并非如此这种情况(我松了一口气,因为我无法相信 BSD make 和 GNU make 在核心操作方面存在如此巨大的差异)。

奇怪的是,删除 obj 后一切正常。因此,在存在 obj 目录的情况下,首先 make cd 进入 ./obj;否则它会按照您的预期执行。

在这里回答我自己的问题。

来自 FreeBSD make 手册页:

.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}

              (Only if `MAKEOBJDIR' is set in the environment or
              on the command line.)

             3.   ${.CURDIR}/obj.${MACHINE}

             4.   ${.CURDIR}/obj

             5.   /usr/obj/${.CURDIR}

             6.   ${.CURDIR}

             Variable expansion is performed on the value before it's
             used, so expressions such as
               ${.CURDIR:S,^/usr/src,/var/obj,}
             may be used.  This is especially useful with
             `MAKEOBJDIR'.

             `.OBJDIR' may be modified in the makefile via the special
             target `.OBJDIR'.  In all cases, make will chdir(2) to
             the specified directory if it exists, and set `.OBJDIR'
             and `PWD' to that directory before executing any targets.

关键部分是

In all cases, make will chdir(2) to specified directory if it exists, and set .OBJDIR'PWD' to that directory before executing any targets.

相比之下,GNU make manual page 没有对 OBJDIR 的任何类型的自动确定进行此类引用,只是在设置后才会使用它。

解决方案是通过伪目标 .OBJDIR:

覆盖 OBJDIR 变量
.OBJDIR: ./

all:
    cd src && make
clean:
    cd src && make clean

另一种解决方案是在 cd 目标前加上 ${CURDIR} 前缀,在 chdirOBJDIR 之后不修改。

不过,我不明白为什么 gmake 的行为方式相同。这对我来说几乎就像一个错误。