diff --git a/arch/lkl/Makefile b/arch/lkl/Makefile index f615869a2814c34..003ca5a7555659f 100644 --- a/arch/lkl/Makefile +++ b/arch/lkl/Makefile @@ -82,18 +82,36 @@ archprepare: arch/lkl/include/generated/uapi/asm/config.h all: lkl.o arch/lkl/include/generated/uapi/asm/syscall_defs.h +# The recipe runs on every build because 'vmlinux' is PHONY in the top-level +# Makefile, so we cannot use $(if_changed) (newer-prereqs filters out PHONY, +# making it miss real vmlinux content changes). Instead, write to a tmp file +# and cmp before replacing, so $@'s mtime is preserved on no-op rebuilds and +# downstream consumers (e.g. tools/lkl/liblkl.a) are not relinked needlessly. +quiet_cmd_link_lkl = OBJCOPY $@ + cmd_link_lkl = $(OBJCOPY) $(if $(KEEP_EH_FRAMES),,-R .eh_frame) \ + -R .syscall_defs \ + $(foreach sym,$(LKL_ENTRY_POINTS),-G$(prefix)$(sym)) \ + --prefix-symbols=$(prefix) $< $@.new && \ + { if cmp -s $@.new $@; then rm -f $@.new; \ + else mv -f $@.new $@; fi; } + lkl.o: vmlinux - $(OBJCOPY) $(if $(KEEP_EH_FRAMES),,-R .eh_frame) -R .syscall_defs $(foreach sym,$(LKL_ENTRY_POINTS),-G$(prefix)$(sym)) --prefix-symbols=$(prefix) vmlinux lkl.o + $(call cmd,link_lkl) + +quiet_cmd_gen_syscall_defs = OBJCOPY $@ + cmd_gen_syscall_defs = $(OBJCOPY) -j .syscall_defs -O binary \ + --set-section-flags .syscall_defs=alloc $< $@.raw && \ + sed 's/\x0//g' $@.raw > $@.new && rm -f $@.raw && \ + { if cmp -s $@.new $@; then rm -f $@.new; \ + else mv -f $@.new $@; fi; } arch/lkl/include/generated/uapi/asm/syscall_defs.h: vmlinux - $(OBJCOPY) -j .syscall_defs -O binary --set-section-flags .syscall_defs=alloc $< $@ - $(Q) export tmpfile=$(shell mktemp); \ - sed 's/\x0//g' $@ > $$tmpfile; mv $$tmpfile $@ ; rm -f $$tmpfile + $(call cmd,gen_syscall_defs) install: scripts_unifdef @echo " INSTALL $(INSTALL_PATH)/lib/lkl.o" @mkdir -p $(INSTALL_PATH)/lib/ - @cp lkl.o $(INSTALL_PATH)/lib/ + @cp -p lkl.o $(INSTALL_PATH)/lib/ @$(srctree)/arch/lkl/scripts/headers_install.py \ $(subst -j,-j$(NPROC),$(findstring -j,$(MAKEFLAGS))) \ $(INSTALL_PATH)/include diff --git a/arch/lkl/include/uapi/asm/Kbuild b/arch/lkl/include/uapi/asm/Kbuild index c9ed295242b2d5b..b3c1b6b6d6deaf1 100644 --- a/arch/lkl/include/uapi/asm/Kbuild +++ b/arch/lkl/include/uapi/asm/Kbuild @@ -3,6 +3,7 @@ generic-y += kvm_para.h generated-y += config.h +generated-y += syscall_defs.h # no header-y since we need special user headers handling # see arch/lkl/script/headers.py diff --git a/arch/lkl/scripts/headers_install.py b/arch/lkl/scripts/headers_install.py index 43fe5ac5829d787..4b895e35e129ff9 100755 --- a/arch/lkl/scripts/headers_install.py +++ b/arch/lkl/scripts/headers_install.py @@ -128,10 +128,16 @@ def install_headers(self): os.makedirs(out_dir) except: pass - print(" INSTALL\t%s" % (out_dir + "/" + os.path.basename(h))) - os.system(self.srctree+"/scripts/headers_install.sh %s %s" % (self.relpath2abspath(h), - out_dir + "/" + os.path.basename(h))) - new_headers.add(out_dir + "/" + os.path.basename(h)) + # Install to a .raw tmp first. update_header() will read the raw + # content, produce the final prefixed version, and only overwrite + # the final destination when content differs - preserving mtime + # on no-op rebuilds so downstream host objects are not recompiled. + raw = out_dir + "/" + os.path.basename(h) + ".raw" + ret = os.system(self.srctree+"/scripts/headers_install.sh %s %s" % + (self.relpath2abspath(h), raw)) + if ret != 0: + sys.exit(1) + new_headers.add(raw) self.headers = new_headers @@ -161,7 +167,9 @@ def find_all_symbols(self): self.defines.add("__NR_stime") def update_header(self, h): - print(" REPLACE\t%s" % h) + # h is a .raw tmp file produced by install_headers(); the final + # destination is h without the .raw suffix. + dst = h[:-len(".raw")] content = open(h).read() for i in self.includes: search_str = r"(#[ \t]*include[ \t]*[<\"][ \t]*)" + i + r"([ \t]*[>\"])" @@ -184,7 +192,11 @@ def update_header(self, h): search_str = r"(\W?union\s+)" + s + r"(\W)" replace_str = "\\1" + self.lkl_prefix(s) + "\\2" content = re.sub(search_str, replace_str, content, flags = re.MULTILINE) - open(h, 'w').write(content) + existing = open(dst).read() if os.path.exists(dst) else None + if content != existing: + print(" INSTALL\t%s" % dst) + open(dst, 'w').write(content) + os.unlink(h) def update_headers(self): p = multiprocessing.Pool(args.jobs) diff --git a/tools/lkl/Makefile b/tools/lkl/Makefile index d3d91841014ea92..7708058ab141f8a 100644 --- a/tools/lkl/Makefile +++ b/tools/lkl/Makefile @@ -75,7 +75,11 @@ $(DOT_CONFIG): $(OUTPUT)/kernel.config $(Q)$(MAKE) -C ../.. ARCH=lkl $(KOPT) syncconfig # rule to build lkl.o -$(OUTPUT)lib/lkl.o: bin/stat $(DOT_CONFIG) +# FORCE is required so the recursive kernel build is always invoked; kbuild +# inside the sub-make handles incremental compilation based on source-file +# timestamps. Without FORCE, changes to kernel sources are silently ignored +# because lib/lkl.o has no dependency on them. +$(OUTPUT)lib/lkl.o: bin/stat $(DOT_CONFIG) FORCE # this workaround is for arm32 linker (ld.gold) $(Q)export PATH="$(srctree)/tools/lkl/bin/:${PATH}" ;\ $(MAKE) -C ../.. ARCH=lkl $(KOPT)