[PATCH] Makefile: Make sure all linker input objects exist

In case the build system builds a directory with empty Makefile, one which does not contain any obj-y entries, the build fails to link due to missing built-in.o .
This happens because of this part of scripts/Makefile.build 81 ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),) 82 builtin-target := $(obj)/built-in.o 83 endif which does not assign builtin-target in case obj-y is empty. The built-in target is then not built at all, and built-in.o is not generated by this part of scripts/Makefile.build 325 ifdef builtin-target 326 quiet_cmd_link_o_target = AR $@ 327 # If the list of objects to link is empty, just create an empty built-in.o ... 335 targets += $(builtin-target) 336 endif # builtin-target This is the correct behavior.
The final link however expects the built-in.o to exist in every directory included in the build, even in those where the aforementioned code skipped generation of built-in.o . Make sure the built-in.o does exist for every directory used in final link simply by doing touch on every built-in.o used for the link, which will create empty built-in.o in case any built-in.o is missing.
A possible alternative fix is the always define the builtin-target and always generate built-in.o .
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org --- Cc: Bryan Brattlof bb@ti.com Cc: Greg Malysa greg.malysa@timesys.com Cc: Heinrich Schuchardt xypron.glpk@gmx.de Cc: Ian Roberts ian.roberts@timesys.com Cc: Ilias Apalodimas ilias.apalodimas@linaro.org Cc: Peter Robinson pbrobinson@gmail.com Cc: Simon Glass sjg@chromium.org Cc: Sumit Garg sumit.garg@linaro.org Cc: Tom Rini trini@konsulko.com Cc: u-boot@lists.denx.de --- Makefile | 5 ++++- arch/sandbox/config.mk | 8 ++++++-- scripts/Makefile.xpl | 2 ++ 3 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/Makefile b/Makefile index 0500eb6e0a7..03df04853c8 100644 --- a/Makefile +++ b/Makefile @@ -1779,6 +1779,7 @@ endif ifeq ($(LTO_ENABLE),y) quiet_cmd_u-boot__ ?= LTO $@ cmd_u-boot__ ?= \ + touch $(u-boot-main) ; \ $(CC) -nostdlib -nostartfiles \ $(LTO_FINAL_LDFLAGS) $(c_flags) \ $(KBUILD_LDFLAGS:%=-Wl,%) $(LDFLAGS_u-boot:%=-Wl,%) -o $@ \ @@ -1792,7 +1793,9 @@ quiet_cmd_u-boot__ ?= LTO $@ $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true) else quiet_cmd_u-boot__ ?= LD $@ - cmd_u-boot__ ?= $(LD) $(KBUILD_LDFLAGS) $(LDFLAGS_u-boot) -o $@ \ + cmd_u-boot__ ?= \ + touch $(u-boot-main) ; \ + $(LD) $(KBUILD_LDFLAGS) $(LDFLAGS_u-boot) -o $@ \ -T u-boot.lds $(u-boot-init) \ --whole-archive \ $(u-boot-main) \ diff --git a/arch/sandbox/config.mk b/arch/sandbox/config.mk index 405843800e9..dd9b7473fa9 100644 --- a/arch/sandbox/config.mk +++ b/arch/sandbox/config.mk @@ -22,7 +22,9 @@ SANITIZERS += -fsanitize=fuzzer endif KBUILD_CFLAGS += $(SANITIZERS)
-cmd_u-boot__ = $(CC) -o $@ -Wl,-T u-boot.lds $(u-boot-init) \ +cmd_u-boot__ = \ + touch $(u-boot-main) ; \ + $(CC) -o $@ -Wl,-T u-boot.lds $(u-boot-init) \ $(KBUILD_LDFLAGS:%=-Wl,%) \ $(SANITIZERS) \ $(LTO_FINAL_LDFLAGS) \ @@ -32,7 +34,9 @@ cmd_u-boot__ = $(CC) -o $@ -Wl,-T u-boot.lds $(u-boot-init) \ -Wl,--no-whole-archive \ $(PLATFORM_LIBS) -Wl,-Map -Wl,u-boot.map -Wl,--gc-sections
-cmd_u-boot-spl = (cd $(obj) && $(CC) -o $(SPL_BIN) -Wl,-T u-boot-spl.lds \ +cmd_u-boot-spl = (cd $(obj) && \ + touch $(patsubst $(obj)/%,%,$(u-boot-spl-main)) && \ + $(CC) -o $(SPL_BIN) -Wl,-T u-boot-spl.lds \ $(KBUILD_LDFLAGS:%=-Wl,%) \ $(SANITIZERS) \ $(LTO_FINAL_LDFLAGS) \ diff --git a/scripts/Makefile.xpl b/scripts/Makefile.xpl index dca5f4539d0..abc49fbe6c9 100644 --- a/scripts/Makefile.xpl +++ b/scripts/Makefile.xpl @@ -510,6 +510,7 @@ quiet_cmd_u-boot-spl ?= LTO $@ cmd_u-boot-spl ?= \ ( \ cd $(obj) && \ + touch $(patsubst $(obj)/%,%,$(u-boot-spl-main)) && \ $(CC) -nostdlib -nostartfiles $(LTO_FINAL_LDFLAGS) $(c_flags) \ $(KBUILD_LDFLAGS:%=-Wl,%) $(LDFLAGS_$(@F):%=-Wl,%) \ $(patsubst $(obj)/%,%,$(u-boot-spl-init)) \ @@ -526,6 +527,7 @@ quiet_cmd_u-boot-spl ?= LD $@ cmd_u-boot-spl ?= \ ( \ cd $(obj) && \ + touch $(patsubst $(obj)/%,%,$(u-boot-spl-main)) && \ $(LD) $(KBUILD_LDFLAGS) $(LDFLAGS_$(@F)) \ $(patsubst $(obj)/%,%,$(u-boot-spl-init)) \ --whole-archive \

Hi Marek,
On 1/12/25 11:32 PM, Marek Vasut wrote:
In case the build system builds a directory with empty Makefile, one which does not contain any obj-y entries, the build fails to link due to missing built-in.o .
This happens because of this part of scripts/Makefile.build 81 ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),) 82 builtin-target := $(obj)/built-in.o 83 endif which does not assign builtin-target in case obj-y is empty. The built-in target is then not built at all, and built-in.o is not generated by this part of scripts/Makefile.build 325 ifdef builtin-target 326 quiet_cmd_link_o_target = AR $@ 327 # If the list of objects to link is empty, just create an empty built-in.o ... 335 targets += $(builtin-target) 336 endif # builtin-target This is the correct behavior.
The final link however expects the built-in.o to exist in every directory included in the build, even in those where the aforementioned code skipped generation of built-in.o . Make sure the built-in.o does exist for every directory used in final link simply by doing touch on every built-in.o used for the link, which will create empty built-in.o in case any built-in.o is missing.
A possible alternative fix is the always define the builtin-target and always generate built-in.o .
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org
I tested this with the following diff:
""" diff --git a/board/theobroma-systems/common/Makefile b/board/theobroma-systems/common/Makefile new file mode 100644 index 00000000000..6125c1a0b79 --- /dev/null +++ b/board/theobroma-systems/common/Makefile @@ -0,0 +1,9 @@ +# +# Copyright (c) 2025 Cherry Embedded Solutions GmbH +# +# SPDX-License-Identifier: GPL-2.0-or-later +# + +ifneq ($(CONFIG_XPL_BUILD),y) +obj-y += common.o +endif diff --git a/board/theobroma-systems/jaguar_rk3588/Makefile b/board/theobroma-systems/jaguar_rk3588/Makefile index d43bf194b68..38b73d2846c 100644 --- a/board/theobroma-systems/jaguar_rk3588/Makefile +++ b/board/theobroma-systems/jaguar_rk3588/Makefile @@ -5,6 +5,3 @@ #
obj-y += jaguar_rk3588.o -ifneq ($(CONFIG_XPL_BUILD),y) -obj-y += ../common/common.o -endif diff --git a/board/theobroma-systems/puma_rk3399/Makefile b/board/theobroma-systems/puma_rk3399/Makefile index 2256e72cda1..d962b56f111 100644 --- a/board/theobroma-systems/puma_rk3399/Makefile +++ b/board/theobroma-systems/puma_rk3399/Makefile @@ -5,6 +5,3 @@ #
obj-y += puma-rk3399.o -ifneq ($(CONFIG_XPL_BUILD),y) -obj-y += ../common/common.o -endif diff --git a/board/theobroma-systems/ringneck_px30/Makefile b/board/theobroma-systems/ringneck_px30/Makefile index 4d108f2d011..31ada1a6942 100644 --- a/board/theobroma-systems/ringneck_px30/Makefile +++ b/board/theobroma-systems/ringneck_px30/Makefile @@ -5,6 +5,3 @@ #
obj-y += ringneck-px30.o -ifneq ($(CONFIG_XPL_BUILD),y) -obj-y += ../common/common.o -endif diff --git a/board/theobroma-systems/tiger_rk3588/Makefile b/board/theobroma-systems/tiger_rk3588/Makefile index 94b0859eb35..900647735fb 100644 --- a/board/theobroma-systems/tiger_rk3588/Makefile +++ b/board/theobroma-systems/tiger_rk3588/Makefile @@ -5,6 +5,3 @@ #
obj-y += tiger_rk3588.o -ifneq ($(CONFIG_XPL_BUILD),y) -obj-y += ../common/common.o -endif """
which allows me to use HAVE_VENDOR_COMMON_LIB mechanism with an empty Makefile for TPL/SPL build stage, so:
Tested-by: Quentin Schulz quentin.schulz@cherry.de
Looking forward to being able to use HAVE_VENDOR_COMMON_LIB!
Though I could actually always include the file and just ifdef CONFIG_XPL_BUILD in common.o, but let's see where this patch goes first :)
Thanks! Quentin

On 1/15/25 11:38 AM, Quentin Schulz wrote:
Hi Marek,
Hi,
On 1/12/25 11:32 PM, Marek Vasut wrote:
In case the build system builds a directory with empty Makefile, one which does not contain any obj-y entries, the build fails to link due to missing built-in.o .
This happens because of this part of scripts/Makefile.build 81 ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib- target)),) 82 builtin-target := $(obj)/built-in.o 83 endif which does not assign builtin-target in case obj-y is empty. The built-in target is then not built at all, and built-in.o is not generated by this part of scripts/Makefile.build 325 ifdef builtin-target 326 quiet_cmd_link_o_target = AR $@ 327 # If the list of objects to link is empty, just create an empty built-in.o ... 335 targets += $(builtin-target) 336 endif # builtin-target This is the correct behavior.
The final link however expects the built-in.o to exist in every directory included in the build, even in those where the aforementioned code skipped generation of built-in.o . Make sure the built-in.o does exist for every directory used in final link simply by doing touch on every built-in.o used for the link, which will create empty built-in.o in case any built- in.o is missing.
A possible alternative fix is the always define the builtin-target and always generate built-in.o .
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org
I tested this with the following diff:
[..]
which allows me to use HAVE_VENDOR_COMMON_LIB mechanism with an empty Makefile for TPL/SPL build stage, so:
Tested-by: Quentin Schulz quentin.schulz@cherry.de
Thank you
Looking forward to being able to use HAVE_VENDOR_COMMON_LIB!
Though I could actually always include the file and just ifdef CONFIG_XPL_BUILD in common.o, but let's see where this patch goes first :)
If the intent is to use an empty Makefile (with or without ifdeferry) in any directory pulled into the build, to mitigate the missing built-in.o problem, that also won't work without this patch, because empty Makefile itself won't lead to generation of the built-in.o .

On Sun, 12 Jan 2025 23:32:38 +0100, Marek Vasut wrote:
In case the build system builds a directory with empty Makefile, one which does not contain any obj-y entries, the build fails to link due to missing built-in.o .
This happens because of this part of scripts/Makefile.build 81 ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),) 82 builtin-target := $(obj)/built-in.o 83 endif which does not assign builtin-target in case obj-y is empty. The built-in target is then not built at all, and built-in.o is not generated by this part of scripts/Makefile.build 325 ifdef builtin-target 326 quiet_cmd_link_o_target = AR $@ 327 # If the list of objects to link is empty, just create an empty built-in.o ... 335 targets += $(builtin-target) 336 endif # builtin-target This is the correct behavior.
[...]
Applied to u-boot/master, thanks!
participants (4)
-
Marek Vasut
-
Marek Vasut
-
Quentin Schulz
-
Tom Rini