My setup:
I'm looking into the possibility of shipping apps on macOS using GTK+.
Unfortunately, the whole process seems daunting to me according to GTK+'s macOS build/bundle/integration guide:
This guide showed various pitfalls of the gigantic script and its environment tweaks, which could mess up the entire OS. The suggested approach of opening a new user account seems not very practical, either.
This all-in-one script approach, excluding any talks about Xcode, is quite scary as it makes me wonder how fast it could keep up with Apple's movement, as Xcode with its toolchain upgrades every few months. Xcode is the only environment that I feel comfortable when it comes to project organization and app bundling.
For one, would it be possible to use Apple's more mature dynamic linking system, i.e., Frameworks, instead of the .dylib approach? I couldn't find any resources or discussions about linking GTK+ through Frameworks, or even using Xcode build system for the job.
Any tips would be appreciated.
UPDATE
My first attempt of bootstrapping the macOS build system for GTK+ just failed at a cmake dependency step, and the script does not even offer an "abort" option. I had to Ctrl-C it: Another negative experience.
UPDATE 2
Progress: I managed to create a Hello-World command-line program in Xcode 10.3 and make it run. Basically I steered clear of the jhbuild route that GNOME recommends.
Things I did:
brew install pygobject3 gtk+3
pkg-config --cflags gtk+-3.0
, and add the result to Other C Flags
of Xcode target's Build Settings
.pkg-config --libs gtk+-3.0
, and add the result to Other Linker Flags
.This is so much easier than the GNOME recommendation. Mind you that its latest edits were done in 2019, so they likely still recommend it.
I'm going to try bundling today.
So after messing around with GTK+ and Xcode 10 toolchain for a whole day, I finally got more confidence in the idea of shipping macOS app built with GTK+. The hardest part for me was to figure out how to make a self-contained app bundle, especially how to deal with the .dylib hell on macOS (Mojave) with Xcode toolchain (10.3). The online resources are incredibly inconsistent on this topic. I was tipped by many tutorials to fix things here and there. However, each of them has a slightly skewed portion that's just enough to throw me off track one minute later. But I'm glad that things are a lot easier than the GNOME WIKI described, with Xcode handling a lot of heavy-lifting.
Here are the things I did to make a hello-world GNOME app based on their getting-started example and make it run on another Mac without any pre-installed dependency, with brief remarks:
Install GTK+
brew install
pygobject3 gtk+3
;Setup Xcode project and finishing coding
Write your GTK+ app code in main.m
(I actually made it main.mm
for possible C++ mix-in). Instead of returning the result of NSApplicationMain()
. You return that of g_application_run()
.
Keep all the other supporting source files the way they are.
Set a proper macOS Deployment Target
: I make it macOS 10.10
for reasonable compatibility. The other test machine I have runs High Sierra.
Here is my main.mm
.
//
// main.mm
// hello_gtk
//
// Created by Me on 2019-08-11.
// Copyright © 2019 Me. All rights reserved.
//
#include <iostream>
#import <Cocoa/Cocoa.h>
#include <gtk/gtk.h>
// callback function which is called when button is clicked
static void on_button_clicked(GtkButton *btn, gpointer data) {
// change button label when it's clicked
gtk_button_set_label(btn, "Hello World");
}
// callback function which is called when application is first started
static void on_app_activate(GApplication *app, gpointer data) {
// create a new application window for the application
// GtkApplication is sub-class of GApplication
// downcast GApplication* to GtkApplication* with GTK_APPLICATION() macro
GtkWidget *window = gtk_application_window_new(GTK_APPLICATION(app));
// a simple push button
GtkWidget *btn = gtk_button_new_with_label("Click Me!");
// connect the event-handler for "clicked" signal of button
g_signal_connect(btn, "clicked", G_CALLBACK(on_button_clicked), NULL);
// add the button to the window
gtk_container_add(GTK_CONTAINER(window), btn);
// display the window
gtk_widget_show_all(GTK_WIDGET(window));
}
int main(int argc, char *argv[]) {
// create new GtkApplication with an unique application ID
GtkApplication *app = gtk_application_new(
"org.gtkmm.example.HelloApp",
G_APPLICATION_FLAGS_NONE
);
// connect the event-handler for "activate" signal of GApplication
// G_CALLBACK() macro is used to cast the callback function pointer
// to generic void pointer
g_signal_connect(app, "activate", G_CALLBACK(on_app_activate), NULL);
// start the application, terminate by closing the window
// GtkApplication* is upcast to GApplication* with G_APPLICATION() macro
int status = g_application_run(G_APPLICATION(app), argc, argv);
// deallocate the application object
g_object_unref(app);
// return status;
return status;
}
Configure Xcode project to compile and link
Here you must link against the Homebrew GTK+. Don't do your .dylib tweaks just yet.
pkg-config --cflags gtk+-3.0
, and add the result to Other C Flags
of Xcode target's Build Settings
.pkg-config --libs gtk+-3.0
, and add the result to Other Linker Flags
.Link Binary with Libraries
Build Phase. In my case: Carbon
(!), Foundation
, CoreGraphics
, Cocoa
.Fix embedded paths in .dylibs
This is a topic much discussed about. People even made tools (including the Jhbuild, and this one) to do the job. Unfortunately, none of these tools or tips worked for me out of the box. My guess is that it's just too hard for hobbyist bloggers to keep up with Apple who has a gift to deprecate things invented a year ago, and the gurus are busy with more interesting and important missions. All the tips got the theories right though, so I finally got it working by following the idea of this one. Here comes my take:
Run Script
Build Phase right after Link Binary with Libraries
. I use a separate script file, and only do sh +x ${PROJECT_DIR}/${PRODUCT_NAME}/deploy_libs.sh
for maintainability.Here is the actual script I wrote:
#! /bin/sh
LibTargetDir="${BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/lib"
Exec=${BUILD_DIR}/${EXECUTABLE_PATH}
RelLibDir="@executable_path/../Frameworks/lib"
pwd
mkdir -p "${LibTargetDir}" 2>&1 > /dev/null
#
# Copy Homebrew libs to hello_world.app/Contents/Frameworks/lib/
#
# Direct dependencies of the executable found out about by otool.
cp /usr/local/opt/gtk+3/lib/libgtk-3.0.dylib "${LibTargetDir}"
cp /usr/local/opt/gtk+3/lib/libgdk-3.0.dylib "${LibTargetDir}"
cp /usr/local/opt/pango/lib/libpangocairo-1.0.0.dylib "${LibTargetDir}"
cp /usr/local/opt/pango/lib/libpango-1.0.0.dylib "${LibTargetDir}"
cp /usr/local/opt/harfbuzz/lib/libharfbuzz.0.dylib "${LibTargetDir}"
cp /usr/local/opt/atk/lib/libatk-1.0.0.dylib "${LibTargetDir}"
cp /usr/local/opt/cairo/lib/libcairo-gobject.2.dylib "${LibTargetDir}"
cp /usr/local/opt/cairo/lib/libcairo.2.dylib "${LibTargetDir}"
cp /usr/local/opt/gdk-pixbuf/lib/libgdk_pixbuf-2.0.0.dylib "${LibTargetDir}"
cp /usr/local/opt/glib/lib/libgio-2.0.0.dylib "${LibTargetDir}"
cp /usr/local/opt/glib/lib/libgobject-2.0.0.dylib "${LibTargetDir}"
cp /usr/local/opt/glib/lib/libglib-2.0.0.dylib "${LibTargetDir}"
cp /usr/local/opt/gettext/lib/libintl.8.dylib "${LibTargetDir}"
# 2nd-order dependencies by the above libs.
cp /usr/local/opt/libepoxy/lib/libepoxy.0.dylib "${LibTargetDir}"
cp /usr/local/opt/fontconfig/lib/libfontconfig.1.dylib "${LibTargetDir}"
cp /usr/local/opt/freetype/lib/libfreetype.6.dylib "${LibTargetDir}"
cp /usr/local//Cellar/libffi/3.2.1/lib/libffi.6.dylib "${LibTargetDir}"
cp /usr/local/opt/fribidi/lib/libfribidi.0.dylib "${LibTargetDir}"
cp /usr/local/opt/glib/lib/libgmodule-2.0.0.dylib "${LibTargetDir}"
cp /usr/local/opt/graphite2/lib/libgraphite2.3.dylib "${LibTargetDir}"
cp /usr/local/Cellar/pango/1.44.5/lib/libpangoft2-1.0.0.dylib "${LibTargetDir}"
cp /usr/local/opt/pixman/lib/libpixman-1.0.dylib "${LibTargetDir}"
cp /usr/local/opt/libpng/lib/libpng16.16.dylib "${LibTargetDir}"
#
# Make them writable for the fixes. The libs are read-only fresh out of Homebrew .
#
chmod -R +w "${LibTargetDir}"/*
#
# Fix .dylib execution paths for the well-known reason: Paths are hardcoded.
#
# Fix executable dependencies.
install_name_tool -change "/usr/local/opt/gtk+3/lib/libgtk-3.0.dylib" "${RelLibDir}/libgtk-3.0.dylib" "${Exec}"
install_name_tool -change "/usr/local/opt/gtk+3/lib/libgdk-3.0.dylib" "${RelLibDir}/libgdk-3.0.dylib" "${Exec}"
install_name_tool -change "/usr/local/opt/pango/lib/libpangocairo-1.0.0.dylib" "${RelLibDir}/libpangocairo-1.0.0.dylib" "${Exec}"
install_name_tool -change "/usr/local/opt/pango/lib/libpango-1.0.0.dylib" "${RelLibDir}/libpango-1.0.0.dylib" "${Exec}"
install_name_tool -change "/usr/local/opt/harfbuzz/lib/libharfbuzz.0.dylib" "${RelLibDir}/libharfbuzz.0.dylib" "${Exec}"
install_name_tool -change "/usr/local/opt/atk/lib/libatk-1.0.0.dylib" "${RelLibDir}/libatk-1.0.0.dylib" "${Exec}"
install_name_tool -change "/usr/local/opt/cairo/lib/libcairo-gobject.2.dylib" "${RelLibDir}/libcairo-gobject.2.dylib" "${Exec}"
install_name_tool -change "/usr/local/opt/cairo/lib/libcairo.2.dylib" "${RelLibDir}/libcairo.2.dylib" "${Exec}"
install_name_tool -change "/usr/local/opt/gdk-pixbuf/lib/libgdk_pixbuf-2.0.0.dylib" "${RelLibDir}/libgdk_pixbuf-2.0.0.dylib" "${Exec}"
install_name_tool -change "/usr/local/opt/glib/lib/libgio-2.0.0.dylib" "${RelLibDir}/libgio-2.0.0.dylib" "${Exec}"
install_name_tool -change "/usr/local/opt/glib/lib/libgobject-2.0.0.dylib" "${RelLibDir}/libgobject-2.0.0.dylib" "${Exec}"
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "${RelLibDir}/libglib-2.0.0.dylib" "${Exec}"
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "${RelLibDir}/libintl.8.dylib" "${Exec}"
# Fix dependencies of dependencies
install_name_tool -change "/usr/local/Cellar/gtk+3/3.24.10/lib/libgdk-3.0.dylib" "${RelLibDir}/libgdk-3.0.dylib" "${LibTargetDir}"/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgmodule-2.0.0.dylib" "${RelLibDir}/libgmodule-2.0.0.dylib" "${LibTargetDir}"/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "${RelLibDir}/libglib-2.0.0.dylib" "${LibTargetDir}"/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "${RelLibDir}/libintl.8.dylib" "${LibTargetDir}"/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgobject-2.0.0.dylib" "${RelLibDir}/libgobject-2.0.0.dylib" "${LibTargetDir}"/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgio-2.0.0.dylib" "${RelLibDir}/libgio-2.0.0.dylib" "${LibTargetDir}"/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/pango/lib/libpangocairo-1.0.0.dylib" "${RelLibDir}/libpangocairo-1.0.0.dylib" "${LibTargetDir}"/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/pango/lib/libpango-1.0.0.dylib" "${RelLibDir}/libpango-1.0.0.dylib" "${LibTargetDir}"/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/harfbuzz/lib/libharfbuzz.0.dylib" "${RelLibDir}/libharfbuzz.0.dylib" "${LibTargetDir}"/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/cairo/lib/libcairo.2.dylib" "${RelLibDir}/libcairo.2.dylib" "${LibTargetDir}"/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/pango/lib/libpangoft2-1.0.0.dylib" "${RelLibDir}/libpangoft2-1.0.0.dylib" "${LibTargetDir}"/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/freetype/lib/libfreetype.6.dylib" "${RelLibDir}/libfreetype.6.dylib" "${LibTargetDir}"/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/fribidi/lib/libfribidi.0.dylib" "${RelLibDir}/libfribidi.0.dylib" "${LibTargetDir}"/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/cairo/lib/libcairo-gobject.2.dylib" "${RelLibDir}/libcairo-gobject.2.dylib" "${LibTargetDir}"/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/gdk-pixbuf/lib/libgdk_pixbuf-2.0.0.dylib" "${RelLibDir}/libgdk_pixbuf-2.0.0.dylib" "${LibTargetDir}"/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/atk/lib/libatk-1.0.0.dylib" "${RelLibDir}/libatk-1.0.0.dylib" "${LibTargetDir}"/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/libepoxy/lib/libepoxy.0.dylib" "${RelLibDir}/libepoxy.0.dylib" "${LibTargetDir}"/libgtk-3.0.dylib
install_name_tool -change "/usr/local/opt/gdk-pixbuf/lib/libgdk_pixbuf-2.0.0.dylib" "${RelLibDir}/libgdk_pixbuf-2.0.0.dylib" "${LibTargetDir}"/libgdk-3.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgobject-2.0.0.dylib" "${RelLibDir}/libgobject-2.0.0.dylib" "${LibTargetDir}"/libgdk-3.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "${RelLibDir}/libglib-2.0.0.dylib" "${LibTargetDir}"/libgdk-3.0.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "${RelLibDir}/libintl.8.dylib" "${LibTargetDir}"/libgdk-3.0.dylib
install_name_tool -change "/usr/local/opt/cairo/lib/libcairo-gobject.2.dylib" "${RelLibDir}/libcairo-gobject.2.dylib" "${LibTargetDir}"/libgdk-3.0.dylib
install_name_tool -change "/usr/local/opt/pango/lib/libpango-1.0.0.dylib" "${RelLibDir}/libpango-1.0.0.dylib" "${LibTargetDir}"/libgdk-3.0.dylib
install_name_tool -change "/usr/local/opt/fribidi/lib/libfribidi.0.dylib" "${RelLibDir}/libfribidi.0.dylib" "${LibTargetDir}"/libgdk-3.0.dylib
install_name_tool -change "/usr/local/opt/cairo/lib/libcairo-gobject.2.dylib" "${RelLibDir}/libcairo-gobject.2.dylib" "${LibTargetDir}"/libgdk-3.0.dylib
install_name_tool -change "/usr/local/opt/libepoxy/lib/libepoxy.0.dylib" "${RelLibDir}/libepoxy.0.dylib" "${LibTargetDir}"/libgdk-3.0.dylib
install_name_tool -change "/usr/local/opt/pango/lib/libpangocairo-1.0.0.dylib" "${RelLibDir}/libpangocairo-1.0.0.dylib" "${LibTargetDir}"/libgdk-3.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgio-2.0.0.dylib" "${RelLibDir}/libgio-2.0.0.dylib" "${LibTargetDir}"/libgdk-3.0.dylib
install_name_tool -change "/usr/local/Cellar/pango/1.44.5/lib/libpango-1.0.0.dylib" "${RelLibDir}/libpango-1.0.0.dylib" "${LibTargetDir}"/libpangocairo-1.0.0.dylib
install_name_tool -change "/usr/local/Cellar/pango/1.44.5/lib/libpangoft2-1.0.0.dylib" "${RelLibDir}/libpangoft2-1.0.0.dylib" "${LibTargetDir}"/libpangocairo-1.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "${RelLibDir}/libglib-2.0.0.dylib" "${LibTargetDir}"/libpangocairo-1.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgobject-2.0.0.dylib" "${RelLibDir}/libgobject-2.0.0.dylib" "${LibTargetDir}"/libpangocairo-1.0.0.dylib
install_name_tool -change "/usr/local/opt/harfbuzz/lib/libharfbuzz.0.dylib" "${RelLibDir}/libharfbuzz.0.dylib" "${LibTargetDir}"/libpangocairo-1.0.0.dylib
install_name_tool -change "/usr/local/opt/fontconfig/lib/libfontconfig.1.dylib" "${RelLibDir}/libfontconfig.1.dylib" "${LibTargetDir}"/libpangocairo-1.0.0.dylib
install_name_tool -change "/usr/local/opt/cairo/lib/libcairo.2.dylib" "${RelLibDir}/libcairo.2.dylib" "${LibTargetDir}"/libpangocairo-1.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "${RelLibDir}/libglib-2.0.0.dylib" "${LibTargetDir}"/libpango-1.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgobject-2.0.0.dylib" "${RelLibDir}/libgobject-2.0.0.dylib" "${LibTargetDir}"/libpango-1.0.0.dylib
install_name_tool -change "/usr/local/opt/fribidi/lib/libfribidi.0.dylib" "${RelLibDir}/libfribidi.0.dylib" "${LibTargetDir}"/libpango-1.0.0.dylib
install_name_tool -change "/usr/local/opt/harfbuzz/lib/libharfbuzz.0.dylib" "${RelLibDir}/libharfbuzz.0.dylib" "${LibTargetDir}"/libpango-1.0.0.dylib
install_name_tool -change "/usr/local/opt/harfbuzz/lib/libharfbuzz.0.dylib" "${RelLibDir}/libharfbuzz.0.dylib" "${LibTargetDir}"/libharfbuzz.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "${RelLibDir}/libglib-2.0.0.dylib" "${LibTargetDir}"/libharfbuzz.0.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "${RelLibDir}/libintl.8.dylib" "${LibTargetDir}"/libharfbuzz.0.dylib
install_name_tool -change "/usr/local/opt/freetype/lib/libfreetype.6.dylib" "${RelLibDir}/libfreetype.6.dylib" "${LibTargetDir}"/libharfbuzz.0.dylib
install_name_tool -change "/usr/local/opt/graphite2/lib/libgraphite2.3.dylib" "${RelLibDir}/libgraphite2.3.dylib" "${LibTargetDir}"/libharfbuzz.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "${RelLibDir}/libglib-2.0.0.dylib" "${LibTargetDir}"/libatk-1.0.0.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "${RelLibDir}/libintl.8.dylib"${LibTargetDir}/libatk-1.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgobject-2.0.0.dylib" "${RelLibDir}/libgobject-2.0.0.dylib" "${LibTargetDir}"/libatk-1.0.0.dylib
install_name_tool -change "/usr/local/opt/cairo/lib/libcairo.2.dylib" "${RelLibDir}/libcairo.2.dylib" "${LibTargetDir}"/libcairo-gobject.2.dylib
install_name_tool -change "/usr/local/opt/pixman/lib/libpixman-1.0.dylib" "${RelLibDir}/libpixman-1.0.dylib" "${LibTargetDir}"/libcairo-gobject.2.dylib
install_name_tool -change "/usr/local/opt/fontconfig/lib/libfontconfig.1.dylib" "${RelLibDir}/libfontconfig.1.dylib" "${LibTargetDir}"/libcairo-gobject.2.dylib
install_name_tool -change "/usr/local/opt/freetype/lib/libfreetype.6.dylib" "${RelLibDir}/libfreetype.6.dylib" "${LibTargetDir}"/libcairo-gobject.2.dylib
install_name_tool -change "/usr/local/opt/libpng/lib/libpng16.16.dylib" "${RelLibDir}/libpng16.16.dylib" "${LibTargetDir}"/libcairo-gobject.2.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgobject-2.0.0.dylib" "${RelLibDir}/libgobject-2.0.0.dylib" "${LibTargetDir}"/libcairo-gobject.2.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "${RelLibDir}/libglib-2.0.0.dylib" "${LibTargetDir}"/libcairo-gobject.2.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "${RelLibDir}/libintl.8.dylib" "${LibTargetDir}"/libcairo-gobject.2.dylib
install_name_tool -change "/usr/local/opt/pixman/lib/libpixman-1.0.dylib" "${RelLibDir}/libpixman-1.0.dylib" "${LibTargetDir}"/libcairo.2.dylib
install_name_tool -change "/usr/local/opt/fontconfig/lib/libfontconfig.1.dylib" "${RelLibDir}/libfontconfig.1.dylib" "${LibTargetDir}"/libcairo.2.dylib
install_name_tool -change "/usr/local/opt/freetype/lib/libfreetype.6.dylib" "${RelLibDir}/libfreetype.6.dylib" "${LibTargetDir}"/libcairo.2.dylib
install_name_tool -change "/usr/local/opt/libpng/lib/libpng16.16.dylib" "${RelLibDir}/libpng16.16.dylib" "${LibTargetDir}"/libcairo.2.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgobject-2.0.0.dylib" "${RelLibDir}/libgobject-2.0.0.dylib" "${LibTargetDir}"/libgdk_pixbuf-2.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "${RelLibDir}/libglib-2.0.0.dylib" "${LibTargetDir}"/libgdk_pixbuf-2.0.0.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "${RelLibDir}/libintl.8.dylib" "${LibTargetDir}"/libgdk_pixbuf-2.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgmodule-2.0.0.dylib" "${RelLibDir}/libgmodule-2.0.0.dylib" "${LibTargetDir}"/libgdk_pixbuf-2.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libgio-2.0.0.dylib" "${RelLibDir}/libgio-2.0.0.dylib" "${LibTargetDir}"/libgdk_pixbuf-2.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "${RelLibDir}/libglib-2.0.0.dylib" "${LibTargetDir}"/libgobject-2.0.0.dylib
install_name_tool -change "/usr/local/opt/libffi/lib/libffi.6.dylib" "${RelLibDir}/libffi.6.dylib" "${LibTargetDir}"/libgobject-2.0.0.dylib
install_name_tool -change "/usr/local/opt/pcre/lib/libpcre.1.dylib" "${RelLibDir}/libpcre.1.dylib" "${LibTargetDir}"/libglib-2.0.0.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "${RelLibDir}/libintl.8.dylib" "${LibTargetDir}"/libglib-2.0.0.dylib
install_name_tool -change "/usr/local/Cellar/glib/2.60.6/lib/libglib-2.0.0.dylib" "${RelLibDir}/libglib-2.0.0.dylib" "${LibTargetDir}"/libgmodule-2.0.0.dylib
install_name_tool -change "/usr/local/Cellar/glib/2.60.6/lib/libgobject-2.0.0.dylib" "${RelLibDir}/libgobject-2.0.0.dylib" "${LibTargetDir}"/libgio-2.0.0.dylib
install_name_tool -change "/usr/local/Cellar/glib/2.60.6/lib/libglib-2.0.0.dylib" "${RelLibDir}/libglib-2.0.0.dylib" "${LibTargetDir}"/libgio-2.0.0.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "${RelLibDir}/libintl.8.dylib" "${LibTargetDir}"/libgio-2.0.0.dylib
install_name_tool -change "/usr/local/Cellar/glib/2.60.6/lib/libgmodule-2.0.0.dylib" "${RelLibDir}/libgmodule-2.0.0.dylib" "${LibTargetDir}"/libgio-2.0.0.dylib
install_name_tool -change "/usr/local/opt/harfbuzz/lib/libharfbuzz.0.dylib" "${RelLibDir}/libharfbuzz.0.dylib" "${LibTargetDir}"/libpangoft2-1.0.0.dylib
install_name_tool -change "/usr/local/Cellar/pango/1.44.5/lib/libpango-1.0.0.dylib" "${RelLibDir}/libpango-1.0.0.dylib" "${LibTargetDir}"/libpangoft2-1.0.0.dylib
install_name_tool -change "/usr/local/opt/glib/lib/libglib-2.0.0.dylib" "${RelLibDir}/libglib-2.0.0.dylib" "${LibTargetDir}"/libpangoft2-1.0.0.dylib
install_name_tool -change "/usr/local/opt/gettext/lib/libintl.8.dylib" "${RelLibDir}/libintl.8.dylib" "${LibTargetDir}"/libpangoft2-1.0.0.dylib
install_name_tool -change "/usr/local/opt/freetype/lib/libfreetype.6.dylib" "${RelLibDir}/libfreetype.6.dylib" "${LibTargetDir}"/libpangoft2-1.0.0.dylib
install_name_tool -change "/usr/local/opt/fontconfig/lib/libfontconfig.1.dylib" "${RelLibDir}/libfontconfig.1.dylib" "${LibTargetDir}"/libpangoft2-1.0.0.dylib
install_name_tool -change "/usr/local/opt/libpng/lib/libpng16.16.dylib" "${RelLibDir}/libpng16.16.dylib" "${LibTargetDir}"/libfreetype.6.dylib
install_name_tool -change "/usr/local/opt/freetype/lib/libfreetype.6.dylib" "${RelLibDir}/libfreetype.6.dylib" "${LibTargetDir}"/libfontconfig.1.dylib
echo "DONE"
Sorry for not writing for-loops with arrays, partly because you literally need to pinpoint every single dependency along the dependency tree until you reach a leaf lib, such as libfreetype
, which only depends on system libs, i.e., things under /usr/lib/
and /System/Library/
. Your only truthful friend is otool -L
. You'll stumble upon quirks such as:
/usr/local/opt
, others their source paths under /usr/local/Cellar
. You'll likely hit one or two DYLB-not-found error after shipping the bundle to another machine if you took symlinks by mistake. You want the physical libs for your install_name_tool
commands. Obviously, although the lib itself is always the first line in the otool
dependency report, you don't need to install_name_tool -change
it.
For bundling the libs, although Xcode Build Phases
comes with a Copy step, that is not what you need to copy your libs to the Framework folder because they require explicitly importing .dylib
files into your project, which would make it hard to distinguish between Debug/Release configurations later.
I beg to have a tool to automate this mess without luck. Guess I'll just have to write one, otherwise this brute-force approach will not scale.
Code-signing the binaries
All dylibs must be code-signed as submodules along with the app.
--deep
to Other Code Signing Flags
, in the Xcode project Build Settings;Code Signing Identity
to your team developer account.Info.plist
at all.Build, Run, and Deploy to other machines
Just build and run. The example should already be working on the dev machine.
Copy the entire app bundle hello_world.app
to another Mac machine, which has no Homebrew or other bags. The app should run successfully as well.
Build .dmg for deployment. It's the standard procedure so I'll skip it for now.
Hope this could help people who might be as clueless as I was at first. My next challenge would be to discover the gist of shipping PyGObject apps on top of GTK+. The worry-free procedure seems to be also buried in a huge desert.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With