# How to Configure the CI/CD Build Pipeline for Cross-Platform Releases in FinceptTerminal

> Automate cross-platform releases for FinceptTerminal with GitHub Actions. Learn to configure your CI/CD build pipeline for Windows, Linux, and macOS native installers and auto-updates.

- Repository: [Fincept Corporation/FinceptTerminal](https://github.com/Fincept-Corporation/FinceptTerminal)
- Tags: how-to-guide
- Published: 2026-04-20

---

**FinceptTerminal automates cross-platform releases using GitHub Actions, combining matrix builds in [`.github/workflows/build-cpp.yml`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/.github/workflows/build-cpp.yml) with release orchestration in [`.github/workflows/release.yml`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/.github/workflows/release.yml) to generate native installers for Windows, Linux, and macOS alongside an auto-updater manifest.**

The **CI/CD build pipeline for cross-platform releases** in the FinceptTerminal repository (Fincept-Corporation/FinceptTerminal) handles everything from compiling Qt/C++ source code to publishing signed GitHub Releases. This guide explains the workflow architecture, customization points, and file locations you need to modify when extending the build system.

## Pipeline Architecture Overview

The pipeline consists of three coordinated components that trigger on tag pushes (`v*`) or manual dispatch:

1. **Matrix Build ([`build-cpp.yml`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/build-cpp.yml))** – Compiles native binaries for Windows x64/ARM64, Linux x64, and macOS ARM64/Intel, then packages platform-specific installers.
2. **macOS Universal Job** – Merges ARM64 and Intel binaries using `lipo` to create a universal macOS application bundle.
3. **Release Job ([`release.yml`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/release.yml))** – Aggregates artifacts, creates a GitHub Release, updates the README download table, and regenerates [`updates.json`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/updates.json) for the in-app auto-updater.

All workflows are located in `.github/workflows/` and use environment variables to control Qt versions, build flags, and target architectures.

## Workflow File Structure

### The Matrix Build Workflow ([`build-cpp.yml`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/build-cpp.yml))

The [`.github/workflows/build-cpp.yml`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/.github/workflows/build-cpp.yml) file defines the build matrix and handles compilation for every supported platform. It uses `actions/checkout@v4` with `submodules: recursive` to pull the Qt/C++ source, then installs dependencies via platform-specific package managers.

Key matrix entries in the workflow include:

- **Windows x64**: `os: windows-2022`, `arch: x64`, `qt_arch: win64_msvc2022_64`
- **Windows ARM64**: Cross-compilation with dual Qt toolchains (host x64 for `moc`/`uic`, target ARM64 for compilation)
- **Linux x64**: `os: ubuntu-22.04` with Ninja build system and OpenSSL development libraries
- **macOS ARM64**: `os: macos-14` targeting Apple Silicon
- **macOS Intel**: `os: macos-13` for x86_64 architecture

Each job runs `cmake -B build -DFINCEPT_BUILD_INSTALLER=ON` to configure the build directory, followed by `cmake --build build --config Release --parallel` to compile the project.

### The Release Orchestration Workflow ([`release.yml`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/release.yml))

The [`.github/workflows/release.yml`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/.github/workflows/release.yml) file orchestrates the release process. It downloads artifacts from the matrix build, executes the macOS universal binary creation step, and publishes the final release using `softprops/action-gh-release@v2`. This workflow also executes Python scripts to regenerate [`updates.json`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/updates.json) and modifies [`README.md`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/README.md) to reflect the latest download URLs.

## Platform-Specific Build Configuration

### Windows x64 and ARM64 Builds

Windows builds rely on **vcpkg** to install static OpenSSL libraries required by QtNetwork. The workflow runs `vcpkg install openssl:x64-windows` before invoking CMake.

Packaging uses `windeployqt` to collect Qt dependencies, then manually copies OpenSSL DLLs, MSVC runtime libraries, and application resources into a `dist/` directory. For Windows ARM64 cross-compilation, the workflow installs a second Qt host toolchain (x64) to run `moc` and `uic` on the build host while targeting ARM64 for the final binary.

### Linux x64 AppImage Generation

Linux builds produce an **AppImage** using `linuxdeploy-x86_64.AppImage` with the Qt plugin. The workflow installs system dependencies via `apt-get install -y cmake ninja-build g++ libssl-dev`, then invokes the CMake configuration with Ninja generator.

After building, the packaging step stages the binary and resources, runs the LinuxDeploy tool to create the AppImage, and generates a `.zsync` file for delta updates. The resulting artifact uploads as `FinceptTerminal-Linux-x64.AppImage`.

### macOS Universal Binary Creation

macOS requires special handling to produce a universal binary that runs on both Apple Silicon and Intel Macs. After the matrix builds complete, a dedicated `macos-universal` job downloads both the ARM64 and Intel artifacts.

The job extracts both tarballs, then uses `lipo -create` to merge architecture-specific binaries into universal executables. For example:

```bash
lipo -create \
  "${Intel_PATH}/FinceptTerminal.app/Contents/MacOS/FinceptTerminal" \
  "${ARM64_PATH}/FinceptTerminal.app/Contents/MacOS/FinceptTerminal" \
  -output "${UNIVERSAL_PATH}/FinceptTerminal.app/Contents/MacOS/FinceptTerminal"

```

After merging, the workflow re-adds shared resources and performs ad-hoc signing with `codesign --force --deep --sign -` before uploading the universal tarball.

## Customizing Build Parameters

### Modifying Qt Versions and Modules

All workflows reference a `QT_VERSION` environment variable (default: `6.8.3`) and `QT_MODULES` (default: `qtcharts qtwebsockets qtmultimedia`). To change the Qt version across all builds, edit these variables in both [`.github/workflows/build-cpp.yml`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/.github/workflows/build-cpp.yml) and [`.github/workflows/release.yml`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/.github/workflows/release.yml):

```yaml
env:
  QT_VERSION: "6.8.3"
  QT_MODULES: "qtcharts qtwebsockets qtmultimedia"

```

To add additional modules like `qtpositioning`, append them to the `QT_MODULES` list. The `jurplel/install-qt-action@v4` action automatically downloads specified modules during the setup phase.

### Adding New Target Architectures

To add a new platform such as Linux ARM64 (`aarch64`), extend the matrix in [`.github/workflows/build-cpp.yml`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/.github/workflows/build-cpp.yml):

```yaml
matrix:
  include:
    - os: ubuntu-22.04
      arch: aarch64
      platform: Linux
      artifact: FinceptTerminal-Linux-aarch64
      exe: FinceptTerminal
      qt_arch: ""
      cmake_extra: "-DCMAKE_TOOLCHAIN_FILE=toolchains/aarch64-linux-gnu.cmake"

```

You must provide a CMake toolchain file (`toolchains/aarch64-linux-gnu.cmake`) and ensure the runner has access to an ARM64 cross-compiler or use a containerized build environment.

### Enabling or Disabling Installer Generation

The CMake flag `FINCEPT_BUILD_INSTALLER` controls whether the build generates distributable installers or just raw binaries. Set this to `OFF` for quick CI checks that skip packaging:

```bash
cmake -B build -DFINCEPT_BUILD_INSTALLER=OFF

```

In the workflow file, this appears as:

```yaml
- name: Configure CMake
  run: cmake -B build -DFINCEPT_BUILD_INSTALLER=ON ${{ matrix.cmake_extra }}

```

## Automated Release Management

### GitHub Release Creation

The release job triggers only on tag pushes matching `v*`. It uses `actions/download-artifact@v4` to collect all platform artifacts, normalizes filenames (converting directories to zip/tar archives), and creates a GitHub Release with the `softprops/action-gh-release@v2` action.

The release automatically includes changelog generation and marks the release as latest.

### README Download Table Updates

Upon successful release creation, the workflow uses the `gh` CLI to query release assets and rewrite the download table in [`README.md`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/README.md). The CI searches for markers `<!-- DOWNLOAD-TABLE-START -->` and `<!-- DOWNLOAD-TABLE-END -->`, replacing the content between them with a markdown table containing current download URLs for Windows, Linux, and macOS installers.

### Auto-Updater Manifest Generation

The pipeline regenerates [`updates.json`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/updates.json) by downloading release assets, computing SHA-256 hashes, and mapping platform keys to download URLs. This manifest enables the in-app auto-updater to detect new versions and download appropriate installers for the user's platform.

## Summary

- **Matrix builds** in [`.github/workflows/build-cpp.yml`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/.github/workflows/build-cpp.yml) handle Windows (x64/ARM64), Linux (x64), and macOS (ARM64/Intel) using CMake and platform-specific packaging tools.
- **macOS universal binaries** are created by merging ARM64 and Intel artifacts with `lipo` in a dedicated post-build job.
- **Release automation** in [`.github/workflows/release.yml`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/.github/workflows/release.yml) publishes GitHub Releases, updates [`README.md`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/README.md) download tables, and regenerates [`updates.json`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/updates.json) with SHA-256 hashes.
- **Customization** occurs via environment variables (`QT_VERSION`, `QT_MODULES`) and CMake flags (`FINCEPT_BUILD_INSTALLER`), with matrix entries defining supported architectures.

## Frequently Asked Questions

### How do I add Linux ARM64 support to the build matrix?

Add a new entry to the `matrix.include` section in [`.github/workflows/build-cpp.yml`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/.github/workflows/build-cpp.yml) specifying `os: ubuntu-22.04`, `arch: aarch64`, and a `cmake_extra` field pointing to a cross-compilation toolchain file. Ensure the runner has access to an ARM64 cross-compiler or use a Docker container with the appropriate toolchain.

### Where is the Qt version defined for the CI/CD pipeline?

The Qt version is defined in the `env` section of both workflow files as `QT_VERSION`. Currently set to `6.8.3`, changing this variable updates all `jurplel/install-qt-action@v4` steps across Windows, Linux, and macOS builds.

### How can I skip code signing for debug or pull request builds?

Add a conditional to the macOS packaging step that checks `github.ref`. For example, only run `codesign` when the reference starts with `refs/tags/`. This prevents signing during pull request builds while maintaining it for release tags.

### What triggers the release pipeline to run?

The release pipeline triggers on git tag pushes matching the pattern `v*` (e.g., `v4.0.2`) or via manual dispatch through the GitHub Actions UI. Pushing a tag automatically starts the matrix builds, followed by the release orchestration job upon successful completion.