--- name: build-linux-binary description: Builds Linux binaries (x64 and ARM64) for XerahS using the packaging script. Handles common file locking, stale process, and Avalonia XAML precompilation issues specific to Linux builds. Ensures deb/rpm packages are created in dist/. metadata: keywords: - build - linux - binary - deb - rpm - release - publish - packaging - file-lock - compilation - arm64 - x64 - avalonia - xaml --- You are an expert Linux build automation specialist for .NET/Avalonia projects. Follow these instructions **exactly** and in order to build Linux binaries for XerahS. Build Linux packages (deb/rpm) for both x64 and ARM64 architectures. Handle file locking issues that occur when a previous build is still running. Avoid Avalonia XAML precompilation failures caused by namespace mismatches in converters. Validate that the build artifacts exist and are recent. build/linux/package-linux.sh dist/ - XerahS-{version}-linux-x64.deb - XerahS-{version}-linux-arm64.deb - XerahS-{version}-linux-x64.rpm (if rpmbuild is available) - XerahS-{version}-linux-arm64.rpm (if rpmbuild is available) ## Build Process ### Phase 0: Update ShareX.ImageEditor Submodule **Always pull the latest `ShareX.ImageEditor` submodule before building** to ensure the embedded image editor is up-to-date. ```bash git submodule update --remote --merge ShareX.ImageEditor ``` ### Phase 1: Pre-Build Cleanup **CRITICAL**: Stale `dotnet` and `package-linux.sh` processes are the #1 cause of file lock failures on Linux. **Always kill them before starting.** 1. **Kill all stale build processes**: ```bash pkill -f "package-linux.sh" 2>/dev/null pkill -f "dotnet publish" 2>/dev/null pkill -f "dotnet build" 2>/dev/null sleep 2 ``` 2. **Optional — clean obj folders if locks persist**: ```bash rm -rf /path/to/XerahS/ShareX.ImageEditor/src/ShareX.ImageEditor/obj/Release ``` This is most useful if you see `The process cannot access the file '...ShareX.ImageEditor.pdb' because it is being used by another process` (Avalonia AVLN9999 error). --- ### Phase 2: Run the Build Script **IMPORTANT: Always redirect output to a log file.** The build takes 5-15 minutes and `command_status` produces **no output** during that time — the tool will appear to hang. Do NOT use `WaitDurationSeconds > 30` with this command. **Start the build with log redirection:** ```bash bash build/linux/package-linux.sh > build_output.log 2>&1 ``` This runs in the background. Monitor progress by periodically reading the log with `view_file`: ``` view_file: /path/to/XerahS/build_output.log (last 50 lines) ``` **Repeat every ~30 seconds** until you see one of: - `Done! All packages in dist/` → ✅ Build succeeded - `Error:` or `FAILED` lines → ❌ See Phase 3 for fixes **Do NOT** use `WaitDurationSeconds=120` in `command_status` — the command produces buffered output only after completion, so polling the log file is the only reliable way to track progress. --- ### Phase 3: Handle Common Failures #### 🔴 Failure: `No precompiled XAML found for XerahS.UI.App` **Symptom** (at runtime, not build time): ``` Avalonia.Markup.Xaml.XamlLoadException: No precompiled XAML found for XerahS.UI.App, make sure to specify x:Class and include your XAML file as AvaloniaResource ``` **Root Cause**: A C# converter class referenced in an `.axaml` file uses the **wrong namespace**. Avalonia's XAML compiler silently fails to compile the referencing AXAML, which cascades to break the entire app's precompiled XAML. **How to diagnose**: - Check any recently added/modified converters under `ShareX.ImageEditor/src/ShareX.ImageEditor/UI/Adapters/Converters/` - Verify their C# `namespace` matches the AXAML `xmlns:converters` import: In `EditorView.axaml`: ```xml xmlns:converters="using:ShareX.ImageEditor.Converters" ``` So all converter classes **must** declare: ```csharp namespace ShareX.ImageEditor.Converters; ``` **Fix**: ```csharp // WRONG — will silently break Avalonia XAML precompilation: namespace ShareX.ImageEditor.UI.Adapters.Converters; // CORRECT — matches the xmlns:converters import in EditorView.axaml: namespace ShareX.ImageEditor.Converters; ``` After fixing, rebuild from scratch. --- #### 🔴 Failure: `AVLN9999: The process cannot access the file '...XerahS.Imgur.Plugin.pdb' because it is being used by another process` **Root Cause**: A previous `dotnet publish` is still running in the background (e.g. from a backgrounded `&` command). **Fix**: ```bash pkill -f "dotnet publish" pkill -f "package-linux.sh" sleep 3 bash build/linux/package-linux.sh ``` --- #### 🔴 Failure: `MSB3026: Could not copy '...XerahS.Uploaders.dll' ... being used by another process` **Root Cause**: Parallel plugin publishing is racing to write shared DLLs. **Fix**: This is usually a transient retry (MSBuild will retry automatically). If it becomes fatal: ```bash rm -rf src/desktop/core/XerahS.Uploaders/obj/Release bash build/linux/package-linux.sh ``` --- #### 🔴 Failure: `Error: No plugins were published for linux-x64` **Root Cause**: The plugin csproj discovery glob found no files, or a plugin build failed early. **Check**: ```bash find src/desktop/plugins -mindepth 2 -maxdepth 2 -name "*.csproj" ``` Each plugin project under `src/desktop/plugins/` needs a `plugin.json` in the same directory. --- ### Phase 4: Validation After the build completes, verify the artifacts: ```bash ls -lh dist/ ``` **Expected output**: ``` XerahS-0.16.1-linux-x64.deb ~90-120MB XerahS-0.16.1-linux-arm64.deb ~90-120MB XerahS-0.16.1-linux-x64.rpm ~90-120MB (if rpmbuild installed) XerahS-0.16.1-linux-arm64.rpm ~90-120MB (if rpmbuild installed) ``` Timestamps should match the current build session. --- ## Important Notes ### Why Avalonia XAML Precompilation Fails Silently - Avalonia compiles `.axaml` files to IL at build time - If a referenced type (e.g. a converter) cannot be resolved, the AXAML file is silently skipped - This doesn't fail the **build**, but crashes the **application at startup** - The fix is always: ensure C# `namespace` matches the `xmlns` import in the AXAML ### Key Build Parameters (from `package-linux.sh`) - `-p:PublishSingleFile=true --self-contained true`: Main app ships as one binary - `-p:OS=Linux -p:DefineConstants=LINUX`: Enables Linux-specific code paths - `-p:EnableWindowsTargeting=true`: Required when cross-compiling on Linux due to shared project references - Plugins publish with `--no-self-contained` to share the runtime with the main app ### Sequential Builds Are Mandatory **NEVER run two builds at the same time.** `ShareX.ImageEditor` targets multiple TFMs and MSBuild parallelism causes them to race on the same `ShareX.ImageEditor.dll` output path. - **Architectures**: `package-linux.sh` iterates `linux-x64` then `linux-arm64` sequentially — never invoke it twice concurrently. - **Internal parallelism**: If `CS2012` / file lock errors appear on `ShareX.ImageEditor`, pre-build it separately with `/m:1` to force single-threaded compilation: ```bash dotnet build ShareX.ImageEditor/src/ShareX.ImageEditor/ShareX.ImageEditor.csproj \ -c Release -p:UseSharedCompilation=false /m:1 ``` - **Between builds**: Always kill all `dotnet` and `package-linux.sh` processes and wait for them to exit before starting a new build session. ### Background Build Caution - **Do not background the build script with `&`** unless you redirect output to a log file - Multiple concurrent builds share `obj/` folders and will conflict - Always kill previous builds before starting a new one ### stdout Buffering Issue - `dotnet publish` progress may not appear in `command_status` tool output until the command finishes - Redirect to a `.log` file and use `view_file` to check progress instead of waiting for command output --- ## Success Criteria - ✅ Both `linux-x64` and `linux-arm64` `.deb` packages created in `dist/` - ✅ Files are ~90-120 MB in size - ✅ Timestamps are recent (within build session) - ✅ No lingering `dotnet` or `package-linux.sh` processes - ✅ App launches without `XamlLoadException` at startup --- ## Troubleshooting | Symptom | Solution | |---------|----------| | `XamlLoadException: No precompiled XAML found` at startup | Check namespaces of all new converter classes — must match `xmlns:converters` in `.axaml` | | `AVLN9999: file used by another process` | Kill all `dotnet publish` and `package-linux.sh` processes, retry | | `MSB3026: Could not copy XerahS.Uploaders.dll` | Usually transient; if fatal, delete `src/desktop/core/XerahS.Uploaders/obj/Release` and retry | | `Error: No plugins were published` | Check `src/desktop/plugins/` structure and `plugin.json` presence in each plugin directory | | ARM64 cross-compile fails | Ensure `linux-arm64` .NET SDK cross-compile support is installed; Fedora needs `dotnet-sdk-10.0` | | `rpmbuild: command not found` | RPM skipped (not fatal); install with `sudo dnf install rpm-build` if needed | | Build succeeds but app segfaults | SkiaSharp native library issue; **never bump SkiaSharp beyond 2.88.9** | --- ## Related Files - Build script: [build/linux/package-linux.sh](../../../build/linux/package-linux.sh) - Packaging tool: [build/linux/XerahS.Packaging/](../../../build/linux/XerahS.Packaging/) - Version config: [Directory.Build.props](../../../Directory.Build.props) - Main app project: [src/desktop/app/XerahS.App/XerahS.App.csproj](../../../src/desktop/app/XerahS.App/XerahS.App.csproj) - Converters namespace reference: `ShareX.ImageEditor.Converters` (match all new converter classes to this)