BundleUtilities

This module provides utility commands for assembling standalone, bundle-style applications with CMake, such as macOS .app bundles or similar directory-based application bundles on other operating systems.

Load this module in CMake installation with:

include(BundleUtilities)

Note

Do not use this module at configure time (from CMakeLists.txt). Instead, include it and invoke its commands from an install(CODE) or install(SCRIPT).

Commands

This module provides the following commands:

fixup_bundle

Prepares a bundle for distribution by fixing up its internal dependencies:

fixup_bundle(<app> <libs> <dirs> [IGNORE_ITEM <files>...])

This command modifies the <app> bundle in-place to make it self-contained and portable, so that it can be drag-n-drop copied to another machine and run there, assuming all of the system libraries are compatible.

This command collects all dependencies (keys) for the executables and libraries in the bundle. For each dependency, it copies the required files into the bundle and adjusts them according to their own prerequisites. Once complete, it clears the collected keys and invokes the verify_app() command to ensure the final bundle is truly standalone.

The arguments are:

<app>

The path to the bundle to fix. This can be an .app directory or direct path to an executable.

<libs>

A list of libraries that must be fixed up, but that cannot be automatically determined by the otool output analysis (i.e. plugins). If plugins are passed to this command as this parameter, they should be installed or copied into the bundle before calling this command.

<dirs>

A list of paths where libraries might be found. These paths are searched first when a target without any path info is given. Then standard system locations are also searched: PATH, Framework locations, /usr/lib, etc.

IGNORE_ITEM <files>...

Added in version 3.6.

Optional list of file names to ignore (e.g. IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe").

copy_and_fixup_bundle

Copies the bundle and fixes up the new copied bundle in-place:

copy_and_fixup_bundle(<src> <dst> <libs> <dirs>)

This command makes a copy of the bundle <src> at location <dst> and then fixes up the new copied bundle in-place at <dst>.

The arguments are:

<src>

The directory of the bundle being copied.

<dst>

The destination directory of the bundle copy.

<libs>

A list of libraries that must be fixed up, but that cannot be automatically determined by the otool output analysis (i.e. plugins). If plugins are passed to this command as this parameter, they should be installed or copied into the bundle before calling this command.

<dirs>

A list of paths where libraries might be found. These paths are searched first when a target without any path info is given. Then standard system locations are also searched: PATH, Framework locations, /usr/lib, etc.

verify_app

Verifies that an application bundle appears valid based on running analysis tools on it:

verify_app(<app> [IGNORE_ITEM <files>...])

If the application fails verification, a message(FATAL_ERROR) is issued, halting the installation process.

The arguments are:

<app>

The path to the application to verify. This can be a .app directory or a standalone executable.

IGNORE_ITEM <files>...

Added in version 3.6.

Optional list of file names to ignore (e.g. IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe").

get_bundle_main_executable

Retrieves the main executable within a given application bundle:

get_bundle_main_executable(<bundle> <result-var>)

The result is stored in a <result-var> variable and will contain a full path name of the bundle's main executable file, or an error: prefixed string if it could not be determined.

get_dotapp_dir

Locates the enclosing .app directory for the given executable:

get_dotapp_dir(<exe> <dotapp-dir-var>)

This command retrieves the nearest parent dir whose name ends with .app given the full path to an executable and stores it to the <dotapp-dir-var> variable. If there is no such parent dir, then it simply retrieves the directory containing the executable.

The retrieved directory may or may not exist.

get_bundle_and_executable

Takes either a .app directory name or the name of an executable nested inside a .app directory and retrieves the path to the .app directory and the path to its main executable:

get_bundle_and_executable(<app> <bundle-var> <executable-var> <valid-var>)

The arguments are:

<app>

The name of the application being processed.

<bundle-var>

Variable name in which to store the resulting path to the .app directory. In case of any error, this variable will contain an error message prefixed with string error:.

<executable-var>

Variable name in which to store the resulting main executable. In case of any error, this variable will contain an error message prefixed with string error:.

<valid-var>

Variable name in which the boolean result is stored whether this command was successful or not.

get_bundle_all_executables

Gets all executables of a given bundle:

get_bundle_all_executables(<bundle> <exes-var>)

This command scans <bundle> bundle recursively for all executable files and stores them into a variable <exes-var>.

get_item_key

Generates a unique key for the given item:

get_item_key(<item> <key-var>)

Given <item> file name, this command generates <key-var> key that should be unique considering the set of libraries that need copying or fixing up to make a bundle standalone. This is essentially the file name including extension with . replaced by _.

This key is used as a prefix for CMake variables so that a set of variables can be associated with a given item based on its key.

get_item_rpaths

Gets RPATHS (run-time search paths) for the given item:

get_item_rpaths(<item> <rpaths-var>)

This command gets RPATHS of the <item> file name and stores them to the variable with provided name <rpaths-var>.

clear_bundle_keys

Clears all variables associated with keys:

clear_bundle_keys(<keys-var>)

This command loops over the <keys-var> list of keys, clearing all the variables associated with each key. After the loop, it clears the list of keys itself. This command should be called after the get_bundle_keys() command, when done working with a list of keys.

set_bundle_key_values

Adds a key to the list of keys:

set_bundle_key_values(
  <keys-var>
  <context>
  <item>
  <exepath>
  <dirs>
  <copyflag>
  [<rpaths>]
)

This command adds the <keys-var> key to the list (if necessary) for the given item. If added, also set all the variables associated with that key.

The arguments are:

<keys-var>

Variable name holding the name of the key to be added to the list for the given item.

<context>

The path to the top level loading path used for @loader_path replacement on Apple operating systems. When resolving item, @loader_path references will be resolved relative to the directory of the given context value (presumably another library).

<item>

The item for which to add the key.

<exepath>

The path to the top level executable used for @executable_path replacement on Apple operating systems.

<dirs>

A list of paths where libraries might be found. These paths are searched first when a target without any path info is given. Then standard system locations are also searched: PATH, Framework locations, /usr/lib, etc.

<copyflag>

If set to 1 library symlink structure will be preserved.

<rpaths>

Optional run-time search paths for an executable file or library to help find files.

get_bundle_keys

Gets bundle keys:

get_bundle_keys(<app> <libs> <dirs> <keys-var> [IGNORE_ITEM <files>...])

This command loops over all the executable and library files within <app> bundle (and given as extra <libs>) and accumulate a list of keys representing them. It sets values associated with each key such that they can be looped over all of them and copies prerequisite libs into the bundle and then does appropriate install_name_tool fixups.

The arguments are:

<app>

The path to the bundle to fix. This can be an .app directory or direct path to an executable.

<libs>

A list of libraries that must be fixed up, but that cannot be automatically determined by the otool output analysis (i.e. plugins). If plugins are passed to this command as this parameter, they should be installed or copied into the bundle before calling this command.

<dirs>

A list of paths where libraries might be found. These paths are searched first when a target without any path info is given. Then standard system locations are also searched: PATH, Framework locations, /usr/lib, etc.

<keys-var>

Variable name holding a list of keys that represent all executable and library files within the bundle.

IGNORE_ITEM <files>...

Added in version 3.6.

Optional list of file names to ignore (e.g. IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe").

copy_resolved_item_into_bundle

Copies a resolved item into the bundle if necessary:

copy_resolved_item_into_bundle(<resolved-item> <resolved-embedded-item>)

Copy is not necessary, if the <resolved-item> is "the same as" the <resolved-embedded-item>.

copy_resolved_framework_into_bundle

Copies a resolved framework into the bundle if necessary:

copy_resolved_framework_into_bundle(<resolved-item> <resolved-embedded-item>)

Copy is not necessary, if the <resolved-item> is "the same as" the <resolved-embedded-item>.

The following variables can be set before invoking this command:

BU_COPY_FULL_FRAMEWORK_CONTENTS

By default, this variable is not set. If full frameworks should be embedded in the bundles, set this variable to boolean true before calling the fixup_bundle() command. By default, this command copies the framework dylib itself plus the framework Resources directory.

fixup_bundle_item

Fixes up bundle item:

fixup_bundle_item(<resolved-embedded-item> <exepath> <dirs>)

This command gets the direct/non-system prerequisites of the <resolved-embedded-item> and for each prerequisite, it changes the way it is referenced to the value of the _EMBEDDED_ITEM keyed variable for that prerequisite. Most likely changing to an @executable_path style reference.

This command requires that the <resolved-embedded-item> be inside the bundle already. In other words, if plugins are passed to fixup_bundle() command as its <libs> parameter, they should be installed or copied into the bundle before calling the fixup_bundle() command.

Also, it changes the id of the item being fixed up to its own _EMBEDDED_ITEM value.

Changes are accumulated in a local variable and one call is made to install_name_tool command-line tool at the end of this command with all the changes at once.

The arguments are:

<resolved-embedded-item>

The bundle item to be fixed up.

<exepath>

The path to the top level executable used for @executable_path replacement on Apple operating systems.

<dirs>

A list of paths where libraries might be found. These paths are searched first when a target without any path info is given. Then standard system locations are also searched: PATH, Framework locations, /usr/lib, etc.

The following variables can be set before invoking this command:

BU_CHMOD_BUNDLE_ITEMS

If this variable is set to boolean true value then bundle items will be marked writable before install_name_tool tool tries to change them.

verify_bundle_prerequisites

Verifies that the sum of all prerequisites of all files inside the bundle are contained within the bundle or are system libraries, presumed to exist everywhere:

verify_bundle_prerequisites(
  <bundle>
  <result-var>
  <info-var>
  [IGNORE_ITEM <files>...]
)

The arguments are:

<bundle>

Name of the bundle being verified.

<result-var>

Name of the variable in which to store a boolean result of whether a verification was successful.

<info-var>

Name of the variable holding any informational messages produced by the verification.

IGNORE_ITEM <files>...

Added in version 3.6.

Optional list of file names to ignore (e.g. IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe").

Verifies that any symlinks found in the specified bundle point to other files that are already also in the bundle:

verify_bundle_symlinks(<bundle> <result-var> <info-var>)

Anything that points to an external file causes this command to fail the verification.

The arguments are:

<bundle>

Name of the bundle being verified.

<result-var>

Name of the variable in which to store a boolean result of whether a verification was successful.

<info-var>

Name of the variable holding any informational messages produced by the verification.

Examples

Using this module inside the installation code that is executed at the installation phase:

CMakeLists.txt
# ...

install(CODE "
  include(BundleUtilities)
  set(BU_CHMOD_BUNDLE_ITEMS TRUE)
  fixup_bundle(
    \"${fixup_exe}\"
    \"${plugins}\"
    \"${bin_dir};${library_dir};${binary_dir}\"
  )
")