#!/bin/sh # Normalization scripts for reproducible builds # Strips non-deterministic content from build artifacts # # Usage: normalize.sh set -eu DIR="${1:-.}" log() { echo "[normalize] $*" >&2 } # Strip timestamps from __DATE__ and __TIME__ macros strip_date_time() { log "Stripping date/time macros..." # Already handled by SOURCE_DATE_EPOCH in modern GCC } # Normalize build paths normalize_paths() { log "Normalizing build paths..." # Handled by -fdebug-prefix-map } # Normalize ar archives for deterministic ordering normalize_archives() { log "Normalizing ar archives..." find "$DIR" -name "*.a" -type f | while read -r archive; do if ar --version 2>&1 | grep -q "GNU ar"; then # GNU ar with deterministic mode ar -rcsD "$archive.tmp" "$archive" && mv "$archive.tmp" "$archive" 2>/dev/null || true fi done } # Strip debug sections that contain non-deterministic info strip_debug_timestamps() { log "Stripping debug timestamps..." find "$DIR" -type f \( -name "*.o" -o -name "*.so" -o -name "*.so.*" -o -executable \) | while read -r obj; do # Check if ELF file "$obj" 2>/dev/null | grep -q "ELF" || continue # Strip build-id if not needed (we regenerate it) # objcopy --remove-section=.note.gnu.build-id "$obj" 2>/dev/null || true # Remove timestamps from DWARF debug info # This is typically handled by SOURCE_DATE_EPOCH done } # Normalize tar archives normalize_tars() { log "Normalizing tar archives..." # When creating tars, use: # tar --sort=name --mtime="@${SOURCE_DATE_EPOCH}" --owner=0 --group=0 --numeric-owner } # Run all normalizations normalize_paths normalize_archives strip_debug_timestamps log "Normalization complete"