chore(build): reduce binary size by ~8 MB#362
Conversation
Signed-off-by: Boris Bliznioukov <blib@mail.com>
There was a problem hiding this comment.
Pull request overview
This PR reduces binary size by approximately 8 MB through two build optimization techniques: stripping debug symbols with -s -w linker flags and using stdlib JSON instead of the heavier go-json dependency via the stdjson build tag. This is particularly valuable for the PicoClaw project's embedded/IoT target where binary size is more critical than marginal JSON performance gains.
Changes:
- Added
-s -wflags to LDFLAGS to strip symbol table and DWARF debug information - Added
-tags stdjsonto GOFLAGS to make the telego Telegram library useencoding/jsoninstead ofgithub.com/grbit/go-json
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Signed-off-by: Boris Bliznioukov <blib@mail.com>
Signed-off-by: Boris Bliznioukov <blib@mail.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Leeaandrob
left a comment
There was a problem hiding this comment.
PR #362 Deep Review — @blib
Clean, well-documented build optimization. The ~8 MB reduction claim is confirmed locally: 25 MB → 17 MB (32% reduction).
Verification
- Checked out branch locally:
feat-bin-size make build— succeeds, binary is 17 MB (vs 25 MB without PR)file build/picoclaw-linux-amd64— confirmsstripped(symbols removed)./picoclaw version— version info correctly embedded (v0.1.2-9-g2d876ea, git: 2d876eaa, Build: ..., Go: go1.25.7)go test ./... -tags stdjson— all tests passing across 14 packages- Verified goreleaser config:
tags: [stdjson]+ldflags: [-s -w, ...]+ version vars - Verified release workflow:
id: setup-go→GOVERSIONenv var → goreleaser template
Binary Size Breakdown
| Build | Size | Delta |
|---|---|---|
| Without PR (upstream Makefile) | 25 MB | — |
With PR (-s -w + stdjson) |
17 MB | -8 MB (32%) |
Summary of Findings
MEDIUM (Suggestion, not blocking)
- M1:
build-alltarget (Makefile:85-89) uses$(LDFLAGS)but NOT$(GOFLAGS)— cross-compiled binaries frommake build-allwill miss thestdjsontag (pre-existing issue, but now more impactful)
POSITIVE
- 32% binary size reduction confirmed — 25 MB → 17 MB
- Version info now in goreleaser builds —
{{ .Version }},{{ .ShortCommit }},{{ .Date }},{{ .Env.GOVERSION }}were missing before this PR. This is a bonus improvement. stdjsonis the official telego build tag — not a hack, properly supported by the library- All tests pass with the
stdjsontag — no functional regression -s -wis standard practice for Go release builds (Go linker docs, Docker best practices)- Excellent PR description with references to Go linker docs and telego source
Verdict: APPROVE
Focused, low-risk build optimization with measurable impact. Ready to merge.
| BUILD_TIME=$(shell date +%FT%T%z) | ||
| GO_VERSION=$(shell $(GO) version | awk '{print $$3}') | ||
| LDFLAGS=-ldflags "-X main.version=$(VERSION) -X main.gitCommit=$(GIT_COMMIT) -X main.buildTime=$(BUILD_TIME) -X main.goVersion=$(GO_VERSION)" | ||
| LDFLAGS=-ldflags "-X main.version=$(VERSION) -X main.gitCommit=$(GIT_COMMIT) -X main.buildTime=$(BUILD_TIME) -X main.goVersion=$(GO_VERSION) -s -w" |
There was a problem hiding this comment.
[Positive] @blib — Clean addition of -s -w to LDFLAGS. The flags are placed after the -X version vars, which is correct (order does not matter for ldflags, but this reads naturally). Confirmed locally: file output shows stripped and picoclaw version still correctly reports version/commit/build info.
| # Go variables | ||
| GO?=go | ||
| GOFLAGS?=-v | ||
| GOFLAGS?=-v -tags stdjson |
There was a problem hiding this comment.
[M1 — MEDIUM: build-all misses GOFLAGS] @blib — The build target (line 77) uses both $(GOFLAGS) and $(LDFLAGS), but build-all (lines 85-89) only uses $(LDFLAGS):
# build (line 77) - correct:
$(GO) build $(GOFLAGS) $(LDFLAGS) -o $(BINARY_PATH) ./$(CMD_DIR)
# build-all (line 85) - missing GOFLAGS:
GOOS=linux GOARCH=amd64 $(GO) build $(LDFLAGS) -o ... ./$(CMD_DIR)This means make build-all cross-compiled binaries will NOT use stdjson, will include go-json, and will be ~1 MB larger per platform. This is a pre-existing inconsistency, but now that GOFLAGS carries the stdjson tag, it matters more.
Not blocking since goreleaser (used for actual releases) is correctly configured.
| - -X main.version={{ .Version }} | ||
| - -X main.gitCommit={{ .ShortCommit }} | ||
| - -X main.buildTime={{ .Date }} | ||
| - -X main.goVersion={{ .Env.GOVERSION }} |
There was a problem hiding this comment.
[Positive — Bonus: Version Info in Release Builds] @blib — The goreleaser config previously had NO ldflags at all, meaning release binaries had empty version info (picoclaw version would show blank or default values). This PR adds both the size optimization AND the version embedding. Nice catch — this was a separate bug that got fixed as a side effect.
|
@blib take look |
1 similar comment
|
@blib take look |
|
Great! |
📝 Description
Reduce binary size by ~8 MB through two changes:
-s -wtoLDFLAGS(-sstrips symbol table,-wstrips DWARF debug info)-tags stdjsontoGOFLAGSso thattelegousesencoding/jsoninstead of thegithub.com/grbit/go-jsondependency🗣️ Type of Change
🤖 AI Code Generation
🔗 Linked Issue
#346
📚 Technical Context (Skip for Docs)
-s -wflags documentation; telego stdjson build taggo-jsonadds ~1 MB to the binary and is only used bytelegofor marginal JSON performance gains. For an embedded/IoT target like PicoClaw, binary size matters more than JSON serialization speed. Stripping debug symbols is standard practice for release builds.