diff options
Diffstat (limited to 'meson/docs/markdown/Creating-OSX-packages.md')
-rw-r--r-- | meson/docs/markdown/Creating-OSX-packages.md | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/meson/docs/markdown/Creating-OSX-packages.md b/meson/docs/markdown/Creating-OSX-packages.md new file mode 100644 index 000000000..849d5fd5d --- /dev/null +++ b/meson/docs/markdown/Creating-OSX-packages.md @@ -0,0 +1,158 @@ +--- +short-description: Tools to create OS X packages +... + +# Creating OSX packages + +Meson does not have native support for building OSX packages but it +does provide all the tools you need to create one yourself. The reason +for this is that it is a very hard task to write a system that +provides for all the different ways to do that but it is very easy to +write simple scripts for each application. + +Sample code for this can be found in [the Meson manual test +suite](https://github.com/jpakkane/meson/tree/master/manual%20tests/4%20standalone%20binaries). + +## Creating an app bundle + +OSX app bundles are actually extremely simple. They are just a +directory of files in a certain format. All the details you need to +know are on [this +page](https://stackoverflow.com/questions/1596945/building-osx-app-bundle) +and it is highly recommended that you read it first. + +Let's assume that we are creating our app bundle into +`/tmp/myapp.app`. Suppose we have one executable, so we need to +install that into `Contents/MacOS`. If we define the executable like +this: + +```meson +executable('myapp', 'foo1.c', ..., install : true) +``` + +then we just need to initialize our build tree with this command: + +```console +$ meson --prefix=/tmp/myapp.app \ + --bindir=Contents/MacOS \ + builddir \ + <other flags you might need> +``` + +Now when we do `meson install` the bundle is properly staged. If you +have any resource files or data, you need to install them into +`Contents/Resources` either by custom install commands or specifying +more install paths to the Meson command. + +Next we need to install an `Info.plist` file and an icon. For those we +need the following two Meson definitions. + +```meson +install_data('myapp.icns', install_dir : 'Contents/Resources') +install_data('Info.plist', install_dir : 'Contents') +``` + +The format of `Info.plist` can be found in the link or the sample +project linked above. The simplest way to get an icon in the `icns` +format is to save your image as a tiff an then use the `tiff2icns` helper +application that comes with XCode. + +Some applications assume that the working directory of the app process +is the same where the binary executable is. If this is the case for +you, then you need to create a wrapper script that looks like this: + +```bash +#!/bin/bash + +cd "${0%/*}" +./myapp +``` + +install it with this: + +```meson +install_data('myapp.sh', install_dir : 'Contents/MacOS') +``` + +and make sure that you specify `myapp.sh` as the executable to run in +your `Info.plist`. + +If you are not using any external libraries, this is all you need to +do. You now have a full app bundle in `/tmp/myapp.app` that you can +use. Most applications use third party frameworks and libraries, +though, so you need to add them to the bundle so it will work on other +peoples' machines. + +As an example we are going to use the [SDL2](https://libsdl.org/) +framework. In order to bundle it in our app, we first specify an +installer script to run. + +```meson +meson.add_install_script('install_script.sh') +``` + +The install script does two things. First it copies the whole +framework into our bundle. + +```console +$ mkdir -p ${MESON_INSTALL_PREFIX}/Contents/Frameworks +$ cp -R /Library/Frameworks/SDL2.framework \ + ${MESON_INSTALL_PREFIX}/Contents/Frameworks +``` + +Then it needs to alter the library search path of our +executable(s). This tells OSX that the libraries your app needs are +inside your bundle. In the case of SDL2, the invocation goes like +this: + +```console +$ install_name_tool -change @rpath/SDL2.framework/Versions/A/SDL2 \ + @executable_path/../FrameWorks/SDL2.framework/Versions/A/SDL2 \ + ${MESON_INSTALL_PREFIX}/Contents/MacOS/myapp +``` + +This is the part of OSX app bundling that you must always do +manually. OSX dependencies come in many shapes and forms and +unfortunately there is no reliable automatic way to determine how each +dependency should be handled. Frameworks go to the `Frameworks` +directory while plain `.dylib` files usually go to +`Contents/Resources/lib` (but you can put them wherever you like). To +get this done you have to check what your program links against with +`otool -L /path/to/binary` and manually add the copy and fix steps to +your install script. Do not copy system libraries inside your bundle, +though. + +After this you have a fully working, self-contained OSX app bundle +ready for distribution. + +## Creating a .dmg installer + +A .dmg installer is similarly quite simple, at its core it is +basically a fancy compressed archive. A good description can be found +on [this page](https://el-tramo.be/guides/fancy-dmg/). Please read it +and create a template image file according to its instructions. + +The actual process of creating the installer is very simple: you mount +the template image, copy your app bundle in it, unmount it and convert +the image into a compressed archive. The actual commands to do this +are not particularly interesting, feel free to steal them from either +the linked page above or from the sample script in Meson's test suite. + +## Putting it all together + +There are many ways to put the .dmg installer together and different +people will do it in different ways. The linked sample code does it by +having two different scripts. This separates the different pieces +generating the installer into logical pieces. + +`install_script.sh` only deals with embedding dependencies and fixing +the library paths. + +`build_osx_installer.sh` sets up the build with the proper paths, +compiles, installs and generates the .dmg package. + +The main reasoning here is that in order to build a complete OSX +installer package from source, all you need to do is to cd into the +source tree and run `./build_osx_installer.sh`. To build packages on +other platforms you would write scripts such as +`build_windows_installer.bat` and so on. |