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 name
  • CPACK_BUNDLE_ICON: The bundle icon
  • CPACK_BUNDLE_PLIST: The bundle plist

We must set these variables before we include CPack in order for them to take effect.

References

  1. Bundle Programming Guide (developer.apple.com)
    1. Application Bundles
  2. Information Property List (developer.apple.com)
  3. Packaging with CPack (gitlab.kitware.com/cmake)
    1. Using CPack with CMake
  4. DragNDrop Package generator (gitlab.kitware.com/cmake)
  5. CPack Bundle Generator (cmake.org)
  6. MACOSX_BUNDLE vs CPACK_BUNDLE (stackoverflow.com)