Skip to content

Commit 2df8220

Browse files
committed
kbuild: build init/built-in.a just once
Kbuild builds init/built-in.a twice; first during the ordinary directory descending, second from scripts/link-vmlinux.sh. We do this because UTS_VERSION contains the build version and the timestamp. We cannot update it during the normal directory traversal since we do not yet know if we need to update vmlinux. UTS_VERSION is temporarily calculated, but omitted from the update check. Otherwise, vmlinux would be rebuilt every time. When Kbuild results in running link-vmlinux.sh, it increments the version number in the .version file and takes the timestamp at that time to really fix UTS_VERSION. However, updating the same file twice is a footgun. To avoid nasty timestamp issues, all build artifacts that depend on init/built-in.a are atomically generated in link-vmlinux.sh, where some of them do not need rebuilding. To fix this issue, this commit changes as follows: [1] Split UTS_VERSION out to include/generated/utsversion.h from include/generated/compile.h include/generated/utsversion.h is generated just before the vmlinux link. It is generated under include/generated/ because some decompressors (s390, x86) use UTS_VERSION. [2] Split init_uts_ns and linux_banner out to init/version-timestamp.c from init/version.c init_uts_ns and linux_banner contain UTS_VERSION. During the ordinary directory descending, they are compiled with __weak and used to determine if vmlinux needs relinking. Just before the vmlinux link, they are compiled without __weak to embed the real version and timestamp. Signed-off-by: Masahiro Yamada <[email protected]>
1 parent 561daaa commit 2df8220

File tree

12 files changed

+120
-131
lines changed

12 files changed

+120
-131
lines changed

arch/powerpc/boot/wrapper

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ fi
433433
# Extract kernel version information, some platforms want to include
434434
# it in the image header
435435
version=`${CROSS}strings "$kernel" | grep '^Linux version [-0-9.]' | \
436-
cut -d' ' -f3`
436+
head -n1 | cut -d' ' -f3`
437437
if [ -n "$version" ]; then
438438
uboot_version="-n Linux-$version"
439439
fi

arch/s390/boot/version.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// SPDX-License-Identifier: GPL-2.0
2+
#include <generated/utsversion.h>
23
#include <generated/utsrelease.h>
34
#include <generated/compile.h>
45
#include "boot.h"

arch/x86/boot/compressed/kaslr.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <linux/uts.h>
3030
#include <linux/utsname.h>
3131
#include <linux/ctype.h>
32+
#include <generated/utsversion.h>
3233
#include <generated/utsrelease.h>
3334

3435
#define _SETUP

arch/x86/boot/version.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
*/
1212

1313
#include "boot.h"
14+
#include <generated/utsversion.h>
1415
#include <generated/utsrelease.h>
1516
#include <generated/compile.h>
1617

init/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# SPDX-License-Identifier: GPL-2.0-only
2+
/utsversion-tmp.h

init/Makefile

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,49 @@ mounts-y := do_mounts.o
1919
mounts-$(CONFIG_BLK_DEV_RAM) += do_mounts_rd.o
2020
mounts-$(CONFIG_BLK_DEV_INITRD) += do_mounts_initrd.o
2121

22-
# dependencies on generated files need to be listed explicitly
23-
$(obj)/version.o: include/generated/compile.h
22+
#
23+
# UTS_VERSION
24+
#
25+
26+
smp-flag-$(CONFIG_SMP) := SMP
27+
preempt-flag-$(CONFIG_PREEMPT_BUILD) := PREEMPT
28+
preempt-flag-$(CONFIG_PREEMPT_DYNAMIC) := PREEMPT_DYNAMIC
29+
preempt-flag-$(CONFIG_PREEMPT_RT) := PREEMPT_RT
30+
31+
build-version = $(or $(KBUILD_BUILD_VERSION), $(build-version-auto))
32+
build-timestamp = $(or $(KBUILD_BUILD_TIMESTAMP), $(build-timestamp-auto))
33+
34+
# Maximum length of UTS_VERSION is 64 chars
35+
filechk_uts_version = \
36+
utsver=$$(echo '$(pound)'"$(build-version)" $(smp-flag-y) $(preempt-flag-y) "$(build-timestamp)" | cut -b -64); \
37+
echo '$(pound)'define UTS_VERSION \""$${utsver}"\"
38+
39+
#
40+
# Build version.c with temporary UTS_VERSION
41+
#
2442

25-
# compile.h changes depending on hostname, generation number, etc,
26-
# so we regenerate it always.
27-
# mkcompile_h will make sure to only update the
28-
# actual file if its content has changed.
43+
$(obj)/utsversion-tmp.h: FORCE
44+
$(call filechk,uts_version)
2945

30-
quiet_cmd_compile.h = CHK $@
31-
cmd_compile.h = \
32-
$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ \
33-
"$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CONFIG_PREEMPT_BUILD)" \
34-
"$(CONFIG_PREEMPT_DYNAMIC)" "$(CONFIG_PREEMPT_RT)" \
35-
"$(CONFIG_CC_VERSION_TEXT)" "$(LD)"
46+
clean-files += utsversion-tmp.h
47+
48+
$(obj)/version.o: include/generated/compile.h $(obj)/utsversion-tmp.h
49+
CFLAGS_version.o := -include $(obj)/utsversion-tmp.h
50+
51+
filechk_compile.h = $(srctree)/scripts/mkcompile_h \
52+
"$(UTS_MACHINE)" "$(CONFIG_CC_VERSION_TEXT)" "$(LD)"
3653

3754
include/generated/compile.h: FORCE
38-
$(call cmd,compile.h)
55+
$(call filechk,compile.h)
56+
57+
#
58+
# Build version-timestamp.c with final UTS_VERSION
59+
#
60+
61+
include/generated/utsversion.h: build-version-auto = $(shell $(srctree)/$(src)/build-version)
62+
include/generated/utsversion.h: build-timestamp-auto = $(shell LC_ALL=C date)
63+
include/generated/utsversion.h: FORCE
64+
$(call filechk,uts_version)
65+
66+
$(obj)/version-timestamp.o: include/generated/utsversion.h
67+
CFLAGS_version-timestamp.o := -include include/generated/utsversion.h

init/build-version

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/sh
2+
# SPDX-License-Identifier: GPL-2.0-only
3+
4+
prev_ver=$(cat .version 2>/dev/null) &&
5+
ver=$(expr ${prev_ver} + 1 2>/dev/null) ||
6+
ver=1
7+
8+
echo ${ver} > .version
9+
10+
echo ${ver}

init/version-timestamp.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
3+
#include <generated/compile.h>
4+
#include <generated/utsrelease.h>
5+
#include <linux/version.h>
6+
#include <linux/proc_ns.h>
7+
#include <linux/refcount.h>
8+
#include <linux/uts.h>
9+
#include <linux/utsname.h>
10+
11+
struct uts_namespace init_uts_ns = {
12+
.ns.count = REFCOUNT_INIT(2),
13+
.name = {
14+
.sysname = UTS_SYSNAME,
15+
.nodename = UTS_NODENAME,
16+
.release = UTS_RELEASE,
17+
.version = UTS_VERSION,
18+
.machine = UTS_MACHINE,
19+
.domainname = UTS_DOMAINNAME,
20+
},
21+
.user_ns = &init_user_ns,
22+
.ns.inum = PROC_UTS_INIT_INO,
23+
#ifdef CONFIG_UTS_NS
24+
.ns.ops = &utsns_operations,
25+
#endif
26+
};
27+
28+
/* FIXED STRINGS! Don't touch! */
29+
const char linux_banner[] =
30+
"Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
31+
LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";

init/version.c

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,6 @@
1818
#include <generated/utsrelease.h>
1919
#include <linux/proc_ns.h>
2020

21-
struct uts_namespace init_uts_ns = {
22-
.ns.count = REFCOUNT_INIT(2),
23-
.name = {
24-
.sysname = UTS_SYSNAME,
25-
.nodename = UTS_NODENAME,
26-
.release = UTS_RELEASE,
27-
.version = UTS_VERSION,
28-
.machine = UTS_MACHINE,
29-
.domainname = UTS_DOMAINNAME,
30-
},
31-
.user_ns = &init_user_ns,
32-
.ns.inum = PROC_UTS_INIT_INO,
33-
#ifdef CONFIG_UTS_NS
34-
.ns.ops = &utsns_operations,
35-
#endif
36-
};
37-
EXPORT_SYMBOL_GPL(init_uts_ns);
38-
3921
static int __init early_hostname(char *arg)
4022
{
4123
size_t bufsize = sizeof(init_uts_ns.name.nodename);
@@ -51,15 +33,23 @@ static int __init early_hostname(char *arg)
5133
}
5234
early_param("hostname", early_hostname);
5335

54-
/* FIXED STRINGS! Don't touch! */
55-
const char linux_banner[] =
56-
"Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
57-
LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";
58-
5936
const char linux_proc_banner[] =
6037
"%s version %s"
6138
" (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ")"
6239
" (" LINUX_COMPILER ") %s\n";
6340

6441
BUILD_SALT;
6542
BUILD_LTO_INFO;
43+
44+
/*
45+
* init_uts_ns and linux_banner contain the build version and timestamp,
46+
* which are really fixed at the very last step of build process.
47+
* They are compiled with __weak first, and without __weak later.
48+
*/
49+
50+
struct uts_namespace init_uts_ns __weak;
51+
const char linux_banner[] __weak;
52+
53+
#include "version-timestamp.c"
54+
55+
EXPORT_SYMBOL_GPL(init_uts_ns);

kernel/gen_kheaders.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ if [ "$building_out_of_srctree" ]; then
3131
fi
3232
all_dirs="$all_dirs $dir_list"
3333

34-
# include/generated/compile.h is ignored because it is touched even when none
35-
# of the source files changed.
34+
# include/generated/utsversion.h is ignored because it is generated after this
35+
# script is executed. (utsversion.h is unneeded for kheaders)
3636
#
3737
# When Kconfig regenerates include/generated/autoconf.h, its timestamp is
3838
# updated, but the contents might be still the same. When any CONFIG option is
@@ -42,7 +42,7 @@ all_dirs="$all_dirs $dir_list"
4242
#
4343
# Ignore them for md5 calculation to avoid pointless regeneration.
4444
headers_md5="$(find $all_dirs -name "*.h" |
45-
grep -v "include/generated/compile.h" |
45+
grep -v "include/generated/utsversion.h" |
4646
grep -v "include/generated/autoconf.h" |
4747
xargs ls -l | md5sum | cut -d ' ' -f1)"
4848

scripts/link-vmlinux.sh

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ vmlinux_link()
7575
objs="${objs} .vmlinux.export.o"
7676
fi
7777

78+
objs="${objs} init/version-timestamp.o"
79+
7880
if [ "${SRCARCH}" = "um" ]; then
7981
wl=-Wl,
8082
ld="${CC}"
@@ -213,19 +215,6 @@ if [ "$1" = "clean" ]; then
213215
exit 0
214216
fi
215217

216-
# Update version
217-
info GEN .version
218-
if [ -r .version ]; then
219-
VERSION=$(expr 0$(cat .version) + 1)
220-
echo $VERSION > .version
221-
else
222-
rm -f .version
223-
echo 1 > .version
224-
fi;
225-
226-
# final build of init/
227-
${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init need-builtin=1
228-
229218
#link vmlinux.o
230219
${MAKE} -f "${srctree}/scripts/Makefile.vmlinux_o"
231220

@@ -260,6 +249,8 @@ if is_enabled CONFIG_MODULES; then
260249
${MAKE} -f "${srctree}/scripts/Makefile.vmlinux" .vmlinux.export.o
261250
fi
262251

252+
${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init init/version-timestamp.o
253+
263254
btf_vmlinux_bin_o=""
264255
if is_enabled CONFIG_DEBUG_INFO_BTF; then
265256
btf_vmlinux_bin_o=.btf.vmlinux.bin.o

scripts/mkcompile_h

Lines changed: 11 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
11
#!/bin/sh
22
# SPDX-License-Identifier: GPL-2.0
33

4-
TARGET=$1
5-
ARCH=$2
6-
SMP=$3
7-
PREEMPT=$4
8-
PREEMPT_DYNAMIC=$5
9-
PREEMPT_RT=$6
10-
CC_VERSION="$7"
11-
LD=$8
4+
UTS_MACHINE=$1
5+
CC_VERSION="$2"
6+
LD=$3
127

138
# Do not expand names
149
set -f
@@ -17,17 +12,6 @@ set -f
1712
LC_ALL=C
1813
export LC_ALL
1914

20-
if [ -z "$KBUILD_BUILD_VERSION" ]; then
21-
VERSION=$(cat .version 2>/dev/null || echo 1)
22-
else
23-
VERSION=$KBUILD_BUILD_VERSION
24-
fi
25-
26-
if [ -z "$KBUILD_BUILD_TIMESTAMP" ]; then
27-
TIMESTAMP=`date`
28-
else
29-
TIMESTAMP=$KBUILD_BUILD_TIMESTAMP
30-
fi
3115
if test -z "$KBUILD_BUILD_USER"; then
3216
LINUX_COMPILE_BY=$(whoami | sed 's/\\/\\\\/')
3317
else
@@ -39,63 +23,12 @@ else
3923
LINUX_COMPILE_HOST=$KBUILD_BUILD_HOST
4024
fi
4125

42-
UTS_VERSION="#$VERSION"
43-
CONFIG_FLAGS=""
44-
if [ -n "$SMP" ] ; then CONFIG_FLAGS="SMP"; fi
45-
46-
if [ -n "$PREEMPT_RT" ] ; then
47-
CONFIG_FLAGS="$CONFIG_FLAGS PREEMPT_RT"
48-
elif [ -n "$PREEMPT_DYNAMIC" ] ; then
49-
CONFIG_FLAGS="$CONFIG_FLAGS PREEMPT_DYNAMIC"
50-
elif [ -n "$PREEMPT" ] ; then
51-
CONFIG_FLAGS="$CONFIG_FLAGS PREEMPT"
52-
fi
53-
54-
# Truncate to maximum length
55-
UTS_LEN=64
56-
UTS_VERSION="$(echo $UTS_VERSION $CONFIG_FLAGS $TIMESTAMP | cut -b -$UTS_LEN)"
57-
58-
# Generate a temporary compile.h
59-
60-
{ echo /\* This file is auto generated, version $VERSION \*/
61-
if [ -n "$CONFIG_FLAGS" ] ; then echo "/* $CONFIG_FLAGS */"; fi
26+
LD_VERSION=$($LD -v | head -n1 | sed 's/(compatible with [^)]*)//' \
27+
| sed 's/[[:space:]]*$//')
6228

63-
echo \#define UTS_MACHINE \"$ARCH\"
64-
65-
echo \#define UTS_VERSION \"$UTS_VERSION\"
66-
67-
printf '#define LINUX_COMPILE_BY "%s"\n' "$LINUX_COMPILE_BY"
68-
echo \#define LINUX_COMPILE_HOST \"$LINUX_COMPILE_HOST\"
69-
70-
LD_VERSION=$($LD -v | head -n1 | sed 's/(compatible with [^)]*)//' \
71-
| sed 's/[[:space:]]*$//')
72-
printf '#define LINUX_COMPILER "%s"\n' "$CC_VERSION, $LD_VERSION"
73-
} > .tmpcompile
74-
75-
# Only replace the real compile.h if the new one is different,
76-
# in order to preserve the timestamp and avoid unnecessary
77-
# recompilations.
78-
# We don't consider the file changed if only the date/time changed,
79-
# unless KBUILD_BUILD_TIMESTAMP was explicitly set (e.g. for
80-
# reproducible builds with that value referring to a commit timestamp).
81-
# A kernel config change will increase the generation number, thus
82-
# causing compile.h to be updated (including date/time) due to the
83-
# changed comment in the
84-
# first line.
85-
86-
if [ -z "$KBUILD_BUILD_TIMESTAMP" ]; then
87-
IGNORE_PATTERN="UTS_VERSION"
88-
else
89-
IGNORE_PATTERN="NOT_A_PATTERN_TO_BE_MATCHED"
90-
fi
91-
92-
if [ -r $TARGET ] && \
93-
grep -v $IGNORE_PATTERN $TARGET > .tmpver.1 && \
94-
grep -v $IGNORE_PATTERN .tmpcompile > .tmpver.2 && \
95-
cmp -s .tmpver.1 .tmpver.2; then
96-
rm -f .tmpcompile
97-
else
98-
echo " UPD $TARGET"
99-
mv -f .tmpcompile $TARGET
100-
fi
101-
rm -f .tmpver.1 .tmpver.2
29+
cat <<EOF
30+
#define UTS_MACHINE "${UTS_MACHINE}"
31+
#define LINUX_COMPILE_BY "${LINUX_COMPILE_BY}"
32+
#define LINUX_COMPILE_HOST "${LINUX_COMPILE_HOST}"
33+
#define LINUX_COMPILER "${CC_VERSION}, ${LD_VERSION}"
34+
EOF

0 commit comments

Comments
 (0)