CTK AppLauncher is a flexible launcher tool designed to simplify the deployment of Qt-based applications. It enables dynamic configuration of environment variables and runtime paths through an .ini
settings file, eliminating the need for hardcoded environment setup scripts.
This launcher is especially useful in relocatable deployments where the runtime environment must adapt to the install location of the application.
The launcher wraps an actual executable (typically suffixed with -real
) and uses a flexible settings system to:
- set or extend environment variables
- prepend library paths (e.g.,
LD_LIBRARY_PATH
,DYLD_LIBRARY_PATH
, orPATH
) - automatically expand values using platform-aware and context-specific placeholders
- support layered configuration via multiple
.ini
files (regular, user, and additional settings)
Note
Designed to be integrated in C++ CMake-based projects used to build and package Qt-based applications, the launcher settings use a simple .ini
format and can be adapted to other scenarios.
Start using CTKAppLauncher by integrating the pre-built binaries into your CMake-based project. See How It Works for configuration details and Why use the pre-built binaries? for rationale.
At startup, the launcher looks for a settings file named:
<LauncherName>LauncherSettings.ini
It searches the following directories, in order:
- the directory containing the launcher executable
- a
bin/
subdirectory - a
lib/
subdirectory
Example:
/path/to/AwesomeApp/
├── bin/
│ ├── AwesomeApp-real
│ └── AwesomeAppLauncherSettings.ini
└── lib/
└── libFoo.so
The settings file is a Qt-compatible .ini
file with structured sections. Example:
[General]
launcherSplashImagePath=bin/Splash.png
launcherSplashScreenHideDelayMs=1000
[Application]
path=bin/AwesomeApp-real
arguments=--multithreading-enabled
[Paths]
1\path=./bin
size=1
[LibraryPaths]
1\path=./lib
size=1
[EnvironmentVariables]
FOO_DIRS=<APPLAUNCHER_DIR>/lib<PATHSEP>/usr/local/lib
Paths
: prepend toPATH
LibraryPaths
: prepend to library search pathsEnvironmentVariables
: set key-value pairsGeneral
: supportsadditionalPathVariables
Application
: used to derive user additional settings
Format follows Qt QSettings.
At runtime, values in the settings file can include placeholders that are expanded contextually by the launcher:
placeholder | description |
---|---|
<APPLAUNCHER_DIR> |
Directory containing the launcher executable |
<APPLAUNCHER_NAME> |
Base name of the launcher executable |
<APPLAUNCHER_SETTINGS_DIR> |
Directory of the current settings file being parsed |
<PATHSEP> |
Platform-specific path separator (: on Unix, ; on Windows) |
<env:VARNAME> |
Expands to the value of the environment variable VARNAME |
<APPLAUNCHER_REGULAR_SETTINGS_DIR> |
Directory of the regular (primary) settings file |
<APPLAUNCHER_USER_SETTINGS_DIR> |
Directory of the user additional settings file (if found) |
<APPLAUNCHER_ADDITIONAL_SETTINGS_DIR> |
Directory of the additional settings file (if specified) |
Expansion is case-insensitive, and these placeholders allow dynamic referencing of paths across different environments and installation layouts.
The launcher can load and merge up to three .ini
settings files. These layers are processed in the following order and can each contribute values to the runtime environment:
-
Regular settings
-
The primary configuration file, located using the naming pattern:
<LauncherName>LauncherSettings.ini
-
Searched in the launcher directory,
bin/
, andlib/
subdirectories. -
Placeholder:
<APPLAUNCHER_REGULAR_SETTINGS_DIR>
-
-
User additional settings (optional)
-
Auto-discovered based on metadata in the
[Application]
group:name
,organizationName
,organizationDomain
, and optionallyrevision
-
Common search paths include:
<APPLAUNCHER_DIR>/<org>/<name>(-<revision>).ini ~/.config/<org>/<name>(-<revision>).ini
-
Placeholder:
<APPLAUNCHER_USER_SETTINGS_DIR>
-
-
Additional settings (optional)
-
Explicitly specified using the
additionalSettingsFilePath
key in the regular settings file. -
Can selectively override or supplement specific groups.
-
Prevent group overrides with:
additionalSettingsExcludeGroups = Paths,LibraryPaths,Environment
-
Placeholder:
<APPLAUNCHER_ADDITIONAL_SETTINGS_DIR>
-
Tip
All three settings files contribute to environment setup. Path variables and environment variables are accumulated and expanded using their respective placeholders, allowing highly flexible and relocatable application configurations.
The launcher builds the runtime environment in two distinct phases:
-
explicit variable assignment
- Environment variables defined under the
[EnvironmentVariables]
group are expanded using the placeholder mechanism (e.g.,<env:VAR>
,<APPLAUNCHER_DIR>
, etc.). - Each key-value pair is directly added to the environment.
- Environment variables defined under the
-
path-based variable composition
-
Paths listed in
[Paths]
,[LibraryPaths]
, and groups referenced byadditionalPathVariables
are expanded and prepended to the corresponding environment variables. -
The launcher ensures platform-specific behavior by mapping each section to the appropriate environment variable:
section linux macos windows LibraryPaths
LD_LIBRARY_PATH
DYLD_LIBRARY_PATH
PATH
Paths
PATH
PATH
PATH
-
Each variable is updated in a deterministic order (entries are sorted by numeric keys like
1\path
,2\path
, etc.).
-
Note
You can extend this behavior using custom groups listed in the additionalPathVariables
section. This allows for flexible mapping of user-defined path lists to specific environment variables.
The launcher accepts various command-line options:
./CTKAppLauncher --launcher-help
Usage
CTKAppLauncher [options]
Options
--launcher-help Display help
--launcher-version Show launcher version information
--launcher-verbose Verbose mode
--launch Specify the application to launch
--launcher-detach Launcher will NOT wait for the application to finish
--launcher-no-splash Hide launcher splash
--launcher-timeout Specify the time in second before the launcher kills the application. -1 means no timeout (default: -1)
--launcher-load-environment Specify the saved environment to load.
--launcher-dump-environment Launcher will print environment variables to be set, then exit
--launcher-show-set-environment-commands Launcher will print commands suitable for setting the parent environment (i.e. using 'eval' in a POSIX shell), then exit
--launcher-additional-settings Additional settings file to consider
--launcher-additional-settings-exclude-groups Comma separated list of settings groups that should NOT be overwritten by values in User and Additional settings. For example: General,Application,ExtraApplicationToLaunch
--launcher-ignore-user-additional-settings Ignore additional user settings
--launcher-generate-exec-wrapper-script Generate executable wrapper script allowing to set the environment
--launcher-generate-template Generate an example of setting file
The launcher internally tracks environment levels to support saving and restoring modified environments across invocations.
This mechanism enables advanced workflows like exporting a clean environment setup or temporarily modifying it for a subprocess.
Each time the launcher runs, it adds an internal marker:
APPLAUNCHER_LEVEL=N
This value increases with each nested launcher invocation. For example:
- First launcher run →
APPLAUNCHER_LEVEL=1
- If the launched application runs another launcher →
APPLAUNCHER_LEVEL=2
, and so on.
The environment variables from the previous level are saved with special names:
APPLAUNCHER_0_PATH=/usr/bin
APPLAUNCHER_1_PATH=/opt/AwesomeApp/bin
This mechanism allows restoring a prior environment level, which is particularly helpful for layered workflows or diagnostic tasks.
Print the environment as it would be set by the launcher:
./CTKAppLauncher --launcher-dump-environment
This includes all environment variables, with expanded values, including paths and placeholders.
Print shell-compatible commands that set the environment in the parent shell:
./CTKAppLauncher --launcher-show-set-environment-commands
You can use this with eval
to persist the environment without running the actual application:
eval $(./CTKAppLauncher --launcher-show-set-environment-commands)
You can explicitly request to restore a previously saved environment level using:
./CTKAppLauncher --launcher-load-environment 0
This will rebuild the environment based on variables prefixed by APPLAUNCHER_0_
.
If the level specified does not exist or is out of range, the launcher will fall back to the current environment.
Tip
Level 0
corresponds to the original environment, before any launcher-modified changes.
When the launcher modifies an environment variable (e.g., PATH
, LD_LIBRARY_PATH
, etc.), it stores the previous value under a variable name prefixed with the level, such as:
APPLAUNCHER_0_PATH
When reloading a level, it strips the prefix and applies the stored values.
Variables not part of the saved environment are unset to avoid contamination from higher levels.
This system makes the launcher robust and self-contained — no manual backup or restore of the environment is needed.
-
add CTKAppLauncher using FetchContent or
ExternalProject
see example -
Use the provided helper functions
ctkAppLauncherConfigureForTarget()
orctkAppLauncherConfigureForExecutable()
available inctkAppLauncher.cmake
To build CTKAppLauncher, you’ll need a C++ compiler, Qt 5.x, and CMake 3.16+.
Clone the repository:
git clone git@github.com:commontk/AppLauncher.git CTKAppLauncher
Configure the build:
On Windows:
cmake ^
-B CTKAppLauncher-build ^
-S CTKAppLauncher
On macOS/Linux:
cmake \
-DCMAKE_BUILD_TYPE:STRING=Release \
-B CTKAppLauncher-build \
-S CTKAppLauncher
Build the project:
cmake --build CTKAppLauncher-build --config Release --parallel
Run tests:
ctest --test-dir CTKAppLauncher-build --build-config Release --output-on-failure --parallel
Tip
To generate a standalone package, you need to either build Qt statically or reuse the archives available at jcfr/qt-static-build.
See the CI workflow for build configuration details.
Each GitHub release includes:
- platform-specific archives
- exact build instructions used
- whether the archive is relocatable or has fixed path expectations
See the GitHub release description for full details.
The pre-built binaries are statically linked and do not require Qt to be present on the host system. If your application bundles Qt libraries, using these binaries ensures the launcher works out of the box across platforms.
- on Windows, the
--launcher-timeout
option may not work as expected
Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given.
See CONTRIBUTING.md for more details.
Follow the steps below after verifying that all tests pass.
click to expand
-
List all tags sorted by version
git fetch --tags && \ git tag -l | sort -V
-
Choose the next release version number (without
tag=vX.Y.Z version_major=$(echo $tag | tr -d v | cut -d. -f1) version_minor=$(echo $tag | tr -d v | cut -d. -f2) version_patch=$(echo $tag | tr -d v | cut -d. -f3) echo "version_major [$version_major] version_minor[$version_minor] version_patch[$version_patch]"
-
Update
CMakeLists.txt
settingCTKAppLauncher_VERSION_IS_RELEASE
andCTKAppLauncher_*_VERSION
variablessed -E "s/set\(CTKAppLauncher_VERSION_IS_RELEASE 0\)/set\(CTKAppLauncher_VERSION_IS_RELEASE 1\)/g" -i CMakeLists.txt && \ sed -E "s/set\(CTKAppLauncher_MAJOR_VERSION [0-9]+\)/set\(CTKAppLauncher_MAJOR_VERSION $version_major\)/g" -i CMakeLists.txt && \ sed -E "s/set\(CTKAppLauncher_MINOR_VERSION [0-9]+\)/set\(CTKAppLauncher_MINOR_VERSION $version_minor\)/g" -i CMakeLists.txt && \ sed -E "s/set\(CTKAppLauncher_BUILD_VERSION [0-9]+\)/set\(CTKAppLauncher_BUILD_VERSION $version_patch\)/g" -i CMakeLists.txt && \ git add CMakeLists.txt && \ git commit -m "CTKAppLauncher $tag" && \ git diff HEAD^
-
Tag the release. Requires a GPG key with signatures:
git tag -s -m "CTKAppLauncher $tag" $tag main
-
Publish the tag to trigger the release build
git push origin $tag
-
Publish the GitHub Release
Once the CI workflow completes for the pushed tag, create a GitHub release.
This will automatically trigger the CD workflow to upload the release assets.
-
Update
CMakeLists.txt
settingCTKAppLauncher_VERSION_IS_RELEASE
to0
sed -E "s/set\(CTKAppLauncher_VERSION_IS_RELEASE 1\)/set\(CTKAppLauncher_VERSION_IS_RELEASE 0\)/g" -i CMakeLists.txt && \ git add CMakeLists.txt && \ git commit -m "Begin post-$tag development [ci skip]" && \ git diff HEAD^
-
Publish the changes:
git push origin main
It is covered by the Apache License, Version 2.0: