Some illustrations to the different scenarios:

# Initial run, graph complete, node statuses according to the file system

$ make -f -
.POSIX:
t1: t2; > $@
t2: t3; set -C; > $@
t3:; > $@
> t3
set -C; > t2
> t1

$ ls -l
total 0
-rw-r--r-- 1 ... 0 Jun 25 13:48 t1
-rw-r--r-- 1 ... 0 Jun 25 13:48 t2
-rw-r--r-- 1 ... 0 Jun 25 13:48 t3

$ make -d -n -f - | make2graph -d color=red
.POSIX:
t1: t2; > $@
t2: t3; set -C; > $@
t3:; > $@
digraph G {
n2 [label="t1"];
n3 [label="t2"];
n4 [label="t3"];
n3 -> n2 ;
n4 -> n3 ;
}

# Independent prerequisite 't3' updated, graph complete, node statuses 
according to the file system

$ touch t3

$ make -f -
.POSIX:
t1: t2; > $@
t2: t3; set -C; > $@
t3:; > $@
set -C; > t2
/bin/sh: line 1: t2: cannot overwrite existing file

$ make -d -n -f - | make2graph -d color=red
.POSIX:
t1: t2; > $@
t2: t3; set -C; > $@
t3:; > $@
digraph G {
n2 [label="t1", color=red];
n3 [label="t2", color=red];
n4 [label="t3"];
n3 -> n2 ;
n4 -> n3 ;
}

# Forcing status of 't2' with option '-o', node statuses as aimed but graph 
incomplete

$ make -f - -o t2
.POSIX:
t1: t2; > $@
t2: t3; set -C; > $@
t3:; > $@
make: 't1' is up to date.

$ make -d -n -f - -o t2 | make2graph -d color=red
.POSIX:
t1: t2; > $@
t2: t3; set -C; > $@
t3:; > $@
digraph G {
n2 [label="t1"];
n3 [label="t2"];
n3 -> n2 ;
}

# Forcing status of 't2' with option '-W', re-make of 't3' correct, node 
statuses not as aimed but graph complete

$ make -f - -W t2
.POSIX:
t1: t2; > $@
t2: t3; set -C; > $@
t3:; > $@
> t1

$ ls -l
total 0
-rw-r--r-- 1 ... 0 Jun 25 13:57 t1
-rw-r--r-- 1 ... 0 Jun 25 13:48 t2
-rw-r--r-- 1 ... 0 Jun 25 13:53 t3

$ make -d -n -f - -W t2 | make2graph -d color=red
.POSIX:
t1: t2; > $@
t2: t3; set -C; > $@
t3:; > $@
digraph G {
n2 [label="t1", color=red];
n3 [label="t2"];
n4 [label="t3"];
n3 -> n2 ;
n4 -> n3 ;
}

# Forcing status of 't2' with option '-W', re-make of 't3' unnecessary, node 
statuses not as aimed but graph complete

$ make -f - -W t2
.POSIX:
t1: t2; > $@
t2: t3; set -C; > $@
t3:; > $@
> t1

$ ls -l
total 0
-rw-r--r-- 1 ... 0 Jun 25 13:58 t1
-rw-r--r-- 1 ... 0 Jun 25 13:48 t2
-rw-r--r-- 1 ... 0 Jun 25 13:53 t3

$ make -d -n -f - -W t2 | make2graph -d color=red
.POSIX:
t1: t2; > $@
t2: t3; set -C; > $@
t3:; > $@
digraph G {
n2 [label="t1", color=red];
n3 [label="t2"];
n4 [label="t3"];
n3 -> n2 ;
n4 -> n3 ;
}

# Forcing status of 't2' with the theoretical option 
'--just-enough-up-to-date', node statuses as aimed, graph complete

$ cp -p t2 t2.bak

$ ls -l
total 0
-rw-r--r-- 1 ... 0 Jun 25 13:58 t1
-rw-r--r-- 1 ... 0 Jun 25 13:48 t2
-rw-r--r-- 1 ... 0 Jun 25 13:48 t2.bak
-rw-r--r-- 1 ... 0 Jun 25 13:53 t3

$ touch -r t3 t2        # = make ... --just-enough-up-to-date t2

$ ls -l
total 0
-rw-r--r-- 1 ... 0 Jun 25 13:58 t1
-rw-r--r-- 1 ... 0 Jun 25 13:53 t2
-rw-r--r-- 1 ... 0 Jun 25 13:48 t2.bak
-rw-r--r-- 1 ... 0 Jun 25 13:53 t3

$ make -f -     # = make ... --just-enough-up-to-date t2
.POSIX:
t1: t2; > $@
t2: t3; set -C; > $@
t3:; > $@
make: 't1' is up to date.

$ make -d -n -f - | make2graph -d color=red     # = make ... 
--just-enough-up-to-date t2
.POSIX:
t1: t2; > $@
t2: t3; set -C; > $@
t3:; > $@
digraph G {
n2 [label="t1"];
n3 [label="t2"];
n4 [label="t3"];
n3 -> n2 ;
n4 -> n3 ;
}

On Tuesday, June 23rd, 2026 at 7:36 PM, WaitronCharm <[email protected]> 
wrote:

> Hello everyone
> 
> I've spent some time digging into 'src/remake.c' to better understand how 
> this behaves and wanted to share my findings, along with a potential logic 
> change I am considering.
> 
> To clarify the exact case driving this:
> 
> 1. I have a specific target that can no longer be remade because it relies on 
> a web resource that is not available anymore.
> 2. However, it has other local prerequisites that still get updated 
> regularly. These updates would normally trigger a remake of this target and 
> would not succeed in any meaningful way.
> 3. I would need to keep these prerequisites in a dependency graph (which I 
> capture via 'makefile2graph').
> 4. Other higher targets rely on this outdated but locally still fine target. 
> They can be updated at any time, but I don't want them constantly and 
> endlessly rebuilding on every single make run.
> 
> As noted before, using '-o' keeps the status clean but prunes the 
> prerequisites from the graph entirely. Conversely, '-W' (which I haven't 
> tried but assume) would preserve the graph but constantly force higher 
> rebuilds. I also cannot simply touch the target with a custom timestamp 
> because its real modification date must remain strictly bound to its last 
> effective, successful remake.
> 
> This led me to the conclusion -- which might be wrong -- that make could 
> internally fake this target's timestamp to be 'just good enough' (i.e., 
> exactly equal to or one tick newer than its latest prerequisite).
> 
> Doing so would:
> 
> - Keep its prerequisites alive in the traversal graph.
> - Report a correctly faked 'up-to-date' status in the visual log.
> - Avoid triggering cascading rebuilds for higher targets.
> 
> I am considering hacking together a local patch to introduce a new 
> command-line option -- something along the lines of 
> '--not-too-old-not-too-young-but-up-to-date=TARGET' -- to enable this 
> behavior for specific targets. The logic would essentially intercept the 
> target, declare it up-to-date so no recipe executes and dynamically set the 
> file's internal modification date to match the highest timestamp of its 
> prerequisites so subsequent processing runs smoothly.
> 
> Could anyone familiar with 'src/remake.c' point me toward the correct place 
> where these specific date comparisons and status assignments happen? Thanks.
> 
> On Tuesday, May 26th, 2026 at 3:50 PM, WaitronCharm <[email protected]> 
> wrote:
> 
> > To clarify further, simply removing -o and using -n (--just-print) instead 
> > is also not a viable workaround. While -n would traverse the prerequisites 
> > and make the graph structurally complete, the reported target build 
> > statuses would be wrong for this use case. The debug output would show 
> > targets as 'needing to be remade' rather than treating them as up-to-date 
> > via the -o override.
> >
> > There seems to be no combination of current options that yields both a 
> > fully traversed dependency graph and the correct target statuses in the 
> > debug logs.
> >
> > On Tuesday, May 26th, 2026 at 3:30 PM, WaitronCharm 
> > <[email protected]> wrote:
> >
> > > Hello,
> > >
> > > I am working on reconstructing the visual dependency graph of a build 
> > > using GNU Make's --debug output. However, I have run into a limitation 
> > > when combining debugging with the -o (--old-file) option.
> > >
> > > When a target is marked as old via -o, GNU Make seems to immediately 
> > > optimize away the traversal of that target's prerequisites. Because these 
> > > prerequisites are not traversed, they are completely omitted from the 
> > > debug log. This leaves the reconstructed visual graph incomplete.
> > >
> > > From an execution standpoint, optimizing out these checks makes perfect 
> > > sense. However, for tooling and visualization, it creates a blind spot. 
> > > Could the final decision to consider a target up-to-date (based on -o) be 
> > > deferred until after its prerequisites have been traversed in the graph?
> > >
> > > I tried using the -n (--just-print / dry-run) option as an alternative to 
> > > see the full graph without executing commands, but it has a different 
> > > limitation: rules that update included makefiles are still actively 
> > > executed under -n.
> > >
> > > This leaves a gap in the current options. There appears to be no 
> > > combination of flags that allows a user to safely skip a target's 
> > > execution while still fully discovering and dumping its underlying 
> > > dependency tree in the debug output.
> > >
> > > Here is a minimal example demonstrating the behavior:
> > >
> > > $ make --debug -f - -o t1
> > > GNU Make 4.4.1
> > > Built for x86_64-pc-cygwin
> > > Copyright (C) 1988-2023 Free Software Foundation, Inc.
> > > License GPLv3+: GNU GPL version 3 or later 
> > > <https://gnu.org/licenses/gpl.html>
> > > This is free software: you are free to change and redistribute it.
> > > There is NO WARRANTY, to the extent permitted by law.
> > > t1: t2; echo $@
> > > t2:; echo $@
> > > Reading makefiles...
> > > Updating makefiles....
> > > Updating goal targets....
> > > make: 't1' is up to date.
> > >
> > > Notice that t2 is never mentioned or evaluated in the debug output above. 
> > > Compare this to a normal run where the full relationship is explicitly 
> > > printed:
> > >
> > > $ make --debug -f -
> > > GNU Make 4.4.1
> > > Built for x86_64-pc-cygwin
> > > Copyright (C) 1988-2023 Free Software Foundation, Inc.
> > > License GPLv3+: GNU GPL version 3 or later 
> > > <https://gnu.org/licenses/gpl.html>
> > > This is free software: you are free to change and redistribute it.
> > > There is NO WARRANTY, to the extent permitted by law.
> > > t1: t2; echo $@
> > > t2:; echo $@
> > > Reading makefiles...
> > > Updating makefiles....
> > > Updating goal targets....
> > >  File 't1' does not exist.
> > >   File 't2' does not exist.
> > >  Must remake target 't2'.
> > > echo t2
> > > t2
> > >  Successfully remade target file 't2'.
> > > Must remake target 't1'.
> > > echo t1
> > > t1
> > > Successfully remade target file 't1'.
> > >
> > > Is this immediate pruning of the graph an intentional design constraint 
> > > for performance, or would the maintainers consider a patch/option that 
> > > forces prerequisite traversal even when a target is short-circuited by -o?
> > >
> > > I would love to hear your thoughts on whether this use case is currently 
> > > supported through other means, or if a feature request is appropriate 
> > > here.
> > >
> > >

Reply via email to