使用 Xcode 为 macOS 发布 GTK+ 应用程序
Shipping GTK+ apps for macOS with Xcode
我的设置:
- macOS 莫哈韦
- Xcode10.3
我正在研究使用 GTK+ 在 macOS 上发布应用程序的可能性。
不幸的是,根据 GTK+ 的 macOS build/bundle/integration 指南,整个过程对我来说似乎令人生畏:
- https://wiki.gnome.org/Projects/GTK/OSX/Building
- https://wiki.gnome.org/Projects/GTK/OSX/Bundling
- https://wiki.gnome.org/Projects/GTK/OSX/Integration
本指南展示了巨大脚本的各种陷阱及其环境调整,这些调整可能会搞乱整个 OS。推荐的开新用户的方法好像也不是很实用。
这种 all-in-one 脚本方法,不包括任何关于 Xcode 的讨论,是相当可怕的,因为它让我想知道它能以多快的速度跟上 Apple 的发展,因为 Xcode工具链每隔几个月升级一次。 Xcode 是我在项目组织和应用捆绑方面唯一感到舒服的环境。
首先,是否可以使用 Apple 更成熟的动态链接系统,即 Frameworks,而不是 .dylib 方法?我找不到任何关于通过框架链接 GTK+ 或什至使用 Xcode 构建系统来完成工作的资源或讨论。
如有任何提示,我们将不胜感激。
更新
我为 GTK+ 引导 macOS 构建系统的第一次尝试在 cmake 依赖步骤失败了,脚本甚至没有提供 "abort" 选项。我不得不 Ctrl-C 它:另一个负面经历。
更新 2
进展:我成功地在Xcode 10.3 中创建了一个Hello-World command-line 程序并使其成为运行。基本上我避开了 GNOME 推荐的 jhbuild 路线。
我做过的事情:
- 从自制程序安装 gtk+3 及其 Python 绑定:
brew install pygobject3 gtk+3
- 在 Xcode 中,创建一个 C++ command-line 项目。
- 找出 header 个搜索路径:
pkg-config --cflags gtk+-3.0
,并将结果添加到 Xcode 目标的 Build Settings
的 Other C Flags
。
- 查找库:
pkg-config --libs gtk+-3.0
,并将结果添加到 Other Linker Flags
。
- 构建并运行。
这比 GNOME 推荐的要容易得多。请注意,它的最新编辑是在 2019 年完成的,因此他们可能仍然会推荐它。
我今天要尝试捆绑。
所以在折腾了 GTK+ 和 Xcode 10 个工具链一整天之后,我终于对发布使用 GTK+ 构建的 macOS 应用程序的想法更有信心了。对我来说最难的部分是弄清楚如何制作 self-contained 应用程序包,尤其是如何使用 Xcode 工具链 (10.3) 处理 macOS (Mojave) 上的 .dylib 地狱。在线资源在这个主题上非常不一致。许多教程建议我在这里和那里修复问题。然而,他们每个人都有一个稍微倾斜的部分,足以让我在一分钟后偏离轨道。但我很高兴事情比 the GNOME WIKI 描述的要容易得多,Xcode 处理了很多 heavy-lifting。
以下是我根据他们的 getting-started example 制作 hello-world GNOME 应用程序并在没有任何 pre-installed 的另一个 Mac 上制作 运行 的事情] 依赖,附有简短说明:
安装GTK+
- 从自制程序安装 gtk+3 及其 Python 绑定:
brew install
pygobject3 gtk+3
;
设置Xcode项目并完成编码
- 在 Xcode 中,使用 Objective-C 创建一个 Cocoa macOS 项目。
在 main.m
中编写您的 GTK+ 应用程序代码(我实际上是 main.mm
用于可能的 C++ mix-in)。而不是 returning NSApplicationMain()
的结果。你 return g_application_run()
.
保持所有其他支持源文件的原样。
设置一个合适的macOS Deployment Target
:为了合理的兼容性,我把它设为macOS 10.10
。另一台测试机我有运行s High Sierra.
这是我的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;
}
配置Xcode项目编译和link
在这里你必须 link 对抗 Homebrew GTK+。现在不要做你的 .dylib 调整。
- 设置编译器标志。找出 header 搜索路径:
pkg-config --cflags gtk+-3.0
,并将结果添加到 Xcode 目标的 Build Settings
. 的 Other C Flags
- 设置 linker 标志。找出所需的标志:
pkg-config --libs gtk+-3.0
,并将结果添加到 Other Linker Flags
.
- 将示例所需的系统框架添加到
Link Binary with Libraries
构建阶段。在我的例子中:Carbon
(!), Foundation
, CoreGraphics
, Cocoa
.
修复 .dylibs 中的嵌入路径
这是一个被广泛讨论的话题。人们甚至制作了工具(包括 Jhbuild 和 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。这是我的观点:
- 在
Link Binary with Libraries
之后添加一个 Run Script
构建阶段。我使用一个单独的脚本文件,只做 sh +x ${PROJECT_DIR}/${PRODUCT_NAME}/deploy_libs.sh
可维护性。
这是我写的实际脚本:
#! /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"
很抱歉没有用数组编写 for-loops,部分原因是您确实需要沿着依赖关系树精确定位每个依赖关系,直到到达 leaf 库,例如libfreetype
,它只依赖于系统库,即 /usr/lib/
和 /System/Library/
下的东西。你唯一真诚的朋友是 otool -L
。您会偶然发现以下怪癖:
- symlink 和版本库:一些特定的依赖项在
/usr/local/opt
下记录为 symlinks,其他的在 /usr/local/Cellar
下记录它们的源路径。如果您错误地使用了 symlinks,那么在将捆绑包发送到另一台机器后,您可能会遇到一个或两个 DYLB-not-found 错误。您需要 install_name_tool
命令的物理库。
显然,虽然 lib 本身始终是 otool
依赖报告的第一行,但您不需要 install_name_tool -change
它。
为了捆绑库,虽然 Xcode Build Phases
带有复制步骤,但这不是您将库复制到框架文件夹所需要的,因为它们需要显式导入 .dylib
文件添加到您的项目中,这将使以后很难区分 Debug/Release 配置。
我恳求有一个工具来自动化这个烂摊子,但运气不好。我想我只需要写一个,否则这种 brute-force 方法将无法扩展。
Code-signing 二进制文件
所有动态库必须 code-signed 作为应用程序的子模块。
- 在 Xcode 项目构建设置中将
--deep
添加到 Other Code Signing Flags
;
- 将
Code Signing Identity
设置为您的团队开发者帐户。
- 对于这个例子,我根本不需要调整
Info.plist
。
构建,运行,并部署到其他机器
只需构建 运行。该示例应该已经在开发机器上运行了。
将整个应用程序包 hello_world.app
复制到另一台没有 Homebrew 或其他包的 Mac 机器。该应用程序也应该 运行 成功。
构建用于部署的 .dmg。这是标准程序,所以我暂时跳过它。
希望这可以帮助那些可能像我一样一开始就一无所知的人。
我的下一个挑战是发现在 GTK+ 之上发布 PyGObject 应用程序的要点。 worry-free程序似乎也被埋在了一片巨大的沙漠中。
我知道这已经过时了,但是...在您的指导下,我编写了一个脚本来完成移动所需库和重写路径的工作。该脚本运行良好,但我发现尽管所有路径 (otool -L) 都被重定向到新的 lib 目录,但 运行 可执行文件中仍然存在错误。 '字符串 xxx.dylib | grep "/usr/local" 显示某些库中仍然存在硬编码路径。这可能会导致问题。可执行文件不会崩溃,只会抛出有关库放置不明确的错误。这是在 Mac 蒙特雷 OS。
我的设置:
- macOS 莫哈韦
- Xcode10.3
我正在研究使用 GTK+ 在 macOS 上发布应用程序的可能性。
不幸的是,根据 GTK+ 的 macOS build/bundle/integration 指南,整个过程对我来说似乎令人生畏:
- https://wiki.gnome.org/Projects/GTK/OSX/Building
- https://wiki.gnome.org/Projects/GTK/OSX/Bundling
- https://wiki.gnome.org/Projects/GTK/OSX/Integration
本指南展示了巨大脚本的各种陷阱及其环境调整,这些调整可能会搞乱整个 OS。推荐的开新用户的方法好像也不是很实用。
这种 all-in-one 脚本方法,不包括任何关于 Xcode 的讨论,是相当可怕的,因为它让我想知道它能以多快的速度跟上 Apple 的发展,因为 Xcode工具链每隔几个月升级一次。 Xcode 是我在项目组织和应用捆绑方面唯一感到舒服的环境。
首先,是否可以使用 Apple 更成熟的动态链接系统,即 Frameworks,而不是 .dylib 方法?我找不到任何关于通过框架链接 GTK+ 或什至使用 Xcode 构建系统来完成工作的资源或讨论。
如有任何提示,我们将不胜感激。
更新
我为 GTK+ 引导 macOS 构建系统的第一次尝试在 cmake 依赖步骤失败了,脚本甚至没有提供 "abort" 选项。我不得不 Ctrl-C 它:另一个负面经历。
更新 2
进展:我成功地在Xcode 10.3 中创建了一个Hello-World command-line 程序并使其成为运行。基本上我避开了 GNOME 推荐的 jhbuild 路线。
我做过的事情:
- 从自制程序安装 gtk+3 及其 Python 绑定:
brew install pygobject3 gtk+3
- 在 Xcode 中,创建一个 C++ command-line 项目。
- 找出 header 个搜索路径:
pkg-config --cflags gtk+-3.0
,并将结果添加到 Xcode 目标的Build Settings
的Other C Flags
。 - 查找库:
pkg-config --libs gtk+-3.0
,并将结果添加到Other Linker Flags
。 - 构建并运行。
这比 GNOME 推荐的要容易得多。请注意,它的最新编辑是在 2019 年完成的,因此他们可能仍然会推荐它。
我今天要尝试捆绑。
所以在折腾了 GTK+ 和 Xcode 10 个工具链一整天之后,我终于对发布使用 GTK+ 构建的 macOS 应用程序的想法更有信心了。对我来说最难的部分是弄清楚如何制作 self-contained 应用程序包,尤其是如何使用 Xcode 工具链 (10.3) 处理 macOS (Mojave) 上的 .dylib 地狱。在线资源在这个主题上非常不一致。许多教程建议我在这里和那里修复问题。然而,他们每个人都有一个稍微倾斜的部分,足以让我在一分钟后偏离轨道。但我很高兴事情比 the GNOME WIKI 描述的要容易得多,Xcode 处理了很多 heavy-lifting。
以下是我根据他们的 getting-started example 制作 hello-world GNOME 应用程序并在没有任何 pre-installed 的另一个 Mac 上制作 运行 的事情] 依赖,附有简短说明:
安装GTK+
- 从自制程序安装 gtk+3 及其 Python 绑定:
brew install pygobject3 gtk+3
;
设置Xcode项目并完成编码
- 在 Xcode 中,使用 Objective-C 创建一个 Cocoa macOS 项目。
在
main.m
中编写您的 GTK+ 应用程序代码(我实际上是main.mm
用于可能的 C++ mix-in)。而不是 returningNSApplicationMain()
的结果。你 returng_application_run()
.保持所有其他支持源文件的原样。
设置一个合适的
macOS Deployment Target
:为了合理的兼容性,我把它设为macOS 10.10
。另一台测试机我有运行s High Sierra.
这是我的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;
}
配置Xcode项目编译和link
在这里你必须 link 对抗 Homebrew GTK+。现在不要做你的 .dylib 调整。
- 设置编译器标志。找出 header 搜索路径:
pkg-config --cflags gtk+-3.0
,并将结果添加到 Xcode 目标的Build Settings
. 的 - 设置 linker 标志。找出所需的标志:
pkg-config --libs gtk+-3.0
,并将结果添加到Other Linker Flags
. - 将示例所需的系统框架添加到
Link Binary with Libraries
构建阶段。在我的例子中:Carbon
(!),Foundation
,CoreGraphics
,Cocoa
.
Other C Flags
修复 .dylibs 中的嵌入路径
这是一个被广泛讨论的话题。人们甚至制作了工具(包括 Jhbuild 和 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。这是我的观点:
- 在
Link Binary with Libraries
之后添加一个Run Script
构建阶段。我使用一个单独的脚本文件,只做sh +x ${PROJECT_DIR}/${PRODUCT_NAME}/deploy_libs.sh
可维护性。
这是我写的实际脚本:
#! /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"
很抱歉没有用数组编写 for-loops,部分原因是您确实需要沿着依赖关系树精确定位每个依赖关系,直到到达 leaf 库,例如libfreetype
,它只依赖于系统库,即 /usr/lib/
和 /System/Library/
下的东西。你唯一真诚的朋友是 otool -L
。您会偶然发现以下怪癖:
- symlink 和版本库:一些特定的依赖项在
/usr/local/opt
下记录为 symlinks,其他的在/usr/local/Cellar
下记录它们的源路径。如果您错误地使用了 symlinks,那么在将捆绑包发送到另一台机器后,您可能会遇到一个或两个 DYLB-not-found 错误。您需要install_name_tool
命令的物理库。
显然,虽然 lib 本身始终是 otool
依赖报告的第一行,但您不需要 install_name_tool -change
它。
为了捆绑库,虽然 Xcode Build Phases
带有复制步骤,但这不是您将库复制到框架文件夹所需要的,因为它们需要显式导入 .dylib
文件添加到您的项目中,这将使以后很难区分 Debug/Release 配置。
我恳求有一个工具来自动化这个烂摊子,但运气不好。我想我只需要写一个,否则这种 brute-force 方法将无法扩展。
Code-signing 二进制文件
所有动态库必须 code-signed 作为应用程序的子模块。
- 在 Xcode 项目构建设置中将
--deep
添加到Other Code Signing Flags
; - 将
Code Signing Identity
设置为您的团队开发者帐户。 - 对于这个例子,我根本不需要调整
Info.plist
。
构建,运行,并部署到其他机器
只需构建 运行。该示例应该已经在开发机器上运行了。
将整个应用程序包
hello_world.app
复制到另一台没有 Homebrew 或其他包的 Mac 机器。该应用程序也应该 运行 成功。构建用于部署的 .dmg。这是标准程序,所以我暂时跳过它。
希望这可以帮助那些可能像我一样一开始就一无所知的人。 我的下一个挑战是发现在 GTK+ 之上发布 PyGObject 应用程序的要点。 worry-free程序似乎也被埋在了一片巨大的沙漠中。
我知道这已经过时了,但是...在您的指导下,我编写了一个脚本来完成移动所需库和重写路径的工作。该脚本运行良好,但我发现尽管所有路径 (otool -L) 都被重定向到新的 lib 目录,但 运行 可执行文件中仍然存在错误。 '字符串 xxx.dylib | grep "/usr/local" 显示某些库中仍然存在硬编码路径。这可能会导致问题。可执行文件不会崩溃,只会抛出有关库放置不明确的错误。这是在 Mac 蒙特雷 OS。