Skip to content

build: track header dependencies in the Autoconf build#36

Open
gburd wants to merge 1 commit into
masterfrom
build/header-deps
Open

build: track header dependencies in the Autoconf build#36
gburd wants to merge 1 commit into
masterfrom
build/header-deps

Conversation

@gburd

@gburd gburd commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

What

Adds automatic header-dependency tracking to the build_unix Autoconf build,
gated on compiler support (-MMD -MP -MT), so editing a shared header rebuilds
every dependent object.

Why

The Makefile listed only .c (and a few .incl) prerequisites per object —
no headers. Editing a shared header (e.g. src/dbinc/lock.h) and running an
incremental make silently left dependent objects compiled against the old
struct layout. A struct-field addition then mismatched across translation units
(one .o writes a field at the old offset, another reads it at the new one) —
silent shared-memory corruption, which surfaced as spurious invalid lock mode
errors during recent SSI work. This is the header-under-tracking hazard already
called out in CONTRIBUTING.md; this PR fixes it instead of just warning.

How

  • configure.ac probes whether $CC accepts -MMD -MP -MT. If so it sets
    DEPFLAGS='-MMD -MP -MT $@' and DEP_INCLUDE to pull in per-object .d
    fragments; otherwise both are empty and behaviour is unchanged (no
    GNU-make-isms leak into the portable build).
  • Makefile.in threads $(DEPFLAGS) into every compile recipe, includes the
    .d fragments via @DEP_INCLUDE@, and adds *.d to clean.
  • Compile recipes switch $?$<: once -MMD adds header prerequisites,
    $? (all newer prereqs) would try to compile a header; $< always names the
    .c and is correct in both modes.

Testing

  • Clean configure + full build on Linux x86_64 (clang) via the Nix dev shell.
  • Validated the fix: touch src/dbinc/lock.h then incremental make now
    rebuilds lock_region.o (compiling the correct source; timestamp advances).
  • Validated the empty-DEPFLAGS fallback still builds correctly.
  • configure regenerated with a surgical ~50-line diff (no autoconf-version
    churn). The large Makefile.in diff is the mechanical $?$< recipe change.

The build_unix Makefile listed only .c (and a few .incl) prerequisites per
object -- no headers -- so editing a shared header (e.g. src/dbinc/lock.h) and
running an incremental `make` silently left dependent objects compiled against
the old layout. A struct-field addition then mismatched across translation
units (one .o writes a field at the old offset, another reads it at the new
one): silent shared-memory corruption, observed as spurious "invalid lock
mode" errors.

Add the standard autoconf/GCC auto-dependency pattern, gated on compiler
support so the portable build is unchanged where it can't be done:

- configure.ac probes whether $CC accepts -MMD -MP -MT; if so it sets
  DEPFLAGS='-MMD -MP -MT $@' and DEP_INCLUDE to pull in the per-object .d
  fragments, else both are empty (today's behaviour).
- Makefile.in threads $(DEPFLAGS) into every compile recipe, includes the
  .d fragments (@DEP_INCLUDE@), and cleans *.d.
- Compile recipes switch from $? (all newer prerequisites) to $< (the source):
  once -MMD adds header prerequisites, $? would try to compile a header. $<
  always names the .c and is correct with or without dependency tracking.

Verified: touching src/dbinc/lock.h now rebuilds lock_region.o (compiling the
right source), and the empty-DEPFLAGS fallback still builds correctly. The
CONTRIBUTING note is updated accordingly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant