Skip to content
On this page

๐Ÿ“ฆ Packaging Guide โ€‹

This guide is aimed at package maintainers who want to create and maintain official packages for CoolerControl. It covers the project's components, build system, dependencies, and common pitfalls.

Project Overview โ€‹

CoolerControl is split into two binary packages backed by a single source tree:

PackageBinaryDescription
coolercontrold/usr/bin/coolercontroldSystem daemon โ€” core logic, hardware access, REST/gRPC API, embedded web UI
coolercontrol/usr/bin/coolercontrolDesktop GUI โ€” thin Qt6/WebEngine wrapper around the daemon's web interface

The daemon is the essential component. The GUI is optional and recommended for desktop users.

Source Components โ€‹

The source tree contains several sub-projects built independently:

Sub-projectLanguageRole
coolercontrold/RustSystem daemon
coolercontrol/C++ / CMakeQt6 desktop application
coolercontrol-ui/TypeScript / Vue.jsWeb UI (embedded in the daemon binary)

An embedded Python service (liqctld) for liquidctl communication is bundled inside the daemon binary and requires no separate packaging. It was a separate package before v2.2.2 โ€” see the Pitfalls section below.

Source Tarballs โ€‹

Official release tarballs are published on the GitLab releases page:

# Source tarball (includes pre-built web UI assets)
https://gitlab.com/coolercontrol/coolercontrol/-/releases/VERSION/downloads/packages/coolercontrol-VERSION.tar.gz

# Rust vendor tarball (offline Cargo dependencies)
https://gitlab.com/coolercontrol/coolercontrol/-/releases/VERSION/downloads/packages/coolercontrold-vendor.tar.gz

The release tarball includes the web UI assets pre-built under coolercontrold/resources/app/. No Node.js or npm is required at package build time.

The vendor tarball is essential for distros that require offline builds (Fedora, OBS, etc.). Both tarballs are published together for each release.

For more info about the release tarball see Web UI Assets

Source tarball layout

The main tarball unpacks to coolercontrol-VERSION/. Inside, you'll find a subdirectory per sub-project (coolercontrold/, coolercontrol/, coolercontrol-ui/). The Fedora spec %prep step uses -n %{project}-%{version}/%{name} to cd into the correct sub-project.

Option 2: GitLab Archive + Build UI from Source โ€‹

If your distro policy requires that all compiled artifacts be built locally during the package build, you can start from the GitLab VCS archive instead:

https://gitlab.com/coolercontrol/coolercontrol/-/archive/VERSION/coolercontrol-VERSION.tar.gz

This is a plain git archive snapshot; it does not include pre-compiled web UI assets. You must build them as an additional step before compiling the daemon:

bash
# Add to BuildRequires: nodejs (>= 22), npm
cd coolercontrol-ui
npm ci --prefer-offline
npm exec vite build -- --outDir ../coolercontrold/resources/app --emptyOutDir
cd ..
# Then proceed with the standard cargo build for coolercontrold

npm network access

npm ci fetches packages from the npm registry unless an offline mirror or pre-populated cache is provided. Most distro build environments block outbound network access. If you need a fully offline build, you must also vendor the npm dependencies or use a local registry.

Web UI Assets and Reproducibility โ€‹

Shipping pre-built web UI assets in a source tarball is a pragmatic approach used by several server applications with embedded web UIs. Cockpit, the Red Hat server web console, navigates this similarly: its spec file conditionally rebuilds the bundle where npm tooling is available (Fedora โ‰ฅ 42), and falls back to the pre-built assets on distributions where it isn't packaged (RHEL, CentOS).

Distro policy varies

Some distributions, including Fedora, have guidelines that discourage shipping pre-built JS assets and may require rebuilding them during the package build. Check your distro's JavaScript packaging policy before choosing Option 1. Where a rebuild is required, use Option 2 and vendor the npm dependencies for offline builds.

CoolerControl's release tarballs are produced by packaging/release-source.sh using deterministic, reproducible-builds-compliant techniques:

  • Sorted file order (--sort=name) eliminates filesystem ordering differences
  • Fixed mtime (--mtime="@${SOURCE_DATE_EPOCH}") derived from the tagged commit timestamp
  • Zero ownership (--owner=0 --group=0 --numeric-owner) removes host-system identity
  • Stripped PAX headers (delete=atime,delete=ctime) removes non-deterministic timestamps
  • VCS files excluded (--exclude-vcs)

Anyone can reproduce the tarball locally by running release-source.sh against the same git ref and verify they get a byte-for-byte identical checksum:

bash
./packaging/release-source.sh https://gitlab.com/coolercontrol/coolercontrol.git VERSION

The full TypeScript and Vue source for the web UI (coolercontrol-ui/) is always present in the tarball alongside the built assets. Nothing is hidden or sourced from outside the release โ€” every build input can be traced, inspected, and rebuilt independently.

Build Dependencies โ€‹

coolercontrold (Rust daemon) โ€‹

DependencyNotes
cargo / rustc โ‰ฅ 1.85Rust edition 2024
libdrm-dev / libdrm-develRequired; libdrm_amdgpu
protobuf-compiler / protobuf-develgRPC code generation at build time

The daemon links NVML (NVIDIA management) and NVML-wrapper at runtime; there are no hard build-time NVIDIA headers required.

coolercontrol (Qt desktop app) โ€‹

DependencyNotes
CMake โ‰ฅ 3.15Build system
GCC / Clang (C++17)Compiler
qt6-base-dev / qt6-qtbase-develQt6 core
qt6-webengine-dev / qt6-qtwebengine-develQt6 WebEngine (Chromium)
qt6-webengine-dev-toolsRequired for Debian-based only
libgl1-mesa-dev / Mesa OpenGL headersOpenGL support

Qt6 WebEngine

Qt6 WebEngine (Chromium-based) is a large dependency that is not available on all architectures. CoolerControl officially supports x86_64 and aarch64 only. Do not attempt builds on 32-bit or other architectures.

Runtime Dependencies โ€‹

coolercontrold โ€‹

DependencyTypeNotes
liquidctl (Python)RecommendedUSB AIO/hub control; not required for hwmon-only setups
libdrm / libdrm-amdgpuOptionalAMD GPU Device names; not required

coolercontrol โ€‹

DependencyTypeNotes
coolercontrold (same version)Required (Debian) / Recommended (Fedora)Debian enforces version parity; Fedora uses a soft dep
libqt6webenginecore6-bin / qt6-qtwebengineRequiredQt6 WebEngine runtime (Chromium engine); Debian name / Fedora name
qt6-qpa-plugins / qt6-qtbase-guiRequiredWayland and X11 platform backends
hicolor-icon-themeRequiredIcon theme for desktop entry
libxcb-cursor0Required on Debian/UbuntuX11 cursor support; usually pulled in via ${shlibs:Depends}

Build Instructions โ€‹

Building the Daemon โ€‹

The daemon uses a standard Cargo workspace. Build from within the coolercontrold/ subdirectory:

bash
cargo build --release

The compiled binary is at target/release/coolercontrold.

Offline builds with a vendor archive โ€‹

If your build environment has no network access, use the upstream vendor tarball (or generate your own with cargo vendor):

bash
# Extract vendor archive alongside source
tar -xzf coolercontrold-vendor-VERSION.tar.gz

# Configure Cargo to use the vendor directory
mkdir -p .cargo
cat > .cargo/config.toml << 'EOF'
[source.crates-io]
replace-with = "vendored-sources"

[source.vendored-sources]
directory = "vendor"
EOF

cargo build --release

On Fedora/SUSE, the %cargo_prep -v vendor and %cargo_build macros handle this automatically.

Building the Desktop App โ€‹

bash
# From within the coolercontrol/ subdirectory
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --parallel $(nproc)

The compiled binary is at build/coolercontrol.

Installation Paths โ€‹

coolercontrold โ€‹

FileDestination
coolercontrold binary/usr/bin/coolercontrold
packaging/systemd/coolercontrold.service/usr/lib/systemd/system/coolercontrold.service
packaging/man/coolercontrold.8/usr/share/man/man8/coolercontrold.8
(config dir)/etc/coolercontrol/ - the daemon will create this directory
(data dir)/var/lib/coolercontrol/ - runtime state and plugins

coolercontrol โ€‹

FileDestination
coolercontrol binary/usr/bin/coolercontrol
packaging/metadata/org.coolercontrol.CoolerControl.desktop/usr/share/applications/
packaging/metadata/org.coolercontrol.CoolerControl.metainfo.xml/usr/share/metainfo/
packaging/metadata/org.coolercontrol.CoolerControl.svg/usr/share/icons/hicolor/scalable/apps/
packaging/metadata/org.coolercontrol.CoolerControl-alert.svg/usr/share/icons/hicolor/scalable/apps/
packaging/metadata/org.coolercontrol.CoolerControl-symbolic.svg/usr/share/icons/hicolor/symbolic/apps/
packaging/metadata/org.coolercontrol.CoolerControl-symbolic-alert.svg/usr/share/icons/hicolor/symbolic/apps/
packaging/metadata/org.coolercontrol.CoolerControl.png/usr/share/icons/hicolor/256x256/apps/
packaging/metadata/org.coolercontrol.CoolerControl-alert.png/usr/share/icons/hicolor/256x256/apps/
packaging/man/coolercontrol.1/usr/share/man/man1/coolercontrol.1

Alert icons

CoolerControl ships two icon states: a normal icon and an alert-state icon (used when an alert is active). Install all variants to /usr/share/icons/hicolor/ so the application can switch between them at runtime.

systemd Integration โ€‹

The coolercontrold.service unit file is at packaging/systemd/coolercontrold.service:

ini
[Unit]
Description=CoolerControl Daemon
After=network.target
StartLimitIntervalSec=60
StartLimitBurst=10

[Service]
Type=simple
Environment="CC_LOG=INFO"
ExecStart=/usr/bin/coolercontrold
Restart=always
RestartSec=1
TimeoutStopSec=10

[Install]
WantedBy=multi-user.target

Key properties:

  • Type=simple โ€” do not change to forking or notify; the daemon does not daemonize itself
  • CC_LOG=INFO โ€” controls log verbosity; valid values: ERROR, WARN, INFO, DEBUG, TRACE
  • Restart policy โ€” the daemon restarts aggressively (every 1 second), rate-limited to 10 restarts in 60 seconds; this is intentional

Use the standard systemd packaging macros for your distro:

RPM (Fedora/SUSE):

spec
BuildRequires: systemd-rpm-macros

%post
%systemd_post %{name}.service

%preun
%systemd_preun %{name}.service

%postun
%systemd_postun_with_restart %{name}.service

Debian:

# In debian/rules override_dh_installsystemd:
dh_installsystemd --name=coolercontrold --no-enable --no-start

OpenRC Integration โ€‹

For Musl/Alpine/Artix or other systems using OpenRC, files are provided at packaging/openrc/:

FileDestination
openrc/init.d/coolercontrol/etc/init.d/coolercontrol
openrc/conf.d/coolercontrol/etc/conf.d/coolercontrol

The init script uses supervise-daemon and logs to syslog. The conf.d file lets users override COOLERCONTROL_LOG_LEVEL without editing the init script directly.

Desktop Integration โ€‹

Validate the desktop entry and AppStream metainfo as part of your package build:

bash
# Validate desktop entry
desktop-file-validate /usr/share/applications/org.coolercontrol.CoolerControl.desktop

# Validate AppStream metainfo (appstream-glib)
appstream-util validate-relax /usr/share/metainfo/org.coolercontrol.CoolerControl.metainfo.xml

The AppStream metainfo ID is org.coolercontrol.CoolerControl. It includes release notes, screenshots, categories (Settings, HardwareSettings), and launchable references to the desktop entry and systemd service.

Existing Package References โ€‹

Upstream maintains reference packaging in the repository that you can base your work on:

FormatLocation in source tree
Debianpackaging/debian/
RPM (Fedora)packaging/fedora/coolercontrold.spec, coolercontrol.spec
OBS (Debian via OBS)packaging/obs/

Tips โ€‹

Build the daemon and GUI separately. They are independent CMake and Cargo projects. There is no top-level combined build system for packaging purposes.

Check upstream's Fedora spec for accurate dependency names. The packaging/fedora/ specs are kept current and reflect the exact pkg-config names used (libdrm_amdgpu, protobuf, etc.).

Validate AppStream metadata. Software centers (GNOME Software, KDE Discover) reject packages with invalid metainfo. Run appstream-util validate-relax during build to catch issues early.

Use %systemd_postun_with_restart (not %systemd_postun) on RPM systems so the daemon restarts after an upgrade rather than requiring a manual systemctl restart.

Pitfalls โ€‹

Rust MSRV is 1.85. Distros shipping older Rust toolchains cannot build the daemon without backporting or providing a newer toolchain. Fedora/COPR and recent Debian/Ubuntu releases are fine; older LTS distros may not be.

Qt6 WebEngine is architecture-limited. The Chromium engine embedded in Qt6 WebEngine does not build on all architectures. Upstream restricts packages to x86_64 / aarch64. If your distro build system attempts other architectures, the build will fail at the CMake stage.

coolercontrol-liqctld is obsolete. Before v2.2.2, there was a separate coolercontrol-liqctld Python package for liquidctl communication. It has been merged into the daemon binary. Any package that previously depended on coolercontrol-liqctld must declare:

spec
Obsoletes: coolercontrol-liqctld <= 2.2.2

The vendor tarball must exactly match the source version. Mixing a vendor tarball from one release with source from another will fail with missing or mismatched crates.

protobuf-compiler is a build-time-only dependency. It is needed to generate gRPC bindings during compilation but is not required at runtime. List it as BuildRequires only.

Released under the GPLv3+ License.