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

FinceptTerminal automates cross-platform releases using GitHub Actions, combining matrix builds in .github/workflows/build-cpp.yml with release orchestration in .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) – 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) – Aggregates artifacts, creates a GitHub Release, updates the README download table, and regenerates 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)

The .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)

The .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 and modifies 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:

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 and .github/workflows/release.yml:

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:

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:

cmake -B build -DFINCEPT_BUILD_INSTALLER=OFF

In the workflow file, this appears as:

- 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. 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 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 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 publishes GitHub Releases, updates README.md download tables, and regenerates 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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →