From f3d8cbe281d116a53b0f77f2fa14be0a0c80f870 Mon Sep 17 00:00:00 2001 From: Michael Wesemann Date: Sun, 26 Jul 2026 19:53:29 +0200 Subject: [PATCH] Cross-compile into ./bin for the usual platforms build.sh produced one binary for the machine it ran on. It now builds darwin/arm64, darwin/amd64, linux/amd64 and linux/arm64 into ./bin, all from the single version that run bumped, so the four never disagree about what they are. PLATFORMS="linux/amd64" ./build.sh narrows it. bin/mgsh is a symlink to the host's build, so there is still one stable path to "the binary for this machine". The old ./mgsh in the repo root is no longer written, and the script deletes it once if it finds it -- a stale binary on a path people have in their fingers is worse than a missing one. CGO_ENABLED=0 throughout: the cross builds then need no toolchain per target and the binaries are static. That is only safe because os/user still resolves the current user without cgo, which mgsh needs for the "[user@host]" stamp on every commit -- checked on darwin before relying on it. Windows is left out on purpose: mgsh shells out to stty and /bin/sh, so it would compile there and then not work. Co-Authored-By: Claude Opus 5 --- .gitignore | 1 + README.md | 34 ++++++++++++++++++++++++++++------ build.sh | 45 +++++++++++++++++++++++++++++++++++++++++---- version.txt | 2 +- 4 files changed, 71 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index b97f152..feb3125 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ .TemporaryItems .Trashes mgsh +bin/ .mgshrc diff --git a/README.md b/README.md index 73ce2d6..070b562 100644 --- a/README.md +++ b/README.md @@ -17,14 +17,36 @@ directory. Go port of the original Perl `mgsh` (`mgsh.perl`). ## Build ```sh -./build.sh # builds ./mgsh and bumps the patch version by 0.0.1 -go build -o mgsh . # plain build, keeps the default version +./build.sh # all platforms into ./bin, bumps the patch version +PLATFORMS="linux/amd64" ./build.sh # just one +go build -o mgsh . # plain build, keeps the default version ``` -`build.sh` reads `version.txt`, increments the patch component, injects it via -`-ldflags -X main.VERSION`, and writes it back — so `version.txt` always holds -the version of the binary just built. Dependencies are fetched via Go modules -(`go.mod` / `go.sum`) on first build. +`build.sh` cross-compiles for `darwin/arm64`, `darwin/amd64`, `linux/amd64` and +`linux/arm64` into `./bin`: + +``` +bin/mgsh -> mgsh-darwin-arm64 (this machine) +bin/mgsh-darwin-amd64 +bin/mgsh-darwin-arm64 +bin/mgsh-linux-amd64 +bin/mgsh-linux-arm64 +``` + +`bin/mgsh` is a symlink to the build for the host, so there is one stable path +to "the binary for this machine". `bin/` is git-ignored. Windows is deliberately +absent: mgsh shells out to `stty` and `/bin/sh`, so it would compile there and +then not work. + +Everything is built with `CGO_ENABLED=0`, which makes the cross builds need no +toolchain per target and the binaries static; `os/user` resolves the current +user without cgo on both darwin and linux. + +It reads `version.txt`, increments the patch component, injects it via +`-ldflags -X main.VERSION` into **all** platforms of that run, and writes it +back — so `version.txt` always holds the version of the binaries just built, and +they all carry the same one. Dependencies are fetched via Go modules (`go.mod` / +`go.sum`) on first build. Run the tests with `go test ./...`. diff --git a/build.sh b/build.sh index 419832b..d9088ed 100755 --- a/build.sh +++ b/build.sh @@ -1,12 +1,22 @@ #!/bin/sh -# Build mgsh, auto-incrementing the patch version by 0.0.1 on every build. +# Build mgsh for the usual platforms into ./bin, auto-incrementing the patch +# version by 0.0.1 on every build. # # version.txt holds the currently built version. Each run increments the patch -# component, then builds with that version injected via -ldflags, and writes it -# back. So version.txt always reflects the version of the binary just built. +# component, then builds every platform with that one version injected via +# -ldflags, and writes it back. So version.txt always reflects the version of +# the binaries just built, and all of them carry the same one. +# +# Override the platform list to build just one: +# PLATFORMS="linux/amd64" ./build.sh +# +# Windows is deliberately absent: mgsh shells out to stty and /bin/sh, so it +# would compile there and then not work. set -e cd "$(dirname "$0")" +PLATFORMS=${PLATFORMS:-"darwin/arm64 darwin/amd64 linux/amd64 linux/arm64"} + V=$(cat version.txt 2>/dev/null || echo 4.0.0) # split MAJOR.MINOR.PATCH and increment PATCH (no carry: 4.0.9 -> 4.0.10) @@ -17,7 +27,34 @@ PATCH=${REST#*.} PATCH=$((PATCH + 1)) NV="$MAJOR.$MINOR.$PATCH" -go build -ldflags "-X main.VERSION=$NV" -o mgsh . +# earlier versions built ./mgsh in the repo root; drop it so nothing keeps +# running a stale binary from a path that is no longer written +if [ -f mgsh ]; then + rm -f mgsh + echo "removed stale ./mgsh (the build now writes ./bin)" +fi + +mkdir -p bin +HOST="$(go env GOOS)/$(go env GOARCH)" + +for p in $PLATFORMS; do + os=${p%/*} + arch=${p#*/} + out="bin/mgsh-$os-$arch" + + # CGO_ENABLED=0 throughout: it makes the cross builds work without a + # toolchain per target and the binaries static, and os/user still resolves + # the current user without cgo on both darwin and linux. + CGO_ENABLED=0 GOOS="$os" GOARCH="$arch" \ + go build -ldflags "-X main.VERSION=$NV" -o "$out" . + + if [ "$p" = "$HOST" ]; then + ln -sf "mgsh-$os-$arch" bin/mgsh # the one for this machine + echo " $out -> bin/mgsh" + else + echo " $out" + fi +done echo "$NV" > version.txt echo "built mgsh v$NV" diff --git a/version.txt b/version.txt index 93896ac..98c52f5 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -4.0.50 +4.0.53