From 5ffeb3d16aa5fd5b535083286afbe875a7fbadc5 Mon Sep 17 00:00:00 2001 From: d00f <8052722+DrDoof@users.noreply.github.com> Date: Mon, 7 Sep 2026 23:46:03 +0200 Subject: [PATCH] build: make the static-file build repeatable Two things kept the same source from producing the same image. fileadder walked the input directory with readdir(), which returns entries in whatever order the filesystem hands them over. The same tree therefore embedded the files in a different order on a different filesystem, and the image differed byte for byte. scandir() with alphasort() fixes the order. version.h was listed in .PHONY, which makes it permanently out of date and propagates that to everything including it, so a plain build recompiled the four largest translation units even when nothing had changed. Dropping it from .PHONY alone would go too far the other way: with no prerequisites the recipe would never run again and the version string would freeze at its first value. A FORCE prerequisite keeps the recipe running every time, and the generated header is only moved into place when its content actually differs, so the timestamp survives an unchanged rebuild. Measured on this tree: with FORCE the version follows GIT_VERSION and an unchanged rebuild leaves version.h untouched; without it the header keeps the value from the first build. --- Makefile | 9 ++++++--- tools/fileadder.c | 12 ++++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 67fd42d7..9a4a1236 100644 --- a/Makefile +++ b/Makefile @@ -112,11 +112,14 @@ html_min: $(HTML) html_data.c html_data.h &: $(HTML) | tools html_min tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -b BANK1 -z -d $(HTML_MIN) -p html_data -$(VERSION_HEADER): +$(VERSION_HEADER): FORCE @printf '%s\n' "#ifndef VERSION_H" "#define VERSION_H" \ "#define VERSION_SW \"$(VERSION_EXTENSION)\"" \ "#define BUILD_DATE \"$(BUILD_DATE)\"" \ - "#endif" > $(VERSION_HEADER) + "#endif" > $(VERSION_HEADER).tmp + @cmp -s $(VERSION_HEADER).tmp $(VERSION_HEADER) \ + && rm -f $(VERSION_HEADER).tmp \ + || mv $(VERSION_HEADER).tmp $(VERSION_HEADER) httpd: html_data.h @@ -166,7 +169,7 @@ $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin: $(BUILDDIR)/rtlplayground.i tools/output/crc_calculator -u $@ ln -sf $(MACHINE)/rtlplayground-$(FILENAME_EXTENSION).bin output/rtlplayground.bin -.PHONY: clean distclean all $(SUBDIRS) $(SUBDIRSCLEAN) $(VERSION_HEADER) create_build_dir +.PHONY: clean distclean all $(SUBDIRS) $(SUBDIRSCLEAN) create_build_dir .PHONY: machine_check: diff --git a/tools/fileadder.c b/tools/fileadder.c index 1da276ec..eec14d23 100644 --- a/tools/fileadder.c +++ b/tools/fileadder.c @@ -338,15 +338,16 @@ int main(int argc, char **argv) if (stat(arguments.data_file, &s) == 0 && s.st_mode & S_IFDIR) { printf("Adding entries in directory %s\n", arguments.data_file); addsDir = true; - DIR *dirptr = opendir(arguments.data_file); - if (!dirptr) { + struct dirent **entries; + int n_entries = scandir(arguments.data_file, &entries, NULL, alphasort); + if (n_entries < 0) { fprintf(stderr, "%s: ", arguments.data_file); perror("Error opening directory"); return 5; } - struct dirent *in_file; int addr = arguments.address; - while ( (in_file = readdir(dirptr)) ) { + for (int e = 0; e < n_entries; e++) { + struct dirent *in_file = entries[e]; snprintf(pathbuffer, PATH_SIZE, "%s/%s", arguments.data_file, in_file->d_name); if (stat(pathbuffer, &s) < 0) { fprintf(stderr, "%s: ", pathbuffer); @@ -377,6 +378,9 @@ int main(int argc, char **argv) addidx(in_file->d_name, addr, data_read); addr += data_read; } + for (int e = 0; e < n_entries; e++) + free(entries[e]); + free(entries); } else { size_t data_read = addfile(arguments.data_file, arguments.address);