fix(build): rebuild C outputs on HUF mode changes

Mode-specific Rust archives exposed the test makefiles' flat C-object cache:
switching from default to forced HUF mode could relink stale default C objects
with a newly built forced Rust archive. That hybrid has incompatible decoder
table expectations and can corrupt dictionary decompression.

Track each makefile's effective HUF mode with an empty archive stamp. It is a
safe normal linker prerequisite, and every mode transition advances its mtime
so cached C objects and direct-source binaries rebuild while unchanged modes
remain incremental.

Test Plan:
- cargo clippy; cargo clippy --benches; cargo clippy --tests
- cargo +nightly fmt, then repeat the Clippy checks
- cargo test --all-targets
- Default -> forced-X1 -> default fuzzer builds without -B, each running
  ./fuzzer -s5346 -i1 --no-big-tests
- Equivalent zstd-small default/forced/default rebuild and --version checks

Refs: rust/README.md
Fixes: d89ebb31
This commit is contained in:
2026-07-10 21:08:14 +02:00
parent 27932113fd
commit 65afd94867
3 changed files with 49 additions and 3 deletions
+23
View File
@@ -91,6 +91,25 @@ $(RUST_STATICLIB): $(RUST_SOURCES)
$(RUST_STATICLIB_32): $(RUST_SOURCES)
$(CARGO) build $(RUST_CARGO_FLAGS) --target $(RUST_TARGET_32)
# These test objects have flat filenames, unlike the configuration-hashed
# program objects. Track the HUF mode separately so a C object set compiled
# for one decoder is never relinked with a Rust archive for another decoder.
# The stamp is an empty archive, so normal linker `$^` recipes can consume it.
RUST_HUF_C_MODE_FILE := $(RUST_DIR)/target/.huf-c-mode-tests
RUST_HUF_C_MODE_STAMP := $(RUST_DIR)/target/.huf-c-mode-tests.a
.PHONY: FORCE_RUST_HUF_C_MODE
FORCE_RUST_HUF_C_MODE:
$(RUST_HUF_C_MODE_STAMP): FORCE_RUST_HUF_C_MODE
@mkdir -p $(@D)
@if test ! -r $(RUST_HUF_C_MODE_FILE) \
|| test "$$(cat $(RUST_HUF_C_MODE_FILE))" != "$(RUST_BUILD_CONFIG)" \
|| test ! -f $@; then \
printf '%s\n' "$(RUST_BUILD_CONFIG)" > $(RUST_HUF_C_MODE_FILE); \
$(AR) rcs $@; \
touch $@; \
fi
CLEAN += $(RUST_HUF_C_MODE_FILE) $(RUST_HUF_C_MODE_STAMP)
DEBUGFLAGS += -g -Wno-c++-compat
CPPFLAGS += -I$(LIB_SRCDIR) -I$(LIB_SRCDIR)/common -I$(LIB_SRCDIR)/compress -I$(LIB_SRCDIR)/legacy \
-I$(LIB_SRCDIR)/dictBuilder -I$(LIB_SRCDIR)/deprecated -I$(PRGDIR) \
@@ -118,6 +137,8 @@ ZSTDMT_OBJ4 := $(subst $(LIB_SRCDIR)/legacy/,zstdmt_l_,$(ZSTDMT_OBJ3))
ZSTDMT_OBJ5 := $(ZSTDMT_OBJ4:.c=.o)
ZSTDMT_OBJECTS := $(ZSTDMT_OBJ5:.S=.o)
$(ZSTD_OBJECTS) $(ZSTDMT_OBJECTS): $(RUST_HUF_C_MODE_STAMP)
# Define *.exe as extension for Windows systems
ifneq (,$(filter Windows%,$(OS)))
EXT =.exe
@@ -311,6 +332,8 @@ $(RUST_LINK_TARGETS): $(RUST_STATICLIB)
RUST_LINK_TARGETS_32 := fullbench32 fuzzer32 zstreamtest32
$(RUST_LINK_TARGETS_32): $(RUST_STATICLIB_32)
$(RUST_LINK_TARGETS) $(RUST_LINK_TARGETS_32): $(RUST_HUF_C_MODE_STAMP)
.PHONY: versionsTest
versionsTest: clean
$(PYTHON) test-zstd-versions.py