NetBSD Problem Report #60435
From kre@munnari.OZ.AU Fri Jul 10 06:56:07 2026
Return-Path: <kre@munnari.OZ.AU>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256
client-signature RSA-PSS (2048 bits) client-digest SHA256)
(Client CN "mail.netbsd.org", Issuer "YR2" (not verified))
by mollari.NetBSD.org (Postfix) with ESMTPS id 122781A923A
for <gnats-bugs@gnats.NetBSD.org>; Fri, 10 Jul 2026 06:56:07 +0000 (UTC)
Message-Id: <202607100644.66A6iT1Q008807@jacaranda.noi.kre.to>
Date: Fri, 10 Jul 2026 13:44:29 +0700 (+07)
From: kre@munnari.OZ.AU
To: gnats-bugs@NetBSD.org
Subject: "make depend" is too fussy
X-Send-Pr-Version: 3.95
X-From4GNATS: "kre@munnari.OZ.AU via gnats" <gnats-admin@NetBSD.org>
>Number: 60435
>Category: toolchain
>Synopsis: "make depend" is too fussy
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: toolchain-manager
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Fri Jul 10 07:00:00 +0000 2026
>Last-Modified: Fri Jul 10 20:10:00 +0000 2026
>Originator: Robert Elz
>Release: NetBSD 11.99.6
>Organization:
>Environment:
System: NetBSD jacaranda.noi.kre.to 11.99.6 NetBSD 11.99.6 (JACARANDA:1.1-20260627) #287: Sun Jun 28 03:17:40 +07 2026 kre@jacaranda.noi.kre.to:/usr/obj/testing/kernels/amd64/JACARANDA amd64
Architecture: x86_64
Machine: amd64
>Description:
If we have a file a.c
#include "b.h"
int func(void);
func(void) {
return B_VERSION;
}
but have no b.h, as that is to be built as part of the build process,
with the Makefile containing (inter alia):
b.h: ${VARIOUS_FILES}
${SOME_COMMAND} ${VARIOUS_FILES} > b.h
for example, and then we "make depend" (for the first time),
currently the make depend fails, as b.h doesn't (yet) exist.
I kind of understand the intent here, without b.h we can't know what
other files it might include, which then a.c would also depend upon.
Seems rational, but that is nonsense. All we need to know, for now,
is that a.c depends upon b.h and that is what the a.d dependency
file should show.
Then when we come to do the actual build, make will see that b.h
doesn't exist, and use the recipe it has been given to build it.
Since b.h will then be newer than any possibly existing a.o, that
will need to be rebuilt. All make needed to be aware of is that
something required a.c to be recompiled, and then do it - how many
other include files b.h might have included is irrelevant, it is
going to be recompiled anyway.
Note this is not a case where different dependencies missing or out
of date cause different build scripts to be run, a.o will be being
rebuilt after b.h is made, because of b.h being out of date, always,
here. Any other dependencies that could have been extracted from
b.h could not alter that.
If we then clean up everything (including b.h) then the next time
we build, all the same happens again, and all is good.
If we don't clean, and just do another build, then make sees that
b.h is newer than the a.d, and as a.d includes a dependency upon b.h
it looks just like any other case where an include file might
have been edited - perhaps causing the list of files it includes
to alter. In that case, make needs to rebuild a.d to get the
current list of dependencies - and it would do that in our case
too. This time b.h does exist, and anything it includes will
be discovered, just as if it had been there the first time, and
a new dependency list for a.o is now made, with the full list
of b.h and everything it includes.
>How-To-Repeat:
Just go and (locally) revert change 1.229 "Properly fix the libc build"
from src/lib/libc/gen/Makefile.inc
Then make sure the OBJDIR for libc is empty (or doesn't exist
at all), and attempt a build.
Expect abject failure. That should not happen, we should
not need to explicitly add the nonsense explicit dependency info
that that change added. That's the whole point of "make depend".
Note that if a build is done with 1.229 in place, and then
that is reverted, and an update build (-u) is performed, all will
work, as the "missing file" is no longer missing - until everything
is cleaned next, then the following build would fail. (BTDT).
>Fix:
No idea, the make system is black magic as far as I'm concerned.
>Audit-Trail:
From: Taylor R Campbell <riastradh@NetBSD.org>
To: Robert Elz <kre@munnari.OZ.AU>
Cc: netbsd-bugs@NetBSD.org, gnats-bugs@NetBSD.org
Subject: Re: toolchain/60435: "make depend" is too fussy
Date: Fri, 10 Jul 2026 18:59:37 +0000
> From: Robert Elz <kre@munnari.OZ.AU>
> Date: Fri, 10 Jul 2026 07:00:00 +0000 (UTC)
>
> Then when we come to do the actual build, make will see that b.h
> doesn't exist, and use the recipe it has been given to build it.
> Since b.h will then be newer than any possibly existing a.o, that
> will need to be rebuilt. All make needed to be aware of is that
> something required a.c to be recompiled, and then do it - how many
> other include files b.h might have included is irrelevant, it is
> going to be recompiled anyway.
>
> Note this is not a case where different dependencies missing or out
> of date cause different build scripts to be run, a.o will be being
> rebuilt after b.h is made, because of b.h being out of date, always,
> here. Any other dependencies that could have been extracted from
> b.h could not alter that.
The transitive dependencies of b.h may not affect the _first_ build of
a.o, but they will affect _subsequent_ builds of a.o. E.g., suppose
b.h includes <machine/mcontext.h>, and you run:
$ make depend
(generates a.d)
$ make
(compiles a.o)
$ edit sys/arch/amd64/include/mcontext.h
Then a subsequent `make' should trigger recompiling a.o, but the only
way for make(1) to know this is if b.h already exists when mkdep(1)
runs so it can discover the dependency on machine/mcontext.h.
We could use `cc -M -MF $*.d' in the .o rule in order to regenerate
the .d file at the same time, but we don't. It also wouldn't help if
a.c includes b.h and b.h includes c.h and _both_ b.h and c.h have to
be generated.
(Note that we would need that _in addition to_ a more lenient
mkdep(1), or else the makefile would still not know that it has to
generate b.h before it can compile a.c -> a.o.)
From: Robert Elz <kre@munnari.OZ.AU>
To: gnats-bugs@netbsd.org
Cc:
Subject: Re: toolchain/60435: "make depend" is too fussy
Date: Sat, 11 Jul 2026 03:08:12 +0700
Date: Fri, 10 Jul 2026 19:00:02 +0000 (UTC)
From: "Taylor R Campbell via gnats" <gnats-admin@NetBSD.org>
Message-ID: <20260710190002.2BBC21A923F@mollari.NetBSD.org>
| The transitive dependencies of b.h may not affect the _first_ build of
| a.o, but they will affect _subsequent_ builds of a.o.
Yes, I know.
| We could use `cc -M -MF $*.d' in the .o rule in order to regenerate
| the .d file at the same time, but we don't.
That's the kind of thing I am requesting, it was a change request, not
a bug to be fixed. If a dependency has changed, regenerate the list of
dependencies, as well as the object.
| It also wouldn't help if a.c includes b.h and b.h includes c.h and
| _both_ b.h and c.h have to be generated.
That's an unlikely case, generated files don't often include others (that
also need generating), they can just generate everything into the one file
(they are ephemeral after all) - c.h would (if it had some other use) still
get generated, but would be included in b.h as content, not as a dependency).
In the extreme case where that isn't possible, then we would need explicit
rules in the makefile to make the right thing happen, but I doubt we'd need
those very much.
| (Note that we would need that _in addition to_ a more lenient
| mkdep(1), or else the makefile would still not know that it has to
| generate b.h before it can compile a.c -> a.o.)
If a.o depends upon b.h then that's make's whole reason for existing
isn't it? b.h must be up to date before a.o can be built. Make knows
that a.o depende upon b.h because a.c has a #include "b.h" in it, and
we have run "make depend" (whether or not b.h actually exists at the time).
While I am here, I expect that you (and others) have seem that the sparc,
sparc64, and ia64 builds have been broken since I added the changes for
the new user.* sysctl vars, as that's where an include file like this was
needed. Everything else builds with the
sysctl.d: user-version.h
dependency that was the last of that set of changes, which made all the other
builds work. That include file needs to be generated (it contains the build
date/time, so it gets regenerated every time a build is done). For some
reason this isn't working on sparc sparc64 or ia64, and at the minute I have
no idea why. I can reproduce it in a sparc build here - the file is never
generated there.
I am still looking, but the build system really is not my area, I have almost
no idea how any of it works (I could handle 7th edition make just fine, but
not what that has turned into). So if anyone has any ideas, please either
implement them, or send me suggestions. The relevant Makefile is
src/lib/libc/gen/Makefile.inc
kre
ps: the atari build is also broken, has been for a while, but that one is
just the normal floppy filesystem overflow that happens ...
(Contact us)
$NetBSD: query-full-pr,v 1.51 2026/08/10 02:28:17 riastradh Exp $
$NetBSD: gnats_config.sh,v 1.10 2026/05/13 22:00:09 riastradh Exp $
Copyright © 1994-2026
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.