Skip to content

Enable AOT binaries and end-to-end publishing of binaries#110

Merged
tig merged 11 commits intodevelopfrom
feature/makefile-releases
May 7, 2026
Merged

Enable AOT binaries and end-to-end publishing of binaries#110
tig merged 11 commits intodevelopfrom
feature/makefile-releases

Conversation

@tig
Copy link
Copy Markdown
Member

@tig tig commented May 7, 2026

Closes #109.

Summary

This is NOT about publishing to winget or brew; just about verifying that the binaries build and run correctly on supported platforms.

  • New Makefile at the repo root for local restore/build/test/AOT-publish loops. RID auto-detected from uname; override with make publish RID=linux-x64. publish-all covers osx-arm64, linux-x64, win-x64.
  • New release job in .github/workflows/release.yml between tag and publish-nuget. Downloads the build matrix artifacts, packages .tar.gz (osx/linux) and .zip (win) under dist/, creates a GitHub Release v<version> via gh release create --generate-notes. Versions containing - (alpha/develop) get --prerelease. Re-runs upload assets with --clobber.
  • notify-failure.needs now includes release so packaging failures still file the incident issue.
  • make doctor (and scripts/doctor.{sh,ps1}) — checks the .NET SDK and the platform-native linker that AOT publishing needs. Prints precise remediation per missing item.
  • CONTRIBUTING.md Prerequisites section: per-platform install matrix for build/test, AOT, and make (Windows separately — VS C++ workload does not include GNU make).
  • .gitattributes forces LF on Makefile and *.sh so a Windows checkout doesn't silently corrupt them.
  • .gitignore covers .vs/, publish/, publish-nonaot/, dist/, **/Properties/launchSettings.json.
  • D-034 added: explicit <PackageReference Include="TextMateSharp"> workaround, since publish was dropping the runtime DLL.

Acceptance bar (per @tig)

This PR is not done until both AOT and non-AOT x64 binaries run on the maintainer's Windows box, and the branch can be pulled and runs cleanly on:

Platform Non-AOT AOT Notes
win-x64 (this machine) ✅ verified — --version, list, help --cat all work ✅ verified against TG 2.1.0-rc.2 (21.17 MB binary, exit 0) upstream AOT chain resolved by TG#5249
win-arm64 ✅ verified by @tig ✅ verified by @tig (after IsPublishable=false fix at 0cd826c — bare dotnet publish was failing NETSDK1151 because test projects ProjectReference self-contained Clet)
osx-arm64 ✅ verified by @tig ✅ verified by @tig ---
linux-x64 (WSL) ⏳ needs maintainer to pull ⏳ needs maintainer to pull TG fix is in 2.1.0-rc.2; please re-pull
linux-arm64 (WSL) ⏳ needs maintainer to pull ⏳ needs maintainer to pull TG fix is in 2.1.0-rc.2; please re-pull

Verification recipe per platform

git fetch origin feature/makefile-releases && git checkout feature/makefile-releases
make doctor                          # one-time: confirm toolchain
make build && make test              # green?
make publish                         # produces publish/<rid>/clet[.exe]
./publish/<rid>/clet --version
./publish/<rid>/clet list
./publish/<rid>/clet help --cat

If make publish fails on Windows with vswhere.exe is not recognized, prepend the VS Installer dir to PATH or run from a Developer Command Prompt — see CONTRIBUTING.md → Common Windows AOT failure.

Doc-update gate

  • D-034 added (TextMateSharp workaround).
  • No spec or runbook impact otherwise (CLI surface, exit codes, JSON schema, alias names unchanged). The release-rollback runbook still applies — adding a published GitHub Release is additive to the existing tag/NuGet flow.

Linked upstream issues

  • AOT chain (resolved): TG#5239 → #5240 (partial) → #5242 (residual) → #5243 (the right fix) → #5248 (filed when rc.1 still crashed) → #5249 (root cause: a horked merge resolution between rc.1 and main dropped #5243's hunk; restoring it shipped in TG 2.1.0-rc.2). clet now pins to that tag.
  • TG#5249 restores the two source files (DeepCloner.cs + ConfigurationManager.cs); an AOT regression test in TG CI was suggested in #5249's body but is not in the merge — worth a separate TG follow-up to prevent another silent re-introduction.

🤖 Generated with Claude Code

tig and others added 8 commits May 7, 2026 11:03
Closes #109.

- Makefile at repo root wraps local restore/build/test/publish loops.
  RID is auto-detected from uname; override with `make publish RID=...`.
  publish-all targets osx-arm64, linux-x64, win-x64.
- New release job in release.yml downloads the build matrix artifacts,
  packages tar.gz (osx/linux) and zip (win) under dist/, and creates a
  GitHub Release tagged v<version> with --generate-notes. Versions
  containing '-' (alpha/develop) are flagged --prerelease. Re-runs
  upload assets with --clobber rather than failing on an existing
  release.
- notify-failure now waits on `release` so a packaging failure files
  the standard incident issue.
- CLAUDE.md gains the smoke-test command and a Makefile reference table.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A Windows checkout failed `make publish` with the cryptic MSB3073 /
"vswhere.exe is not recognized" error. The fix isn't to guess — it's
that AOT compilation requires a platform-native linker that the .NET
SDK does not bundle. Codify this so the next maintainer doesn't have
to rediscover it.

- scripts/doctor.sh: per-platform check of .NET SDK plus the native
  toolchain (Xcode CLT on macOS, clang+zlib on Linux, vswhere +
  VC.Tools.x86.x64 on Windows). Prints a remediation step per
  missing item; exits non-zero if anything is missing.
- Makefile: new `make doctor` target that runs the script. `make help`
  points users at it when publish fails.
- CONTRIBUTING.md: new "Prerequisites" section with a per-platform
  install matrix (apt, dnf, xcode-select, VS Build Tools).
- CLAUDE.md: notes the AOT toolchain requirement and points at
  CONTRIBUTING and `make doctor`.
- .gitattributes: forces LF on Makefile and *.sh so a Windows checkout
  doesn't silently corrupt them via autocrlf.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Windows users running PowerShell don't have `make` and may not have
bash on PATH, so the bash-only doctor was effectively unreachable from
the default Windows shell. Mirror it in PowerShell and document both
entrypoints.

- scripts/doctor.ps1: same checks as doctor.sh — .NET SDK, vswhere,
  VC.Tools.x86.x64 — using native PowerShell + vswhere.
- CONTRIBUTING.md: spells out three ways to run the check (`make
  doctor`, `bash scripts/doctor.sh`, `pwsh -File scripts/doctor.ps1`)
  so no one has to guess based on platform.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous Prerequisites section implied installing the VS C++
workload was sufficient on Windows. It fixes AOT publishing (MSVC
linker), but does not install GNU make — VS ships MSBuild and nmake,
neither of which understands our Makefile.

Split the Windows row's concerns: AOT prereq is one column, `make`
itself is its own column. Document the three common ways to get GNU
make on Windows (choco, winget, scoop) and call out WSL/Git Bash as
alternatives. Make is optional — every target maps to a plain dotnet
command — so this is positioning, not adding a hard dependency.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previous doctor queried vswhere with -requires VC.Tools.x86.x64. That
component ID matches Build Tools / Community / Enterprise but missed
VS 18 Insiders even when link.exe was present at exactly the path
the AOT MSBuild target uses. False negative, exactly the kind of
"setup must be wrong" guessing this script was supposed to prevent.

Now both doctor scripts check for the linker directly:
- if link.exe is on PATH → ok (Developer Command Prompt)
- else `vswhere -find VC\Tools\MSVC\**\Hostx64\x64\link.exe` (with
  -prerelease so Insiders/preview installs are discovered)
- else miss

Verified locally: doctor now correctly identifies the linker in a
VS 18 Insiders install at .../14.51.36231/.../link.exe and reports ok.

Also document a separate Windows AOT failure mode in CONTRIBUTING:
even with the linker installed, the AOT target shells out via cmd.exe
where vswhere.exe is not on PATH, producing the same MSB3073. Fix:
launch from a Developer Command Prompt, or prepend the VS Installer
dir to PATH for the session.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
These were showing as untracked on every clean checkout:
- .vs/ — Visual Studio's IDE cache
- publish/ — local AOT output from `make publish`
- dist/ — release archive output (also produced locally if anyone
  exercises the release packaging steps)
- **/Properties/launchSettings.json — VS auto-generates this with
  local debug profiles; not shared

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Used as the non-AOT side-by-side output dir when working around the
upstream Terminal.Gui AOT trimming bug.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`dotnet publish` (AOT or non-AOT) was dropping TextMateSharp.dll from
the output directory while keeping TextMateSharp.Grammars.dll. At
runtime any markdown render via the syntax highlighter threw
FileNotFoundException — `clet help select --cat` reproduced it
reliably. This blocked PR #110's bar of having a published binary
that actually runs.

Add a direct PackageReference (pin matches what Grammars already
brings in transitively, so no new version surface) and document as
D-034. Verified locally on win-x64 non-AOT: --version, list, and
help --cat all work end-to-end.

AOT publish on win-x64 still crashes at module init due to upstream
TG bug gui-cs/Terminal.Gui#5239 (separate issue, not blocked on this
workaround).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@tig tig marked this pull request as draft May 7, 2026 18:17
@tig tig changed the title Add Makefile and GitHub Releases job (#109) Enable AOT binaries and end-to-end publishing of binaries May 7, 2026
tig and others added 3 commits May 7, 2026 16:35
`src/Clet.SourceGen/` was kept around as a parking spot for a future
auto-discovery source generator. v2 third-party-clets isn't on the
roadmap anymore, so the project is dead weight that has to be carried
through every solution-wide build, restore, and pack step.

- src/Clet.SourceGen/ removed (csproj + Placeholder.cs).
- Clet.slnx no longer references it.
- specs/clet-spec.md project-layout trees updated; the prose lines
  that called the source generator out as a separate project /
  placeholder are gone. §11 still describes the v2 hypothetical
  auto-discovery design (that's an exploration section, not a
  current-code claim, so left intact).
- CLAUDE.md project list updated to drop the SourceGen bullet.

Build, unit, integration, and smoke tests all green after removal.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The AOT crash chain (#5239 → #5240 partial → #5242 residual → #5243
horked-merge → TG#5249 restoring the fix) is fully resolved in TG
2.1.0-rc.2. Verified locally on win-x64:

  dotnet publish src/Clet -c Release -r win-x64 --self-contained
                          -p:PublishAot=true -o publish/win-x64
  ./publish/win-x64/clet.exe --version
  → 1.0.0-alpha (Terminal.Gui 2.1.0-rc.2), exit 0
  → 21.17 MB binary

Move clet's TerminalGuiVersion default off the `2.0.2-develop.*`
float and onto a stable RC tag, satisfying spec §7's v0.5 milestone
"TG dep on a release tag, not develop".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A solution-wide `dotnet publish` (no project arg) walks every project.
The test projects ProjectReference Clet, which becomes self-contained
under AOT publish — and a non-self-contained project cannot reference
a self-contained one. The build fails with NETSDK1151:

  error NETSDK1151: The referenced project '../../src/Clet/Clet.csproj'
  is a self-contained executable. A self-contained executable cannot
  be referenced by a non self-contained executable.

Surfaced on win-arm64 by @tig running bare `dotnet publish` against
the freshly pinned 2.1.0-rc.2.

Add tests/Directory.Build.props with `<IsPublishable>false</IsPublishable>`,
which propagates to all four test csprojs (UnitTests, IntegrationTests,
SmokeTests, UITests). Bare `dotnet publish` now skips them and only
publishes Clet itself. Tests still build and run normally.

Verified locally: `dotnet publish -c Release` succeeds (only Clet
publishes); `dotnet build -c Release` 0 errors; `dotnet run --project
tests/Clet.UnitTests --no-build -c Release` 431/431 pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@tig tig marked this pull request as ready for review May 7, 2026 23:32
@tig tig merged commit 863e135 into develop May 7, 2026
5 checks passed
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.

Add Makefile for local builds and GitHub Releases to workflow

1 participant