# Build Linux Binary

> Build XerahS Linux binaries (x64 or ARM64) with the packaging script. Use only for Linux packaging, artifact checks, or packaging-specific Avalonia diagnostics.

- Skill: `sharex/build-linux-binary` (Agent Skill)
- Install (CLI): `npx skillmds@latest add sharex/build-linux-binary`
- Raw SKILL.md: https://api.skillmd.com/api/skills/sharex/build-linux-binary/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: sharex (https://skillmd.com/u/sharex)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/sharex/build-linux-binary

---


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.

<task>
  <goal>Build Linux packages (deb/rpm) for both x64 and ARM64 architectures.</goal>
  <goal>Handle file locking issues that occur when a previous build is still running.</goal>
  <goal>Avoid Avalonia XAML precompilation failures caused by namespace mismatches in converters.</goal>
  <goal>Validate that the build artifacts exist and are recent.</goal>
</task>

<context>
  <build_script_path>build/linux/package-linux.sh</build_script_path>
  <dist_output_path>dist/</dist_output_path>
  <expected_outputs>
    - 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)
  </expected_outputs>
</context>

## Shared Build Guardrails

Before Linux packaging work, follow [build-common](../build-common/SKILL.md) for shared timeout, lock recovery, no-concurrent-build, `-m:1`, TFM, and SkiaSharp rules. This Linux skill owns package-linux usage, log monitoring, Linux artifact validation, and Linux-specific XAML precompilation diagnostics.

## Build Process

### Preparation

Build the pinned submodule revision. Update ImageEditor only when requested, using the operator's Git wrapper. For confirmed stalls or output locks, use [build-common](../build-common/SKILL.md); do not terminate unrelated builds.

### Phase 2: Run the Build Script

Use the packaging script below. If the host buffers output, capture a log and inspect it while the build runs. Redirection alone does not background a shell command.

```bash
bash build/linux/package-linux.sh > build_output.log 2>&1
```

Verify the exit code and resulting artifacts. Judge stalls from output and process activity, not a fixed timeout.

### 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**: identify the lock holder and use [build-common](../build-common/SKILL.md) to cancel only the affected task-owned build, then rerun the packaging script.

---

#### 🔴 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**: Ensure this checkout's previous build has exited before starting another build sharing its outputs.

### 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
- Cancel a confirmed stalled task-owned build before retrying; leave other checkouts' processes alone.

### stdout Buffering Issue
- If the host buffers output, redirect to a log and inspect progress through the host's file or terminal tools.

---

## 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` | Identify the task-owned lock holder; recover through build-common and 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; verify the current centrally managed SkiaSharp/native-assets set and published runtimes before changing versions |

---

## Related Files
- Shared guardrails: [build-common](../build-common/SKILL.md)
- 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)

