
Question:
I have a very simple Makefile that just shells out to another Makefile:
all:
cd src && make all
My directory structure (the Makefile
is in the top-level directory):
[I] mqudsi@php ~/bbcp> tree -d
.
├── bin
│ └── FreeBSD
├── obj
│ └── FreeBSD
├── src
└── utils
This works just fine under Linux, but under FreeBSD, it gives an error about src
not being found.
To debug, I updated the Makefile command to pwd; cd src && make all
and I discovered that <em>somehow</em> when I run make
in the top-level directory, it is being executed under ./obj
instead, meaning it's looking for ./obj/src/
to cd
into.
Aside from the fact that I have no clue why it's doing that, I presumed for sure that calling gmake
instead of make
under FreeBSD would take care of it, but that wasn't the case (and I'm relieved, because I can't believe there is that huge of a difference between BSD make and GNU make in terms of core operation).
The odd thing is, deleting obj
makes everything work perfectly. So in the presence of an obj
directory, make
cds into ./obj
first; otherwise it executes as you'd expect it to.
Answering my own question here.
From the FreeBSD make
man page:
.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.
The key part being
<blockquote><strong>In all cases, make will chdir(2) to specified directory if it exists, and set .OBJDIR'
PWD' to that directory before executing any targets.</strong>
By contrast, the <a href="https://www.gnu.org/software/make/manual/make.html" rel="nofollow">GNU make manual page</a> makes no such reference to any sort of automatic determination of OBJDIR
, only that it will be used if it is set.
The solution was to override the OBJDIR
variable via the pseudotarget .OBJDIR
:
.OBJDIR: ./
all:
cd src && make
clean:
cd src && make clean
An alternative solution is to prefix the cd
targets with ${CURDIR}
, which isn't modified after the chdir
into OBJDIR
.
I don't get why gmake
behaved the same way, however. That feels almost like a bug to me.