Re: [PATCH] kbuild: use .NOTINTERMEDIATE for future GNU Make versions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sun 11 Dec 2022 12:10:59 GMT, Masahiro Yamada wrote:
> In Kbuild, some files are generated by chains of pattern/implicit 
> rules.
> For example, *.dtb.o files in drivers/of/unittest-data/Makefile are
> generated by the chain of 3 pattern rules, like this:
> 
>   %.dts  ->  %.dtb  ->  %.dtb.S  ->  %.dtb.o
> 
> Here, %.dts is the real source, %.dtb.o is the final target.
> %.dtb and %.dtb.S are called "intermediate files".
> 
> As GNU Make manual [1] says, intermediate files are treated differently
> in two ways:
> 
>  (a) The first difference is what happens if the intermediate file does
>    not exist. If an ordinary file 'b' does not exist, and make considers
>    a target that depends on 'b', it invariably creates 'b' and then
>    updates the target from 'b'. But if 'b' is an intermediate file, then
>    make can leave well enough alone: it won't create 'b' unless one of
>    its prerequisites is out of date. This means the target depending
>    on 'b' won't be rebuilt either, unless there is some other reason
>    to update that target: for example the target doesn't exist or a
>    different prerequisite is newer than the target.
> 
>  (b) The second difference is that if make does create 'b' in order to
>    update something else, it deletes 'b' later on after it is no longer
>    needed. Therefore, an intermediate file which did not exist before
>    make also does not exist after make. make reports the deletion to
>    you by printing a 'rm' command showing which file it is deleting.
> 
> Actually, (b) is problematic for Kbuild because most of the build rules
> depend on FORCE and the if_changed* macros really determine if the
> target should be updated. So, all missing files, whether they are
> intermediate or not, are always rebuilt.
> 
> To see why (b) is a problem, delete ".SECONDARY:" from
> scripts/Kbuild.include, and repeat this command:
> 
>   $ make allmodconfig drivers/of/unittest-data/
> 
> The intermediate files will be deleted, which results in rebuilding
> intermediate and final objects in the next run of make.
> 
> In the old days, people suppressed (b) in inconsistent ways.
> As commit 54a702f70589 ("kbuild: mark $(targets) as .SECONDARY and
> remove .PRECIOUS markers") noted, you should not use .PRECIOUS because
> .PRECIOUS has the following behavior (c), which is not likely what you
> want.
> 
>  (c) If make is killed or interrupted during the execution of their
>    recipes, the target is not deleted. Also, the target is not deleted
>    on error even if .DELETE_ON_ERROR is specified.
> 
> .SECONDARY is a much better way to disable (b), but a small problem
> is that .SECONDARY enables (a), which gives a side-effect to $?;
> prerequisites marked as .SECONDARY do not appear in $?. This is a
> drawback for Kbuild.
> 
> I thought it was a bug and opened a bug report. As Paul, the GNU Make
> maintainer, concluded in [2], this is not a bug.
> 
> A good news is that, GNU Make 4.4 added the perfect solution,
> .NOTINTERMEDIATE, which cancels both (a) and (b).
> 
> For clarificaton, my understanding of .INTERMEDIATE, .SECONDARY,
> .PRECIOUS and .NOTINTERMEDIATE are as follows:
> 
>                         (a)         (b)         (c)
>   .INTERMEDIATE        enable      enable      disable
>   .SECONDARY           enable      disable     disable
>   .PRECIOUS            disable     disable     enable
>   .NOTINTERMEDIATE     disable     disable     disable
> 
> However, GNU Make 4.4 has a bug for the global .NOTINTERMEDIATE. [3]
> It was fixed by commit 6164608900ad ("[SV 63417] Ensure global
> .NOTINTERMEDIATE disables all intermediates"), and will be available
> in the next release of GNU Make.
> 
> The following is the gain for .NOTINTERMEDIATE:
> 
>   [Current Make]
> 
>       $ make allnoconfig vmlinux
>           [ full build ]
>       $ rm include/linux/device.h
>       $ make vmlinux
>         CALL    scripts/checksyscalls.sh
> 
>   Make does not notice the removal of <linux/device.h>.
> 
>   [Future Make]
> 
>       $ make-latest allnoconfig vmlinux
>           [ full build ]
>       $ rm include/linux/device.h
>       $ make-latest vmlinux
>         CC      arch/x86/kernel/asm-offsets.s
>       In file included from ./include/linux/writeback.h:13,
>                        from ./include/linux/memcontrol.h:22,
>                        from ./include/linux/swap.h:9,
>                        from ./include/linux/suspend.h:5,
>                        from arch/x86/kernel/asm-offsets.c:13:
>       ./include/linux/blk_types.h:11:10: fatal error: linux/device.h: No such file or directory
>          11 | #include <linux/device.h>
>             |          ^~~~~~~~~~~~~~~~
>       compilation terminated.
>       make-latest[1]: *** [scripts/Makefile.build:114: arch/x86/kernel/asm-offsets.s] Error 1
>       make-latest: *** [Makefile:1282: prepare0] Error 2
> 
>   Make notices the removal of <linux/device.h>, and rebuilds objects
>   that depended on <linux/device.h>. There exists a source file that
>   includes <linux/device.h>, and it raises an error.
> 
> To see detailed background information, refer to commit 2d3b1b8f0da7
> ("kbuild: drop $(wildcard $^) check in if_changed* for faster rebuild").
> 
> [1]: https://www.gnu.org/software/make/manual/make.html#Chained-Rules
> [2]: https://savannah.gnu.org/bugs/?55532
> [3]: https://savannah.gnu.org/bugs/?63417
> 
> Signed-off-by: Masahiro Yamada <masahiroy@xxxxxxxxxx>
> ---
> 
>  scripts/Kbuild.include | 13 ++++++++++---
>  1 file changed, 10 insertions(+), 3 deletions(-)
> 

I really do appreciate the detailed and enlightening reasoning.

Reviewed-by: Nicolas Schier <nicolas@xxxxxxxxx>

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [Linux&nblp;USB Development]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite Secrets]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux