Creating an app bundle

Introduction

On (most) apple devices, applications are just folders containing information about the app. Here I will show you how to create the basic setup for your application. The content of an application-bundle varies, based on the IDE, libraries, language, and more, so get ready for a lot of frustration. If you want to read more information about the bundles, I recommend you to read this apple developer page.

1. Creating the executable

The first thing is to create your executable, this process varies depending on your IDE and language (I like to work in c++, so my applications are compiled with g++). I suggest to google how to compile your code if you don't know how.

2. Setting up folder structure

The next step is to setup the bundle structure. Open your terminal and locate a folder you want to start building your app. I prefer to do it on my Desktop, so I did:
$ cd ~/Desktop
I then ran the following commands to create the structure (you could do it in one long command, but this is easier to read for you).
$ mkdir myapp.app
$ mkdir myapp.app/Contents/
$ mkdir myapp.app/Contents/MacOS/
$ mkdir myapp.app/Contents/Resources/
$ mkdir myapp.app/Contents/Resources/lib
$ mkdir myapp.app/Contents/Resources/bin
$ mkdir myapp.app/Contents/Resources/etc
$ mkdir myapp.app/Contents/Resources/share

This will create a folder that looks (somewhat) like this:
Screenshot of the folder that will be created
Put your executable in the MacOS folder by copying and pasting it, or with the terminal command:
$ cp /Users/MyName/Documents/app /Users/MyName/Desktop/myapp.app/Contents/MacOS
NOTE: to get to the Contents/MacOS folder in your finder, you need to rightclick myapp.app and click `Show Package Contents`.

3. Linking Dynamic Libraries (AKA hell)

Most applications use one or multiple libraries. typically, these libraries come with .dylib files (DYnamic LIBraries). Your application work, because your computer has the dylibs stored somewhere (usually in /usr/local/opt/somelibrary/lib/) and you tell your compiler where it can find these files to compile.

This would mean that your app will only work on Macs with the same version library installed in the same location. This is not really what we want, so we're going to copy all the files our application needs and distribut them with out application.

I used the GTK+3.0 library to create a GUI for one of my applications, so I had to get the GTK+3.0 dylibs. Luckily, there is a simple command that will list all your app's dependencies:
$ otool -L myExecutable
My results looked like this:
Screenshot of my terminal listing my executable's dependecies
It shows all the paths to the dylibs my app depends on and the lowest required version (the files in usr/lib/ and /System/ are system files and are already installed on every Mac). You now need to copy every dylib into your Resources/lib folder. I did this with a bash file:
$ cd ~/Desktop/myapp.app
$ touch copyDylibs
$ chmod +x copyDylibs

Open the file with your favourite text editor and add the copy command for every dylib:
$ cp /path/to/dylib /path/to/desired/location
So for me the bash file looked like this:

#!/bin/bash
cp /usr/local/opt/atk/lib/libatk-1.0.0.dylib Resources/lib
cp /usr/local/opt/atkmm/lib/libatkmm-1.6.1.dylib Resources/lib
cp /usr/local/opt/gtkmm3/lib/libgdkmm-3.0.1.dylib Resources/lib
cp /usr/local/opt/glibmm/lib/libgiomm-2.4.1.dylib Resources/lib
cp /usr/local/opt/pangomm/lib/libpangomm-1.4.1.dylib Resources/lib
cp /usr/local/opt/glibmm/lib/libglibmm-2.4.1.dylib Resources/lib
cp /usr/local/opt/gtk+3/lib/libgtk-3.0.dylib Resources/lib
cp /usr/local/opt/gtk+3/lib/libgdk-3.0.dylib Resources/lib
cp /usr/local/opt/pango/lib/libpangocairo-1.0.0.dylib Resources/lib
cp /usr/local/opt/pango/lib/libpango-1.0.0.dylib Resources/lib
cp /usr/local/opt/cairo/lib/libcairo-gobject.2.dylib Resources/lib
cp /usr/local/opt/glib/lib/libgio-2.0.0.dylib Resources/lib
cp /usr/local/opt/cairomm/lib/libcairomm-1.0.1.dylib Resources/lib
cp /usr/local/opt/cairo/lib/libcairo.2.dylib Resources/lib
cp /usr/local/opt/libsigc++/lib/libsigc-2.0.0.dylib Resources/lib
cp /usr/local/opt/gdk-pixbuf/lib/libgdk_pixbuf-2.0.0.dylib Resources/lib
cp /usr/local/opt/glib/lib/libgobject-2.0.0.dylib Resources/lib
cp /usr/local/opt/glib/lib/libglib-2.0.0.dylib Resources/lib
cp /usr/local/opt/gettext/lib/libintl.8.dylib Resources/lib
cp /usr/local/opt/pixman/lib/libpixman-1.0.dylib Resources/lib
cp /usr/local/opt/fontconfig/lib/libfontconfig.1.dylib Resources/lib
cp /usr/local/opt/freetype/lib/libfreetype.6.dylib Resources/lib
cp /usr/local/opt/libpng/lib/libpng16.16.dylib Resources/lib
cp /usr/local/opt/libepoxy/lib/libepoxy.dylib Resources/lib
cp /usr/local/opt/libffi/lib/libffi.6.dylib Resources/lib
cp /usr/local/Cellar/glib/2.52.3/lib/libgmodule-2.0.0.dylib Resources/lib
cp /usr/local/opt/pcre/lib/libpcre.1.dylib Resources/lib
cp /usr/local/Cellar/glibmm/2.52.0/lib/libglibmm-2.4.1.dylib Resources/lib
cp /usr/local/Cellar/gtk+3/3.22.17/lib/libgdk-3.0.dylib Resources/lib
cp /usr/local/opt/glib/lib/libgthread-2.0.0.dylib Resources/lib
cp /usr/local/Cellar/pango/1.40.7/lib/libpangoft2-1.0.0.dylib Resources/lib
cp /usr/local/opt/harfbuzz/lib/libharfbuzz.0.dylib Resources/lib
cp /usr/local/opt/graphite2/lib/libgraphite2.3.dylib Resources/lib
cp /usr/local/Cellar/pango/1.40.7/lib/libpango-1.0.0.dylib Resources/lib

Then run the file by typing the following in your terminal:
$ ./copyDylibs
Sometimes, dylibs depend on eachother (libgtk-3.0.dylib uses functionalities of libgdk-3.0.dylib), so you will need to tell every dylib it should look for the dylib you copied to your lib folder (rather than the one in /usr/local/opt/). This can be done with the install_name_tool command, which looks like this:
$ install_name_tool -change "path/to/original/file" "path/to/new/file" fileToChange
The path/to/original/file we know, thanks to the otool. The path/to/new/file we know, wich is /Users/USERNAME/Desktop/myapp.app/Resources/lib. But your user will not have the same USERNAME as you have and he will probably also not have it located on their desktop. So we will have te set the path/to/new/file to something based of our executable. Luckily @executable_path exists. @executable_path is the path to our executable located in the MacOS folder (There is @executable_path, @loader_path and @rpath, more about those here)

You will need to do install_name_tool for every dylib's dependency, so I used otool -L again for every dylib to see it's dependencies. NOTE: if the first entry is the same dylib as you used the otool on (even if it's in a different folder), you can ignore the first dylib.
Screenshot of my dylib dependencies
I added these commands to the copyDylibs bash file, so Every time I copy the files, they also look for the right dependencies. The bash file now looks like this:

#!/bin/bash
cp /usr/local/opt/atk/lib/libatk-1.0.0.dylib Resources/lib
cp /usr/local/opt/atkmm/lib/libatkmm-1.6.1.dylib Resources/lib
cp /usr/local/opt/gtkmm3/lib/libgdkmm-3.0.1.dylib Resources/lib
cp /usr/local/opt/glibmm/lib/libgiomm-2.4.1.dylib Resources/lib
cp /usr/local/opt/pangomm/lib/libpangomm-1.4.1.dylib Resources/lib
cp /usr/local/opt/glibmm/lib/libglibmm-2.4.1.dylib Resources/lib
cp /usr/local/opt/gtk+3/lib/libgtk-3.0.dylib Resources/lib
cp /usr/local/opt/gtk+3/lib/libgdk-3.0.dylib Resources/lib
cp /usr/local/opt/pango/lib/libpangocairo-1.0.0.dylib Resources/lib
cp /usr/local/opt/pango/lib/libpango-1.0.0.dylib Resources/lib
cp /usr/local/opt/cairo/lib/libcairo-gobject.2.dylib Resources/lib
cp /usr/local/opt/glib/lib/libgio-2.0.0.dylib Resources/lib
cp /usr/local/opt/cairomm/lib/libcairomm-1.0.1.dylib Resources/lib
cp /usr/local/opt/cairo/lib/libcairo.2.dylib Resources/lib
cp /usr/local/opt/libsigc++/lib/libsigc-2.0.0.dylib Resources/lib
cp /usr/local/opt/gdk-pixbuf/lib/libgdk_pixbuf-2.0.0.dylib Resources/lib
cp /usr/local/opt/glib/lib/libgobject-2.0.0.dylib Resources/lib
cp /usr/local/opt/glib/lib/libglib-2.0.0.dylib Resources/lib
cp /usr/local/opt/gettext/lib/libintl.8.dylib Resources/lib
cp /usr/local/opt/pixman/lib/libpixman-1.0.dylib Resources/lib
cp /usr/local/opt/fontconfig/lib/libfontconfig.1.dylib Resources/lib
cp /usr/local/opt/freetype/lib/libfreetype.6.dylib Resources/lib
cp /usr/local/opt/libpng/lib/libpng16.16.dylib Resources/lib
cp /usr/local/opt/libepoxy/lib/libepoxy.dylib Resources/lib
cp /usr/local/opt/libffi/lib/libffi.6.dylib Resources/lib
cp /usr/local/Cellar/glib/2.52.3/lib/libgmodule-2.0.0.dylib Resources/lib
cp /usr/local/opt/pcre/lib/libpcre.1.dylib Resources/lib
cp /usr/local/Cellar/glibmm/2.52.0/lib/libglibmm-2.4.1.dylib Resources/lib
cp /usr/local/Cellar/gtk+3/3.22.17/lib/libgdk-3.0.dylib Resources/lib
cp /usr/local/opt/glib/lib/libgthread-2.0.0.dylib Resources/lib
cp /usr/local/Cellar/pango/1.40.7/lib/libpangoft2-1.0.0.dylib Resources/lib
cp /usr/local/opt/harfbuzz/lib/libharfbuzz.0.dylib Resources/lib
cp /usr/local/opt/graphite2/lib/libgraphite2.3.dylib Resources/lib
cp /usr/local/Cellar/pango/1.40.7/lib/libpango-1.0.0.dylib Resources/lib

install_name_tool -change "/usr/local/opt/glib/lib/libgobject-2.0.0.dylib" "@executable_path/../Resources/lib/libgobject-2.0.0.dylib" Resources/lib/libatk-1.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "@executable_path/../Resources/lib/libglib-2.0.0.dylib" Resources/lib/libatk-1.0.0.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "@executable_path/../Resources/lib/libintl.8.dylib" Resources/lib/libatk-1.0.0.dylib

install_name_tool -change "/usr/local/opt/atk/lib/libatk-1.0.0.dylib" "@executable_path/../Resources/lib/libatk-1.0.0.dylib" Resources/lib/libatkmm-1.6.1.dylib
install_name_tool -change "/usr/local/opt/glibmm/lib/libglibmm-2.4.1.dylib" "@executable_path/../Resources/lib/libglibmm-2.4.1.dylib" Resources/lib/libatkmm-1.6.1.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgobject-2.0.0.dylib" "@executable_path/../Resources/lib/libgobject-2.0.0.dylib" Resources/lib/libatkmm-1.6.1.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "@executable_path/../Resources/lib/libglib-2.0.0.dylib" Resources/lib/libatkmm-1.6.1.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "@executable_path/../Resources/lib/libintl.8.dylib" Resources/lib/libatkmm-1.6.1.dylib
install_name_tool -change "/usr/local/opt/libsigc++/lib/libsigc-2.0.0.dylib" "@executable_path/../Resources/lib/libsigc-2.0.0.dylib" Resources/lib/libatkmm-1.6.1.dylib

install_name_tool -change "/usr/local/Cellar/cairo/1.14.10/lib/libcairo.2.dylib" "@executable_path/../Resources/lib/libcairo.2.dylib" Resources/lib/libcairo-gobject.2.dylib
install_name_tool -change "/usr/local/opt/pixman/lib/libpixman-1.0.dylib" "@executable_path/../Resources/lib/libpixman-1.0.dylib" Resources/lib/libcairo-gobject.2.dylib
install_name_tool -change "/usr/local/opt/fontconfig/lib/libfontconfig.1.dylib" "@executable_path/../Resources/lib/libfontconfig.1.dylib" Resources/lib/libcairo-gobject.2.dylib
install_name_tool -change "/usr/local/opt/freetype/lib/libfreetype.6.dylib" "@executable_path/../Resources/lib/libfreetype.6.dylib" Resources/lib/libcairo-gobject.2.dylib
install_name_tool -change "/usr/local/opt/libpng/lib/libpng16.16.dylib" "@executable_path/../Resources/lib/libpng16.16.dylib" Resources/lib/libcairo-gobject.2.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgobject-2.0.0.dylib" "@executable_path/../Resources/lib/libgobject-2.0.0.dylib" Resources/lib/libcairo-gobject.2.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "@executable_path/../Resources/lib/libglib-2.0.0.dylib" Resources/lib/libcairo-gobject.2.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "@executable_path/../Resources/lib/libintl.8.dylib" Resources/lib/libcairo-gobject.2.dylib

install_name_tool -change "/usr/local/opt/pixman/lib/libpixman-1.0.dylib" "@executable_path/../Resources/lib/libpixman-1.0.dylib" Resources/lib/libcairo.2.dylib
install_name_tool -change "/usr/local/opt/fontconfig/lib/libfontconfig.1.dylib" "@executable_path/../Resources/lib/libfontconfig.1.dylib" Resources/lib/libcairo.2.dylib
install_name_tool -change "/usr/local/opt/freetype/lib/libfreetype.6.dylib" "@executable_path/../Resources/lib/libfreetype.6.dylib" Resources/lib/libcairo.2.dylib
install_name_tool -change "/usr/local/opt/libpng/lib/libpng16.16.dylib" "@executable_path/../Resources/lib/libpng16.16.dylib" Resources/lib/libcairo.2.dylib

install_name_tool -change "/usr/local/opt/libsigc++/lib/libsigc-2.0.0.dylib" "@executable_path/../Resources/lib/libsigc-2.0.0.dylib" Resources/lib/libcairomm-1.0.1.dylib
install_name_tool -change "/usr/local/opt/freetype/lib/libfreetype.6.dylib" "@executable_path/../Resources/lib/libfreetype.6.dylib" Resources/lib/libcairomm-1.0.1.dylib
install_name_tool -change "/usr/local/opt/libpng/lib/libpng16.16.dylib" "@executable_path/../Resources/lib/libpng16.16.dylib" Resources/lib/libcairomm-1.0.1.dylib
install_name_tool -change "/usr/local/opt/cairo/lib/libcairo.2.dylib" "@executable_path/../Resources/lib/libcairo.2.dylib" Resources/lib/libcairomm-1.0.1.dylib

install_name_tool -change "/usr/local/opt/freetype/lib/libfreetype.6.dylib" "@executable_path/../Resources/lib/libfreetype.6.dylib" Resources/lib/libfontconfig.1.dylib

install_name_tool -change "/usr/local/opt/libpng/lib/libpng16.16.dylib" "@executable_path/../Resources/lib/libpng16.16.dylib" Resources/lib/libfreetype.6.dylib

install_name_tool -change "/usr/local/opt/glib/lib/libgmodule-2.0.0.dylib" "@executable_path/../Resources/lib/libgmodule-2.0.0.dylib" Resources/lib/libgdk_pixbuf-2.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgio-2.0.0.dylib" "@executable_path/../Resources/lib/libgio-2.0.0.dylib" Resources/lib/libgdk_pixbuf-2.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgobject-2.0.0.dylib" "@executable_path/../Resources/lib/libgobject-2.0.0.dylib" Resources/lib/libgdk_pixbuf-2.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "@executable_path/../Resources/lib/libglib-2.0.0.dylib" Resources/lib/libgdk_pixbuf-2.0.0.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "@executable_path/../Resources/lib/libintl.8.dylib" Resources/lib/libgdk_pixbuf-2.0.0.dylib
install_name_tool -change "/usr/local/opt/libpng/lib/libpng16.16.dylib" "@executable_path/../Resources/lib/libpng16.16.dylib" Resources/lib/libgdk_pixbuf-2.0.0.dylib

install_name_tool -change "/usr/local/opt/pango/lib/libpangocairo-1.0.0.dylib" "@executable_path/../Resources/lib/libpangocairo-1.0.0.dylib" Resources/lib/libgdk-3.0.dylib
install_name_tool -change "/usr/local/opt/pango/lib/libpango-1.0.0.dylib" "@executable_path/../Resources/lib/libpango-1.0.0.dylib" Resources/lib/libgdk-3.0.dylib
install_name_tool -change "/usr/local/opt/gdk-pixbuf/lib/libgdk_pixbuf-2.0.0.dylib" "@executable_path/../Resources/lib/libgdk_pixbuf-2.0.0.dylib" Resources/lib/libgdk-3.0.dylib
install_name_tool -change "/usr/local/opt/cairo/lib/libcairo-gobject.2.dylib" "@executable_path/../Resources/lib/libcairo-gobject.2.dylib" Resources/lib/libgdk-3.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgio-2.0.0.dylib" "@executable_path/../Resources/lib/libgio-2.0.0.dylib" Resources/lib/libgdk-3.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgobject-2.0.0.dylib" "@executable_path/../Resources/lib/libgobject-2.0.0.dylib" Resources/lib/libgdk-3.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "@executable_path/../Resources/lib/libglib-2.0.0.dylib" Resources/lib/libgdk-3.0.dylib
install_name_tool -change "/usr/local/opt/cairo/lib/libcairo.2.dylib" "@executable_path/../Resources/lib/libcairo.2.dylib" Resources/lib/libgdk-3.0.dylib
install_name_tool -change "/usr/local/opt/libepoxy/lib/libepoxy.dylib" "@executable_path/../Resources/lib/libepoxy.dylib" Resources/lib/libgdk-3.0.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "@executable_path/../Resources/lib/libintl.8.dylib" Resources/lib/libgdk-3.0.dylib

install_name_tool -change "/usr/local/opt/glibmm/lib/libgiomm-2.4.1.dylib" "@executable_path/../Resources/lib/libgiomm-2.4.1.dylib" Resources/lib/libgdkmm-3.0.1.dylib
install_name_tool -change "/usr/local/opt/pangomm/lib/libpangomm-1.4.1.dylib" "@executable_path/../Resources/lib/libpangomm-1.4.1.dylib" Resources/lib/libgdkmm-3.0.1.dylib
install_name_tool -change "/usr/local/opt/glibmm/lib/libglibmm-2.4.1.dylib" "@executable_path/../Resources/lib/libglibmm-2.4.1.dylib" Resources/lib/libgdkmm-3.0.1.dylib
install_name_tool -change "/usr/local/opt/gtk+3/lib/libgtk-3.0.dylib" "@executable_path/../Resources/lib/libgtk-3.0.dylib" Resources/lib/libgdkmm-3.0.1.dylib
install_name_tool -change "/usr/local/opt/gtk+3/lib/libgdk-3.0.dylib" "@executable_path/../Resources/lib/libgdk-3.0.dylib" Resources/lib/libgdkmm-3.0.1.dylib
install_name_tool -change "/usr/local/opt/pango/lib/libpangocairo-1.0.0.dylib" "@executable_path/../Resources/lib/libpangocairo-1.0.0.dylib" Resources/lib/libgdkmm-3.0.1.dylib
install_name_tool -change "/usr/local/opt/pango/lib/libpango-1.0.0.dylib" "@executable_path/../Resources/lib/libpango-1.0.0.dylib" Resources/lib/libgdkmm-3.0.1.dylib
install_name_tool -change "/usr/local/opt/atk/lib/libatk-1.0.0.dylib" "@executable_path/../Resources/lib/libatk-1.0.0.dylib" Resources/lib/libgdkmm-3.0.1.dylib
install_name_tool -change "/usr/local/opt/cairo/lib/libcairo-gobject.2.dylib" "@executable_path/../Resources/lib/libcairo-gobject.2.dylib" Resources/lib/libgdkmm-3.0.1.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgio-2.0.0.dylib" "@executable_path/../Resources/lib/libgio-2.0.0.dylib" Resources/lib/libgdkmm-3.0.1.dylib
install_name_tool -change "/usr/local/opt/cairomm/lib/libcairomm-1.0.1.dylib" "@executable_path/../Resources/lib/libcairomm-1.0.1.dylib" Resources/lib/libgdkmm-3.0.1.dylib
install_name_tool -change "/usr/local/opt/cairo/lib/libcairo.2.dylib" "@executable_path/../Resources/lib/libcairo.2.dylib" Resources/lib/libgdkmm-3.0.1.dylib
install_name_tool -change "/usr/local/opt/libsigc++/lib/libsigc-2.0.0.dylib" "@executable_path/../Resources/lib/libsigc-2.0.0.dylib" Resources/lib/libgdkmm-3.0.1.dylib
install_name_tool -change "/usr/local/opt/gdk-pixbuf/lib/libgdk_pixbuf-2.0.0.dylib" "@executable_path/../Resources/lib/libgdk_pixbuf-2.0.0.dylib" Resources/lib/libgdkmm-3.0.1.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgobject-2.0.0.dylib" "@executable_path/../Resources/lib/libgobject-2.0.0.dylib" Resources/lib/libgdkmm-3.0.1.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "@executable_path/../Resources/lib/libglib-2.0.0.dylib" Resources/lib/libgdkmm-3.0.1.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "@executable_path/../Resources/lib/libintl.8.dylib" Resources/lib/libgdkmm-3.0.1.dylib

install_name_tool -change "/usr/local/Cellar/glib/2.52.3/lib/libgobject-2.0.0.dylib" "@executable_path/../Resources/lib/libgobject-2.0.0.dylib" Resources/lib/libgio-2.0.0.dylib
install_name_tool -change "/usr/local/opt/libffi/lib/libffi.6.dylib" "@executable_path/../Resources/lib/libffi.6.dylib" Resources/lib/libgio-2.0.0.dylib
install_name_tool -change "/usr/local/Cellar/glib/2.52.3/lib/libgmodule-2.0.0.dylib" "@executable_path/../Resources/lib/libgmodule-2.0.0.dylib" Resources/lib/libgio-2.0.0.dylib
install_name_tool -change "/usr/local/Cellar/glib/2.52.3/lib/libglib-2.0.0.dylib" "@executable_path/../Resources/lib/libglib-2.0.0.dylib" Resources/lib/libgio-2.0.0.dylib
install_name_tool -change "/usr/local/opt/pcre/lib/libpcre.1.dylib" "@executable_path/../Resources/lib/libpcre.1.dylib" Resources/lib/libgio-2.0.0.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "@executable_path/../Resources/lib/libintl.8.dylib" Resources/lib/libgio-2.0.0.dylib

install_name_tool -change "/usr/local/opt/libsigc++/lib/libsigc-2.0.0.dylib" "@executable_path/../Resources/lib/libsigc-2.0.0.dylib" Resources/lib/libgiomm-2.4.1.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgmodule-2.0.0.dylib" "@executable_path/../Resources/lib/libgmodule-2.0.0.dylib" Resources/lib/libgiomm-2.4.1.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgio-2.0.0.dylib" "@executable_path/../Resources/lib/libgio-2.0.0.dylib" Resources/lib/libgiomm-2.4.1.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgobject-2.0.0.dylib" "@executable_path/../Resources/lib/libgobject-2.0.0.dylib" Resources/lib/libgiomm-2.4.1.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "@executable_path/../Resources/lib/libglib-2.0.0.dylib" Resources/lib/libgiomm-2.4.1.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "@executable_path/../Resources/lib/libintl.8.dylib" Resources/lib/libgiomm-2.4.1.dylib
install_name_tool -change "/usr/local/Cellar/glibmm/2.52.0/lib/libglibmm-2.4.1.dylib" "@executable_path/../Resources/lib/libglibmm-2.4.1.dylib" Resources/lib/libgiomm-2.4.1.dylib

install_name_tool -change "/usr/local/opt/pcre/lib/libpcre.1.dylib" "@executable_path/../Resources/lib/libpcre.1.dylib" Resources/lib/libglib-2.0.0.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "@executable_path/../Resources/lib/libintl.8.dylib" Resources/lib/libglib-2.0.0.dylib

install_name_tool -change "/usr/local/opt/libsigc++/lib/libsigc-2.0.0.dylib" "@executable_path/../Resources/lib/libsigc-2.0.0.dylib" Resources/lib/libglibmm-2.4.1.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgobject-2.0.0.dylib" "@executable_path/../Resources/lib/libgobject-2.0.0.dylib" Resources/lib/libglibmm-2.4.1.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgmodule-2.0.0.dylib" "@executable_path/../Resources/lib/libgmodule-2.0.0.dylib" Resources/lib/libglibmm-2.4.1.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "@executable_path/../Resources/lib/libglib-2.0.0.dylib" Resources/lib/libglibmm-2.4.1.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "@executable_path/../Resources/lib/libintl.8.dylib" Resources/lib/libglibmm-2.4.1.dylib

install_name_tool -change "/usr/local/Cellar/glib/2.52.3/lib/libglib-2.0.0.dylib" "@executable_path/../Resources/lib/libglib-2.0.0.dylib" Resources/lib/libgmodule-2.0.0.dylib
install_name_tool -change "/usr/local/opt/pcre/lib/libpcre.1.dylib" "@executable_path/../Resources/lib/libpcre.1.dylib" Resources/lib/libgmodule-2.0.0.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "@executable_path/../Resources/lib/libintl.8.dylib" Resources/lib/libgmodule-2.0.0.dylib

install_name_tool -change "/usr/local/Cellar/glib/2.52.3/lib/libglib-2.0.0.dylib" "@executable_path/../Resources/lib/libglib-2.0.0.dylib" Resources/lib/libgobject-2.0.0.dylib
install_name_tool -change "/usr/local/opt/pcre/lib/libpcre.1.dylib" "@executable_path/../Resources/lib/libpcre.1.dylib" Resources/lib/libgobject-2.0.0.dylib
install_name_tool -change "/usr/local/opt/libffi/lib/libffi.6.dylib" "@executable_path/../Resources/lib/libffi.6.dylib" Resources/lib/libgobject-2.0.0.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "@executable_path/../Resources/lib/libintl.8.dylib" Resources/lib/libgobject-2.0.0.dylib

install_name_tool -change "/usr/local/Cellar/glib/2.52.3/lib/libglib-2.0.0.dylib" "@executable_path/../Resources/lib/libglib-2.0.0.dylib" Resources/lib/libgthread-2.0.0.dylib
install_name_tool -change "/usr/local/opt/pcre/lib/libpcre.1.dylib" "@executable_path/../Resources/lib/libpcre.1.dylib" Resources/lib/libgthread-2.0.0.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "@executable_path/../Resources/lib/libintl.8.dylib" Resources/lib/libgthread-2.0.0.dylib

install_name_tool -change "/usr/local/Cellar/gtk+3/3.22.17/lib/libgdk-3.0.dylib" "@executable_path/../Resources/lib/libgdk-3.0.dylib" Resources/lib/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgmodule-2.0.0.dylib" "@executable_path/../Resources/lib/libgmodule-2.0.0.dylib" Resources/lib/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/pango/lib/libpangocairo-1.0.0.dylib" "@executable_path/../Resources/lib/libpangocairo-1.0.0.dylib" Resources/lib/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/pango/lib/libpango-1.0.0.dylib" "@executable_path/../Resources/lib/libpango-1.0.0.dylib" Resources/lib/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/cairo/lib/libcairo-gobject.2.dylib" "@executable_path/../Resources/lib/libcairo-gobject.2.dylib" Resources/lib/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/cairo/lib/libcairo.2.dylib" "@executable_path/../Resources/lib/libcairo.2.dylib" Resources/lib/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/gdk-pixbuf/lib/libgdk_pixbuf-2.0.0.dylib" "@executable_path/../Resources/lib/libgdk_pixbuf-2.0.0.dylib" Resources/lib/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/atk/lib/libatk-1.0.0.dylib" "@executable_path/../Resources/lib/libatk-1.0.0.dylib" Resources/lib/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/libepoxy/lib/libepoxy.dylib" "@executable_path/../Resources/lib/libepoxy.dylib" Resources/lib/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgio-2.0.0.dylib" "@executable_path/../Resources/lib/libgio-2.0.0.dylib" Resources/lib/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgobject-2.0.0.dylib" "@executable_path/../Resources/lib/libgobject-2.0.0.dylib" Resources/lib/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "@executable_path/../Resources/lib/libglib-2.0.0.dylib" Resources/lib/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "@executable_path/../Resources/lib/libintl.8.dylib" Resources/lib/libgtk-3.0.dylib

install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "@executable_path/../Resources/lib/libglib-2.0.0.dylib" Resources/lib/libharfbuzz.0.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "@executable_path/../Resources/lib/libintl.8.dylib" Resources/lib/libharfbuzz.0.dylib
install_name_tool -change "/usr/local/opt/freetype/lib/libfreetype.6.dylib" "@executable_path/../Resources/lib/libfreetype.6.dylib" Resources/lib/libharfbuzz.0.dylib
install_name_tool -change "/usr/local/opt/graphite2/lib/libgraphite2.3.dylib" "@executable_path/../Resources/lib/libgraphite2.3.dylib" Resources/lib/libharfbuzz.0.dylib

install_name_tool -change "/usr/local/opt/glib/lib/libgobject-2.0.0.dylib" "@executable_path/../Resources/lib/libgobject-2.0.0.dylib" Resources/lib/libpango-1.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgthread-2.0.0.dylib" "@executable_path/../Resources/lib/libgthread-2.0.0.dylib" Resources/lib/libpango-1.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "@executable_path/../Resources/lib/libglib-2.0.0.dylib" Resources/lib/libpango-1.0.0.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "@executable_path/../Resources/lib/libintl.8.dylib" Resources/lib/libpango-1.0.0.dylib

install_name_tool -change "/usr/local/Cellar/pango/1.40.7/lib/libpango-1.0.0.dylib" "@executable_path/../Resources/lib/libpango-1.0.0.dylib" Resources/lib/libpangocairo-1.0.0.dylib
install_name_tool -change "/usr/local/opt/cairo/lib/libcairo.2.dylib" "@executable_path/../Resources/lib/libcairo.2.dylib" Resources/lib/libpangocairo-1.0.0.dylib
install_name_tool -change "/usr/local/Cellar/pango/1.40.7/lib/libpangoft2-1.0.0.dylib" "@executable_path/../Resources/lib/libpangoft2-1.0.0.dylib" Resources/lib/libpangocairo-1.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgobject-2.0.0.dylib" "@executable_path/../Resources/lib/libgobject-2.0.0.dylib" Resources/lib/libpangocairo-1.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgthread-2.0.0.dylib" "@executable_path/../Resources/lib/libgthread-2.0.0.dylib" Resources/lib/libpangocairo-1.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "@executable_path/../Resources/lib/libglib-2.0.0.dylib" Resources/lib/libpangocairo-1.0.0.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "@executable_path/../Resources/lib/libintl.8.dylib" Resources/lib/libpangocairo-1.0.0.dylib
install_name_tool -change "/usr/local/opt/harfbuzz/lib/libharfbuzz.0.dylib" "@executable_path/../Resources/lib/libharfbuzz.0.dylib" Resources/lib/libpangocairo-1.0.0.dylib
install_name_tool -change "/usr/local/opt/fontconfig/lib/libfontconfig.1.dylib" "@executable_path/../Resources/lib/libfontconfig.1.dylib" Resources/lib/libpangocairo-1.0.0.dylib
install_name_tool -change "/usr/local/opt/freetype/lib/libfreetype.6.dylib" "@executable_path/../Resources/lib/libfreetype.6.dylib" Resources/lib/libpangocairo-1.0.0.dylib

install_name_tool -change "/usr/local/Cellar/pango/1.40.7/lib/libpango-1.0.0.dylib" "@executable_path/../Resources/lib/libpango-1.0.0.dylib" Resources/lib/libpangoft2-1.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgobject-2.0.0.dylib" "@executable_path/../Resources/lib/libgobject-2.0.0.dylib" Resources/lib/libpangoft2-1.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgthread-2.0.0.dylib" "@executable_path/../Resources/lib/libgthread-2.0.0.dylib" Resources/lib/libpangoft2-1.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "@executable_path/../Resources/lib/libglib-2.0.0.dylib" Resources/lib/libpangoft2-1.0.0.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "@executable_path/../Resources/lib/libintl.8.dylib" Resources/lib/libpangoft2-1.0.0.dylib
install_name_tool -change "/usr/local/opt/harfbuzz/lib/libharfbuzz.0.dylib" "@executable_path/../Resources/lib/libharfbuzz.0.dylib" Resources/lib/libpangoft2-1.0.0.dylib
install_name_tool -change "/usr/local/opt/fontconfig/lib/libfontconfig.1.dylib" "@executable_path/../Resources/lib/libfontconfig.1.dylib" Resources/lib/libpangoft2-1.0.0.dylib
install_name_tool -change "/usr/local/opt/freetype/lib/libfreetype.6.dylib" "@executable_path/../Resources/lib/libfreetype.6.dylib" Resources/lib/libpangoft2-1.0.0.dylib

install_name_tool -change "/usr/local/opt/glibmm/lib/libglibmm-2.4.1.dylib" "@executable_path/../Resources/lib/libglibmm-2.4.1.dylib" Resources/lib/libpangomm-1.4.1.dylib
install_name_tool -change "/usr/local/opt/cairomm/lib/libcairomm-1.0.1.dylib" "@executable_path/../Resources/lib/libcairomm-1.0.1.dylib" Resources/lib/libpangomm-1.4.1.dylib
install_name_tool -change "/usr/local/opt/libsigc++/lib/libsigc-2.0.0.dylib" "@executable_path/../Resources/lib/libsigc-2.0.0.dylib" Resources/lib/libpangomm-1.4.1.dylib
install_name_tool -change "/usr/local/opt/pango/lib/libpangocairo-1.0.0.dylib" "@executable_path/../Resources/lib/libpangocairo-1.0.0.dylib" Resources/lib/libpangomm-1.4.1.dylib
install_name_tool -change "/usr/local/opt/pango/lib/libpango-1.0.0.dylib" "@executable_path/../Resources/lib/libpango-1.0.0.dylib" Resources/lib/libpangomm-1.4.1.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgobject-2.0.0.dylib" "@executable_path/../Resources/lib/libgobject-2.0.0.dylib" Resources/lib/libpangomm-1.4.1.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "@executable_path/../Resources/lib/libglib-2.0.0.dylib" Resources/lib/libpangomm-1.4.1.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "@executable_path/../Resources/lib/libintl.8.dylib" Resources/lib/libpangomm-1.4.1.dylib
install_name_tool -change "/usr/local/opt/cairo/lib/libcairo.2.dylib" "@executable_path/../Resources/lib/libcairo.2.dylib" Resources/lib/libpangomm-1.4.1.dylib

Now make sure the old dylibs are deleted and run the bash script with this command:
$ sudo ./copyDylibs
NOTE: You need to fill in your password after running the command. If you don't add the sudo, you will get errors

The dylibs are now in the right place and know where to look for information. It is possible your dylibs have more dependencies, but won't show up with otool, this is because they are not dylib files. For the GTK+3 library, as example, there are .so files the app needs, but there is no clear indication it needs those files. There is big chance your library also uses .so files, a little explanation on .so files can be found here. NOTE: Your .so probably also has relative paths to files, so use otool -L and install_name_tool -change to set the correct paths.

At this point it could go anywhere, some libraries require you to have files in the bin folder and others to have some files in the share folder. What worked for me was to look up an existing app that uses the same library as I did and compare. If you use the GTK+3 library, you could check out my Minesweeper to see how I've done things. I believe Gimp also uses GTK, altough I'm pretty sure it's an older version of GTK and written in python.

One thing you do still have to do is to tell the executable to use your copied dylibs. So for that I created a new bash file, and put install_name_tool -change for each dependency.

4. Info.plist

The Info.plist is an REQUIRED XML file containing information about your application. Open your terminal and create the Info.plist:
$ cd ~/Desktop
$ touch Info.plist
Now open it up in your favourite text editor. Inside this file there are three required keys: the executable, the name of the application and the icon of the bundle (I will come back later on the icon, just make sure you use the .icns extension on it). A really basic file lookes like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <!--The executable-->
  <key>CFBundleExecutable</key>
  <string>app</string><!--This should be the name of the executable inside your MacOS folder-->

  <!--Company name-->
  <key>CFBundleIdentifier</key>
  <string>com.mycompany.www</string>

  <!--Desired application name-->
  <key>CFBundleName</key>
  <string>My App</string>

  <!--icons file, located in the Resources folder-->
  <key>CFBundleIconFile</key>
  <string>logo.icns</string>
</dict>
</plist>

Remember when I told you to put your executable inside your MacOS folder and then put the executable name inside the Info.plist? We are going to change it. When working with libraries, you sometimes have to set environment variables. Take the .so files my GTK+ application uses as an example, these files are loaded from the GDK_PIXBUF_MODULE_FILE path. We are going to replace our executable with a shell script, so we can set some variables before opening our app.

First, rename your executable. I like to just add "-bin" behind the name. Now open your terminal and create the new executable with the name you used in the Info.plist:
$ cd ~/Desktop/myapp.app/Contents/MacOS
$ touch myapp
$ chmod +x myapp
Open it with your favourite text editor.

You start off with setting some variables, this will make our live a little easier. After these variables, it will be different for every library again. You just have to remember you can set the variables by typing:
export SYSTEM_VARIABLE="$bundle_etc"
where $bundle_etc could be any variable.

My shell script looked like this:

#!/bin/sh
name=`basename "$0"`
tmp="`pwd`/$0"
tmp=`dirname "$tmp"`
tmp=`dirname "$tmp"`
bundle=`dirname "$tmp"`

bundle_contents="$bundle"/Contents
bundle_res="$bundle_contents"/Resources
bundle_lib="$bundle_res"/lib
bundle_bin="$bundle_res"/bin
bundle_data="$bundle_res"/share
bundle_etc="$bundle_res"/etc

export DYLD_LIBRARY_PATH="$bundle_lib"
export XDG_CONFIG_DIRS="$bundle_etc"/xdg
export XDG_DATA_DIRS="$bundle_data"

export GTK_DATA_PREFIX="$bundle_res"
export GTK_EXE_PREFIX="$bundle_res"
export GTK_PATH="$bundle_res"

export GTK3_RC_FILES="$bundle_etc/gtk-3.0/gtkrc"
export GTK_IM_MODULE_FILE="$bundle_etc/gtk-3.0/gtk.immodules"
export GDK_PIXBUF_MODULE_FILE="$bundle_etc/gtk-3.0/gdk-pixbuf.loaders"
export GDK_PIXBUF_MODULEDIR="$bundle_lib/gdk-pixbuf-2.0/2.10.0/loaders"

if test -f "$bundle_lib/charset.alias"; then
 export CHARSETALIASDIR="$bundle_lib"
fi

EXTRA_ARGS=
if /bin/expr "x$1" : '^x-psn_' > /dev/null; then
 shift 1
fi

exec "$bundle_contents/MacOS/$name-bin" "$@" $EXTRA_ARGS

The final thing is to add the icon. The icon needs to be located inside the Resources folder (not inside any subfolder) and needs the .icns extension. I used this site to convert my png to .icns. Put this in the Resources folder and make sure it has the same name as the plist says.

This was finally it! You can now double click the application to run the app. If your image uses any images/stylesheets/whatever, be sure to put them inside the Resources folder (those files may be inside a subfolder). If you want to learn how to load in resource files with bundles, checkout Load recources from mac appbundle