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

NetBSD Home
NetBSD PR Database Search

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