PublishAotCompressed.macOS 1.0.1-preview

This is a prerelease version of PublishAotCompressed.macOS.
dotnet add package PublishAotCompressed.macOS --version 1.0.1-preview
                    
NuGet\Install-Package PublishAotCompressed.macOS -Version 1.0.1-preview
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="PublishAotCompressed.macOS" Version="1.0.1-preview" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PublishAotCompressed.macOS" Version="1.0.1-preview" />
                    
Directory.Packages.props
<PackageReference Include="PublishAotCompressed.macOS" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add PublishAotCompressed.macOS --version 1.0.1-preview
                    
#r "nuget: PublishAotCompressed.macOS, 1.0.1-preview"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package PublishAotCompressed.macOS@1.0.1-preview
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=PublishAotCompressed.macOS&version=1.0.1-preview&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=PublishAotCompressed.macOS&version=1.0.1-preview&prerelease
                    
Install as a Cake Tool

PublishAotCompressed.macOS

License: MIT NuGet

MSBuild targets to automatically compress Native AOT binaries with UPX on macOS. Designed to work seamlessly with cross-compilation from macOS to Windows and Linux.

English | 简体中文

🚀 Features

  • Automatic UPX compression after Native AOT compilation
  • Cross-compilation support - compress binaries for Windows and Linux from macOS
  • macOS-only - streamlined for macOS development workflow
  • 60%+ size reduction - typical compression rates
  • Optional LZMA for even better compression
  • Smart detection - automatically skips compression for macOS targets

📋 Table of Contents

Quick Start

Prerequisites

  • macOS (Apple Silicon or Intel)
  • .NET 9.0 SDK or later
  • UPX installed via Homebrew:
    brew install upx
    

For Windows Cross-compilation

This package works perfectly with PublishAotCross.macOS for cross-compiling to Windows.

  1. Install cross-compilation tools:

    # Install LLVM for lld-link
    brew install lld
    
    # Add to PATH (or add to ~/.zshrc for permanent)
    export PATH="$(brew --prefix lld)/bin:$PATH"
    
    # Install xwin for Windows SDK
    cargo install --locked xwin
    
    # Download Windows SDK (~1.5GB)
    mkdir -p $HOME/.local/share/xwin-sdk
    xwin --accept-license \
      --cache-dir $HOME/.local/share/xwin-sdk \
      --arch x86_64,aarch64 \
      splat --preserve-ms-arch-notation
    
  2. Add packages to your project:

    <ItemGroup>
      <PackageReference Include="PublishAotCross.macOS" Version="1.0.3-preview" />
      <PackageReference Include="PublishAotCompressed.macOS" Version="1.0.0-preview" />
    </ItemGroup>
    
  3. Publish with compression:

    # Ensure lld-link is in PATH
    export PATH="$(brew --prefix lld)/bin:$PATH"
    
    # Build for Windows (automatically compressed with UPX)
    dotnet publish -r win-x64 -c Release
    dotnet publish -r win-arm64 -c Release
    dotnet publish -r win-x86 -c Release
    

📖 Detailed Windows setup guide: See PublishAotCross.macOS QUICKSTART.md

For Linux Cross-compilation

  1. Install Zig (via Homebrew):

    brew install zig
    
  2. Add packages to your project (same as above):

    <ItemGroup>
      <PackageReference Include="PublishAotCross.macOS" Version="1.0.3-preview" />
      <PackageReference Include="PublishAotCompressed.macOS" Version="1.0.0-preview" />
    </ItemGroup>
    
  3. Publish with compression:

    # glibc-based (Ubuntu, Debian, etc.)
    dotnet publish -r linux-x64 -c Release /p:StripSymbols=false
    dotnet publish -r linux-arm64 -c Release /p:StripSymbols=false
    
    # musl-based (Alpine Linux)
    dotnet publish -r linux-musl-x64 -c Release /p:StripSymbols=false
    dotnet publish -r linux-musl-arm64 -c Release /p:StripSymbols=false
    

📖 Detailed Linux setup guide: See PublishAotCross.macOS QUICKSTART-LINUX.md

For macOS (native)

Good news: macOS targets are built-in! Just publish normally:

dotnet publish -r osx-arm64 -c Release
dotnet publish -r osx-x64 -c Release

Note: macOS targets automatically skip UPX compression. The package will display a message and produce uncompressed binaries that run normally. This is by design since UPX-compressed macOS binaries cannot run due to macOS security restrictions (System Integrity Protection, code signing, Gatekeeper).

Configuration

Compression Settings

You can use either the full property name or the short alias:

<PropertyGroup>
  
  <Upx>true</Upx>
  
  
  <PublishAotCompressed>true</PublishAotCompressed>
  
  
  <CompressBest>true</CompressBest>
  
  
  <PublishLzmaCompressed>true</PublishLzmaCompressed>
</PropertyGroup>

Command Line Usage

# Enable compression (short form) ✅ Recommended
dotnet publish -r win-x64 -c Release /p:Upx=true

# Disable compression (short form) ✅ Recommended  
dotnet publish -r win-x64 -c Release /p:Upx=false

# Or use the full property name
dotnet publish -r win-x64 -c Release /p:PublishAotCompressed=false

Example Project Configuration

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <PublishAot>true</PublishAot>
    
    
    <UseSystemResourceKeys>true</UseSystemResourceKeys>
    <InvariantGlobalization>true</InvariantGlobalization>
  </PropertyGroup>
  
  <ItemGroup>
    
    <PackageReference Include="PublishAotCross.macOS" Version="1.0.3-preview" />
    <PackageReference Include="PublishAotCompressed.macOS" Version="1.0.0-preview" />
  </ItemGroup>
</Project>

Supported Targets

Target UPX Support Cross-compilation Tool
win-x64 ✅ Compresses PublishAotCross.macOS
win-arm64 ✅ Compresses PublishAotCross.macOS
win-x86 ✅ Compresses PublishAotCross.macOS

Linux (via Zig)

Target UPX Support Cross-compilation Tool
linux-x64 ✅ Compresses PublishAotCross.macOS
linux-arm64 ✅ Compresses PublishAotCross.macOS
linux-musl-x64 ✅ Compresses PublishAotCross.macOS
linux-musl-arm64 ✅ Compresses PublishAotCross.macOS

macOS (native)

Target UPX Support Notes
osx-arm64 ⏭️ Skipped Auto-skipped due to macOS security
osx-x64 ⏭️ Skipped Auto-skipped due to macOS security

How It Works

This package hooks into the Native AOT build process and automatically compresses the compiled binary:

Build Flow:

.NET AOT Compiler (macOS) → Native Binary → UPX Compression → Compressed Executable
                             (.exe/.elf)      (macOS tool)      (for target OS)

Technical Details:

  1. MSBuild Target: Runs AfterTargets="LinkNative" to compress the binary immediately after linking
  2. Platform Detection: Identifies target OS from RuntimeIdentifier (win-/linux-/osx-*)
  3. Smart Compression:
    • For Windows/Linux targets: runs UPX with --best flag
    • For macOS targets: skips compression and displays a message
  4. Host Tool: Always uses macOS ARM64 UPX binary included in the package

UPX Compression:

  • Algorithm: LZBA (default) or LZMA (optional)
  • Level: --best (level 9) by default
  • Decompression: Automatic at program launch, in-memory, typically unnoticeable

Compression Results

For a Hello World program with size optimizations enabled:

Target Uncompressed With --best UPX Compression Ratio Savings
Windows x64 1.05 MB 483 KB 44.9% 55.1%
Windows ARM64 1.01 MB 455 KB 45.0% 55.0%
Linux x64 1.30 MB 520 KB 40.0% 60.0%
Linux ARM64 1.25 MB 500 KB 40.0% 60.0%
macOS ARM64 1.20 MB N/A (skipped) - -

💡 Tip: Add <PublishLzmaCompressed>true</PublishLzmaCompressed> for even better compression (typically 5-10% smaller, but adds ~50-100ms to startup time).

Deploying to Target Platforms

Linux Deployment

.NET Native AOT binaries require the ICU library on the target system:

# Ubuntu/Debian
sudo apt-get install -y libicu-dev

# CentOS/RHEL/Fedora
sudo yum install -y icu

# Alpine Linux
apk add --no-cache icu-libs

Docker Example:

FROM ubuntu:22.04
RUN apt-get update && apt-get install -y libicu-dev
COPY YourApp /app/
CMD ["/app/YourApp"]

Disable ICU (Optional):

<PropertyGroup>
  <InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>

Windows Deployment

UPX-compressed Windows executables:

  • ✅ Run on any Windows 10/11 system
  • ✅ No additional runtime required (.NET Native AOT)
  • ⚠️ May trigger false positives in some antivirus software (add to whitelist if needed)

If Windows shows "compressed file" dialog:

  • This is a file association issue with WinRAR/7-Zip
  • Solution: Right-click → Properties → Unblock (if shown)
  • The .exe is directly executable, not a compressed archive

Troubleshooting

upx: command not found

Install UPX via Homebrew:

brew install upx

Cross-compilation fails

Make sure you've installed the cross-compilation tools:

UPX compression fails

Check that the package is properly installed:

# Verify UPX is available
upx --version

# Check package installation
dotnet list package | grep PublishAotCompressed.macOS

"PublishAotCompressed.macOS can only be used on macOS"

This package only works on macOS. For other platforms:

Complete .NET Native AOT Cross-Compilation Ecosystem

Project Purpose Platforms
PublishAotCross.macOS Cross-compile from macOS macOS → Windows/Linux
PublishAotCompressed.macOS (this) UPX compression on macOS Compresses Windows/Linux binaries
PublishAotCross Cross-compile from Windows Windows → Linux
PublishAotCrossXWin Cross-compile from Linux Linux → Windows
PublishAotCompressed Original UPX package Multi-platform

Cross-Compilation + Compression Matrix

Build Host Target Cross-compilation UPX Compression
macOS Windows ✅ PublishAotCross.macOS ✅ This package
macOS Linux ✅ PublishAotCross.macOS ✅ This package
macOS macOS Native ⏭️ Skipped (security)
Windows Linux ✅ PublishAotCross ✅ PublishAotCompressed
Linux Windows ✅ PublishAotCrossXWin ✅ PublishAotCompressed

💡 macOS users get the best of both worlds - cross-compile to both Windows and Linux with automatic UPX compression from a single machine!

Requirements

Build Host

  • macOS (Apple Silicon or Intel)
  • .NET 9.0 SDK or later
  • Homebrew (for installing tools)

For Windows Cross-compilation

  • LLVM (lld-link linker) - via brew install lld
  • Rust/Cargo (for installing xwin) - via brew install rust
  • xwin - via cargo install xwin
  • ~1.5GB disk space for Windows SDK

For Linux Cross-compilation

  • Zig (~200MB, includes everything) - via brew install zig

Example Project

See the test/ directory in this repository for a complete example.

License

MIT License - see LICENSE.TXT for details.

Credits

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Support


Made with ❤️ for the .NET Native AOT community on macOS

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

  • .NETStandard 2.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1-preview 291 11/5/2025
1.0.0-preview 290 11/5/2025