Some notes about generating a macOS bundle with CMake
This post post is just a bunch of incomplete notes. I found the information to be a bit disseminated and I thought it would be a good idea to put everything togheter in one place. You can find references to the sources.
At the moment of writing this I was using CMake and CPack 3.18.1.
What are macOS bundles?[1]
A bundle is just a directory with a specific structure that contains executable code and the resources needed by that code. The operating system treats such directories in special ways. For example, a macOS app is a bundle (i.e. a directory). However, macOS presents the app as a single unit, as it was a file, in order to prevent users to accidentally modify important resources of the app and breaking it.
There are different types of bundles. Depending on its structure and contents a bundle can be:
- An application bundle
- A framework bundle
- A plug-in bundle
For the task at hand we are only concerned about application bundles.
Structure of an application bundle[1.1]
A Mac app bundle has a simple basic structure: there’s a top-level directory named Contents. All the contents of the bundle are inside this directory, including the resources, executable code, private frameworks, private plug-ins and support files that the application needs.
The basic structure of a macOS application
MyApp.app/
Contents/
Info.plist
MacOS/
Resources/
The Info.plist file holds configuration information for the application. macOS looks into this file to gather relevant information about your application.
The MacOS directory contains the standalone executable code of the application. In most cases, this directory contains only one binary file: your application’s main executable. However, you can also put additional standalone executables (such as command-line tools) in this directory.
The Resources directory contains all of the application’s resource files. Resources are data files that live outside your application’s executable file like images, icons, sounds, strings files, configuration files, and data files (among others).
The info.plist[2]
To do.
Generating a bundle with CMake and CPack
CPack is a tool that helps creating installers or installation packages for our application for each operating system we support.
Just like CMake has several generators to write the input files for several build systems, CPack ha several generators to create different types of packages and installers for different platforms[3]. There are two main generators for macOS bundles: the DragNDrop generator and the Bundle generator.
The DragNDrop generator does not allow multiple executables inside a single bundle; it enforces a 1:1 bundle-to-executable relationship.[4]
The Bundle generator does support multiple executables inside a single bundle.
CPack is a standalone executable that reads a configuration file usually named CPackConfig.cmake
.
However, CMake comes with a CPack module, which will automatically generate an
appropriate CPack configuration file[3.1].
The only thing we need to do to set it up is to include the module in our CMakeLists.txt:
include(CPack)
In order to use the CPack Bundle generator we need to define three CMake variables[5]:
CPACK_BUNDLE_NAME
: The bundle nameCPACK_BUNDLE_ICON
: The bundle iconCPACK_BUNDLE_PLIST
: The bundle plist
We must set these variables before we include CPack in order for them to take effect.
References
- Bundle Programming Guide (developer.apple.com)
- Information Property List (developer.apple.com)
- Packaging with CPack (gitlab.kitware.com/cmake)
- DragNDrop Package generator (gitlab.kitware.com/cmake)
- CPack Bundle Generator (cmake.org)
- MACOSX_BUNDLE vs CPACK_BUNDLE (stackoverflow.com)