Skip to content

aot: enable ahead-of-time (AOT) compilation#2366

Open
mjcheetham wants to merge 10 commits into
git-ecosystem:vnextfrom
mjcheetham:aot
Open

aot: enable ahead-of-time (AOT) compilation#2366
mjcheetham wants to merge 10 commits into
git-ecosystem:vnextfrom
mjcheetham:aot

Conversation

@mjcheetham

Copy link
Copy Markdown
Contributor

Summary

Make Git Credential Manager build as a Native AOT application, and turn AOT on by default at publish. Getting there means removing the reflection-based APIs AOT can't use — chiefly JSON serialisation — and moving onto an Avalonia version that supports the compiled, trim-safe patterns AOT requires.

Why

AOT gives a self-contained native binary with no managed startup cost and no runtime dependency, which is a better shape for a credential helper that Git launches on every operation. The blockers are reflection-driven code paths; this branch converts the big one (JSON) to source generation and updates the UI stack so the whole product is AOT/trim-safe.

What changes

  • Upgrade Avalonia to 12.0.5. Reacts to 12.x breaking changes: explicit x:DataType for the now-default compiled bindings across all views, reworked clipboard and hotkey access, and renamed window-chrome / placeholder-text properties.
  • Enable JSON source generation product-wide. Define explicit JSON contexts per area (with their serialisation options) so System.Text.Json generates serialisers instead of using reflection.
  • Enable JSON source generation for Trace2. Switch to the built-in lower-snake-case naming policy and set enum string values via attributes.
  • Turn on PublishAot by default, so a published build is a native AOT binary.
  • Drop the explicit AOT flags from the macOS/Linux layout scripts now that the project sets it.

Notes

  • AOT linking needs a native toolchain (clang, zlib). That's fine for the shipped package; a from-source --no-aot path is added in the build-system rework that follows.

Requires PR #2365 to be completed first.

Drop the .NET Framework target (net472) from all projects and build
scripts. Windows builds will now target the, only, TFM of `net10.0`.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Remove all code that was conditional on a .NET Framework target. Now
that we're only building against the CoreCLR, this code was dead.

Note that we now lose the ability to use the embedded web view for
Microsoft authentication, which was a .NET Framework-only feature (and
therefore Windows only). Support for embedded web view flows will be
restored at a later date via Avalonia WebView.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Add the SupportedOSPlatform attributes to types that only run on the
relevant specific OS platform. This will help ensure we're always gating
use of OS-specific behaviour to that specific OS.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Suppress the "This call site is reachable on all platforms" warning
for all test projects - we use custom Xunit attributes to dynamically
skip OS-specific tests unless the test is running on the appropriate OS.
The analyzer for CA1416 does not know how to handle this.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Upgrade all Avalonia packages to the latest version, which is 12.0.5 at
time of writing.

Version 12.x has some breaking changes that we must react to, including
a required and explicit `x:DataType` specified for the now default
compiled bindings in all views. There have also been changes to how the
clipboard is accessed, as well as hotkeys. Finally some properties have
been renamed and reworked, specifically on the customising window
chrome/decorations and control placeholder text.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
In order to support ahead-of-time (AOT) compilation we must avoid using
reflection-based APIs. JSON serialisation is one of those APIs that we
use a lot across the product.

System.Text.Json supports source generation-based serialisation. We opt
into this by creating explict 'JSON contexts' for each area that define
the set of types we should generate serialisers for, including custom
serialisation options (case sensitivity, naming conventions, etc).

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Enable JSON source generation for Trace2 messages. This will further
help unlock AOT compilation options which cannot use reflection-based
APIs.

Replace the custom JSON naming policy with the built-in lower snake case
policy, and for good measure also explictly set the enum string values
as attributes on the members themselves.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Enable AOT compilation on publish for Git Credential Manager by default!

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
@mjcheetham mjcheetham added engineering Refactoring or build changes gcm3.0 Targets the next major release of Git Credential Manager - v3.0 labels Jun 29, 2026
Comment on lines -21 to -22
<Border BorderBrush="{DynamicResource DialogWindowBorderBrush}"
BorderThickness="{Binding ShowCustomWindowBorder, Converter={x:Static converters:BoolConvertersEx.ToThickness}}">

@mjcheetham mjcheetham Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The diff looks large, but we just dropped the wrapping <Border> element, and the rest moved 'one tab less' and made some minor renames. Diff ignoring whitespace for an easier time.

Enabling Native AOT makes the Linux CI jobs link a native binary for
the target runtime. Cross-linking the Arm runtimes from the x64
ubuntu-latest runner has no target toolchain, so the linux-arm job
fails at the clang link step.

Run the Arm matrix entries on GitHub's Arm64 runners so linux-arm64
links natively, and install the armhf GNU toolchain
(gcc-arm-linux-gnueabihf, which pulls in binutils and the sysroot) for
the 32-bit linux-arm target, which still cross-compiles on the Arm64
host.

Assisted-by: Claude Opus 4.8
Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Native AOT links the published binary with clang. Leaving it on for a
source install would force every distro to install a C toolchain just
to build a local copy, which is why the install-from-source validation
fails across the board with "gcc or clang is missing".

Installing from source does not need a native binary, so turn AOT off
for it alone: set PublishAot=false in the environment for the build
(the executable project honours an externally supplied value, and the
nested publish inherits it through the packaging scripts). With AOT
off, layout.sh's existing self-contained, single-file publish produces
a portable binary that needs only the .NET SDK to build and bundles its
own runtime to run - so it launches even on the distros where the SDK
was installed to a non-standard location. The shipped packages set
nothing and still default to AOT.

This is a deliberate stopgap that leaves the rest of the
install-from-source flow as-is; a later commit reworks
install-from-source handling altogether.

Assisted-by: Claude Opus 4.8
Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
@mjcheetham mjcheetham marked this pull request as ready for review June 29, 2026 16:43
@mjcheetham mjcheetham requested review from a team as code owners June 29, 2026 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

engineering Refactoring or build changes gcm3.0 Targets the next major release of Git Credential Manager - v3.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant