Shipping Your App
Package desktop applications with runtime dependencies and configure settings for release distribution.
On this page
You can package a desktop application built in the Desktop Apps guides (starting with Building a Desktop App) into a standalone release that runs on machines without the SDK.
The release is a standalone folder on Windows and Linux— on macOS, it is an app bundle.
Packaging assumes the project links with the CMake package from Linking to the Library.
Distribute Runtime Files
An installed application needs runtime files placed alongside the executable— it cannot run from the compiled binary alone.
File Search Paths
The default file system loads file:/// URLs from the assets/ directory. Settings::file_system_path sets this root path and defaults to ./assets/.
On Windows and Linux, the path is relative to the folder containing the executable. Inside a macOS app bundle, the path is relative to Contents/Resources/.
The renderer loads its own runtime data from assets/resources/.
Required Files
Every release build requires the following files and directory layout:
| Item | Windows and Linux | macOS App Bundle | Contents |
|---|---|---|---|
| Shared libraries | Beside the executable | Contents/MacOS/ |
The four libraries from the SDK's bin/ folder (UltralightCore, WebCore, Ultralight, and AppCore). |
| SDK resources | assets/resources/ |
Contents/Resources/assets/resources/ |
Runtime data including ICU data (icudt67l.dat), certificates (cacert.pem), and media controls. |
| Web content | assets/ |
Contents/Resources/assets/ |
HTML, CSS, JavaScript, and image files for the page. |
| Web Inspector (optional) | assets/inspector/ |
Contents/Resources/assets/inspector/ |
Web Inspector front end, included only when shipping developer tools to users. |
🚧 Missing runtime resources
If an application runs from the build folder but fails once installed, the
assets/resources/folder is almost always missing. Withouticudt67l.dat,App::Create()displays an error message box and exits. Withoutcacert.pem, the library logs an error and all HTTPS requests fail.
Package with CMake Install Rules
Calling find_package(Ultralight) defines path variables for the SDK's runtime files:
ULTRALIGHT_BINARY_DIR— shared libraries.ULTRALIGHT_RESOURCES_DIR— runtime data files.ULTRALIGHT_INSPECTOR_DIR— Web Inspector front end.
Windows and Linux Folders
Use CMake install() rules to assemble the executable and its runtime files into a standalone folder.
install(TARGETS MyApp RUNTIME DESTINATION "MyApp")
install(DIRECTORY "${ULTRALIGHT_BINARY_DIR}/" DESTINATION "MyApp")
install(DIRECTORY "${ULTRALIGHT_RESOURCES_DIR}" DESTINATION "MyApp/assets")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/assets/"
DESTINATION "MyApp/assets" OPTIONAL)
Running cmake --install populates the MyApp folder— ready to distribute directly or pass to an installer.
While ultralight_copy_runtime_files() from Linking to the Library stages these files in the build folder during development, install rules package them for release.
To ship developer tools to users, add an install rule that copies ULTRALIGHT_INSPECTOR_DIR into MyApp/assets.
macOS App Bundles
To target all three platforms in a single CMakeLists.txt, split the install rules with an if (APPLE) check.
if (APPLE)
install(TARGETS MyApp BUNDLE DESTINATION ".")
install(DIRECTORY "${ULTRALIGHT_BINARY_DIR}/"
DESTINATION "MyApp.app/Contents/MacOS")
install(DIRECTORY "${ULTRALIGHT_RESOURCES_DIR}"
DESTINATION "MyApp.app/Contents/Resources/assets")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/assets/"
DESTINATION "MyApp.app/Contents/Resources/assets" OPTIONAL)
else ()
install(TARGETS MyApp RUNTIME DESTINATION "MyApp")
install(DIRECTORY "${ULTRALIGHT_BINARY_DIR}/" DESTINATION "MyApp")
install(DIRECTORY "${ULTRALIGHT_RESOURCES_DIR}" DESTINATION "MyApp/assets")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/assets/"
DESTINATION "MyApp/assets" OPTIONAL)
endif ()
For a complete example showing both layouts, see samples/cmake/Common.cmake in the SDK.
🚧 Set BUNDLE DESTINATION on macOS
A target configured with
MACOSX_BUNDLErequiresBUNDLE DESTINATIONin itsinstall(TARGETS)rule. SpecifyingRUNTIME DESTINATIONalone causes a CMake configuration error on macOS.
Other Build Systems
Projects built without CMake must copy the runtime dependencies into the directory layouts shown above as a post-build step.
For step-by-step compiler and linker flags, see Linking to the Library.
The executable must be able to locate its shared libraries when launched. Windows searches the folder containing the executable automatically. On macOS, configure the linker to set the runtime search path (rpath) to @executable_path/. On Linux, set the rpath to $ORIGIN.
Configure Platform Settings
Each OS introduces release requirements beyond the build flags and link libraries described in Linking to the Library.
Windows
Target machines need the Microsoft Visual C++ Redistributable (x64)— an installer can bundle the package and run it during setup.
macOS
Pass MACOSX_BUNDLE to add_executable() to create an app bundle, then configure its properties in CMake.
set_target_properties(MyApp PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER "com.acme.starlight"
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in")
CMake generates a default Info.plist for each bundle— you can point MACOSX_BUNDLE_INFO_PLIST at a custom template to override it. The SDK provides samples/cmake/Info.plist.in as a starting point to configure the bundle identifier, version string, and NSHighResolutionCapable.
The bundle identifier set in MACOSX_BUNDLE_GUI_IDENTIFIER also names the application's storage directories on macOS.
Linux
Target machines must meet the Linux system requirements, including the supported glibc version and the X11 and fontconfig libraries needed by libAppCore.so. For the required dependencies, see Linking to the Library.
Storage and Log Locations
Ultralight creates dedicated application directories to store runtime logs, profiler traces, and persistent session data like cookies and databases.
Directory paths are derived from Settings::developer_name and Settings::app_name, which default to "MyCompany" and "MyApp". Set these properties to your company and application names before calling App::Create().
| Platform | Session Data | Logs and Traces |
|---|---|---|
| Windows | %APPDATA%\<developer_name>\<app_name> |
Same folder as session data |
| macOS | ~/Library/Application Support/<name> |
~/Library/Caches/<name> |
| Linux | $XDG_CACHE_HOME/com.<developer_name>.<app_name> |
Same folder as session data |
On macOS, <name> is the bundle identifier, or com.<developer_name>.<app_name> when the bundle has none.
On Linux, the directory falls back to ~/.cache/com.<developer_name>.<app_name> if $XDG_CACHE_HOME is unset.
To configure custom storage paths, see Sessions and Site Data. For log output details, see Logging and Console Messages.
Prepare for Release
Before shipping an application, review runtime settings and test the packaged release on a clean machine.
App Settings in Settings
Settings is the first argument passed to App::Create().
Leave Settings::enable_profiler set to false, which is the default. Turning it on writes trace files on every run to the diagnostics folder rather than the session data folder— on macOS, this is ~/Library/Caches/<name>.
The profiler requires the Pro edition or higher.
Engine Options in Config
Config is the second argument passed to App::Create().
Keep Config::diagnostics.developer_mode set to false. When developer mode is off, a release library ignores diagnostics environment variables such as UL_JS_DIAGNOSTICS— users cannot alter runtime behavior from their environment. For details, see Developer Mode and Diagnostics.
🚧 Never ignore SSL errors in production
Keep
Config::ignore_ssl_errorsset tofalse, which is the default. Setting it totrueconnects to servers with invalid certificates, creating a security risk in production.
View Permissions in ViewConfig
Pass ViewConfig to Window::AddPanel() to configure settings for individual views.
Set ViewConfig::allow_universal_access_from_file_urls to false when you load local pages you don't fully control. The default value is true, which lets a file:/// page read other frames and send requests to any origin. Setting it to false enforces standard cross-origin rules for local files.
Test on a Clean Machine
Run the distributed application folder on a machine without the SDK or developer tools installed. This confirms that the executable finds its shared libraries and runtime files in their packaged locations.
Verify that assets/resources/ is present beside the executable— in a macOS app bundle, this belongs in Contents/Resources/assets/resources/.