Skip to content

gnumake: drop zig bootstrap, build with cc_binary#717

Merged
oharboe merged 3 commits into
mainfrom
gnumake
May 10, 2026
Merged

gnumake: drop zig bootstrap, build with cc_binary#717
oharboe merged 3 commits into
mainfrom
gnumake

Conversation

@oharboe
Copy link
Copy Markdown
Collaborator

@oharboe oharboe commented May 7, 2026

PR #699 made @gnumake hermetic by downloading the full Zig toolchain (~80 MB, hzeller measured >10 min) and bootstrapping make with zig cc -static -target x86_64-linux-musl. hzeller's review:

ahem, this downloads a huge zig compiler (gmake is written in C, not
zig) (it takes > 10 minutes to download). Why not just compile gmake
with the regular c compiler? With that, you get the hermeticity
guarantees. Whipping out a BUILD file shoud be simple. Then upstreaming
it to BZR will also make it useful for others.

He's right that the project already registers a hermetic clang (@llvm_toolchain from toolchains_llvm, used to build OpenROAD/yosys), so zig is redundant for fetching a C compiler. Convert @gnumake to a thin repo rule that downloads the gmake source and overlays a checked-in cc_binary BUILD file plus a vendored config.h.

Hermeticity for the make binary itself comes from:

  • Bazel sandbox -> execroot-relative paths in FILE (no host paths leak into the binary).
  • linkopts = ["-Wl,--build-id=none", "-Wl,-s"] strip the random ELF build-id and symbols/debug info.
  • Same hermetic clang the rest of the project uses.

Verified two clean output_bases on this host produce identical sha256 c678430fbbd1cff14b8b22e67080187fa49c762fbc7d45b8481a71e5d34770a9 (290 KB, stripped, dynamically linked). make --version reports GNU Make 4.4.1. A trivial Makefile recipe runs end-to-end.

What this does not attempt: vendoring a sysroot to make the binary byte-identical across host glibc versions. cc_binary outputs are currently tied to host glibc symbol versions -- the same caveat that already applies to cc_binary-built yosys/openroad in this project. Project-wide cross-distro hermeticity is a separate, larger effort.

Linux x86_64 only -- the registered LLVM tarball
(LLVM-20.1.8-Linux-X64.tar.xz) doesn't support other hosts today, so the previous gnumake.bzl support for macOS/aarch64 was already dead.

config.h is the autoconf output of ./configure --without-guile --disable-nls against gmake 4.4.1, captured once and committed verbatim. HAVE_DECL_BSD_SIGNAL is patched to 0 because bsd_signal was removed from glibc 2.27+; the original config.h captured under musl had it set to 1.

PR #699 made @gnumake hermetic by downloading the full Zig toolchain
(~80 MB, hzeller measured >10 min) and bootstrapping make with
zig cc -static -target x86_64-linux-musl. hzeller's review:

  ahem, this downloads a huge zig compiler (gmake is written in C, not
  zig) (it takes > 10 minutes to download). Why not just compile gmake
  with the regular c compiler? With that, you get the hermeticity
  guarantees. Whipping out a BUILD file shoud be simple. Then upstreaming
  it to BZR will also make it useful for others.

He's right that the project already registers a hermetic clang
(@llvm_toolchain from toolchains_llvm, used to build OpenROAD/yosys), so
zig is redundant for fetching a C compiler. Convert @gnumake to a thin
repo rule that downloads the gmake source and overlays a checked-in
cc_binary BUILD file plus a vendored config.h.

Hermeticity for the make binary itself comes from:
  - Bazel sandbox -> execroot-relative paths in __FILE__ (no host paths
    leak into the binary).
  - linkopts = ["-Wl,--build-id=none", "-Wl,-s"] strip the random ELF
    build-id and symbols/debug info.
  - Same hermetic clang the rest of the project uses.

Verified two clean output_bases on this host produce identical sha256
c678430fbbd1cff14b8b22e67080187fa49c762fbc7d45b8481a71e5d34770a9 (290 KB,
stripped, dynamically linked). `make --version` reports GNU Make 4.4.1.
A trivial Makefile recipe runs end-to-end.

What this does not attempt: vendoring a sysroot to make the binary
byte-identical across host glibc versions. cc_binary outputs are
currently tied to host glibc symbol versions -- the same caveat that
already applies to cc_binary-built yosys/openroad in this project.
Project-wide cross-distro hermeticity is a separate, larger effort.

Linux x86_64 only -- the registered LLVM tarball
(LLVM-20.1.8-Linux-X64.tar.xz) doesn't support other hosts today, so
the previous gnumake.bzl support for macOS/aarch64 was already dead.

config.h is the autoconf output of `./configure --without-guile
--disable-nls` against gmake 4.4.1, captured once and committed verbatim.
HAVE_DECL_BSD_SIGNAL is patched to 0 because bsd_signal was removed
from glibc 2.27+; the original config.h captured under musl had it set
to 1.

Signed-off-by: Øyvind Harboe <[email protected]>
@oharboe
Copy link
Copy Markdown
Collaborator Author

oharboe commented May 7, 2026

@hzeller This is what Claude did...

Comment thread tools/gnumake/BUILD.gnumake Outdated
# gmake's remake.c / read.c reference these as install-prefix paths
# (.LIBPATTERNS, dlopen search). Match autotools' default --prefix
# so behavior is identical to a stock distro build.
'-DLIBDIR=\\"/usr/local/lib\\"',
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thes paths don't really make sense. What happens if you set them empty or not at all ?

Comment thread gnumake.bzl Outdated
"""

_MAKE_VERSION = "4.4.1"
_MAKE_SHA256 = "dd16fb1d67bfab79a72f5e8390735c49e3e8e70b4945a15ab1f81ddb78658fb3"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is this hash used to verify the download ?

oharboe added 2 commits May 8, 2026 07:44
Two inline review comments:

* gnumake.bzl:21 -- "where is this hash used to verify the download?"
  Inline _MAKE_SHA256 directly into the download_and_extract call so the
  hash sits next to the URL list and the verification is visible at a
  glance.

* tools/gnumake/BUILD.gnumake:53 -- "thes paths don't really make sense.
  What happens if you set them empty or not at all?" The bazel-built make
  is never `make install`-ed, so /usr/local/{lib,share/locale,include} is
  fiction. Set the three install-prefix -D values to empty strings so we
  don't lie about where files live. Build, --version, and a trivial
  Makefile recipe still work.

The make binary's sha256 changes (different preprocessor input -> different
object code), but determinism on a fixed host is preserved.

Signed-off-by: Øyvind Harboe <[email protected]>
On macOS (and any host where the registered LLVM toolchain isn't
applicable) the bazel-built @gnumake//:make won't compile. Document the
stock Bazel mechanism for swapping it out: --override_repository against
a tiny per-host overlay (BUILD.bazel + sh_binary wrapper + empty
REPO.bazel marker). No bazel-orfs helper, no new repo rule -- pure Bazel
idiom that any user can replicate in their own project.

Two pitfalls the docstring calls out, both verified locally:

  * The override key must be the canonical repo name
    `+orfs_repositories+gnumake`, not the apparent name `gnumake`.
    Bazel silently ignores the apparent-name form for repos created by
    a module extension.
  * The override directory needs an empty REPO.bazel marker; without
    it Bazel errors with "No MODULE.bazel, REPO.bazel, or WORKSPACE
    file found".

Verified end-to-end: `bazelisk run --override_repository=... @gnumake//:make
-- --version` invokes the host's /usr/bin/make and prints its version.

Docs only -- no change to the build path. Default behavior on Linux
x86_64 is unchanged.

Signed-off-by: Øyvind Harboe <[email protected]>
@oharboe
Copy link
Copy Markdown
Collaborator Author

oharboe commented May 8, 2026

Pushed two follow-up commits:

  • 65454e8 — addresses both inline review comments (inlined the sha256 hash; LIBDIR/LOCALEDIR/INCLUDEDIR
    -D values now empty strings rather than fictional /usr/local paths).
  • 61f4d64 — docs only, adds an --override_repository recipe for users who want to swap
    @gnumake//:make for a host gmake (e.g. on macOS). No bazel-orfs helper, just stock Bazel.

Verified end-to-end here: bazelisk test //... is 47/47 green both with the default and with the
override active against /usr/bin/make.

@oharboe
Copy link
Copy Markdown
Collaborator Author

oharboe commented May 8, 2026

@hzeller OK now?

@oharboe
Copy link
Copy Markdown
Collaborator Author

oharboe commented May 10, 2026

@hzeller Ok?

@hzeller
Copy link
Copy Markdown

hzeller commented May 10, 2026

the extension stuff still looks a bit complicated, but maybe that is what needed with bazel 8 ? Anyway, I think this is a good start; from there we should get it on bzr, then we don't need any *.bzl files.

@oharboe oharboe merged commit 05bbceb into main May 10, 2026
1 check passed
oharboe added a commit that referenced this pull request May 10, 2026
Two inline review comments:

* gnumake.bzl:21 -- "where is this hash used to verify the download?"
  Inline _MAKE_SHA256 directly into the download_and_extract call so the
  hash sits next to the URL list and the verification is visible at a
  glance.

* tools/gnumake/BUILD.gnumake:53 -- "thes paths don't really make sense.
  What happens if you set them empty or not at all?" The bazel-built make
  is never `make install`-ed, so /usr/local/{lib,share/locale,include} is
  fiction. Set the three install-prefix -D values to empty strings so we
  don't lie about where files live. Build, --version, and a trivial
  Makefile recipe still work.

The make binary's sha256 changes (different preprocessor input -> different
object code), but determinism on a fixed host is preserved.

Signed-off-by: Øyvind Harboe <[email protected]>
@oharboe oharboe deleted the gnumake branch May 10, 2026 15:10
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.

2 participants