1. ホーム
  2. macos

[解決済み] OSXアプリバンドル構築

2023-01-08 18:25:59

質問

Xcodeを使わずにosXアプリを作ったとします。GCC でコンパイルした後、いくつかの他のライブラリにリンクされた実行ファイルを得ました。これらのライブラリのいくつかは、他の非標準的なシステム ライブラリに動的にリンクされるかもしれません。

最初に必要なディレクトリ構造を作成し、次にリンクを再帰的にコピー/チェック/修正して、すべての動的依存関係がアプリ バンドルにもあることを確認することによって OSX アプリ バンドルを作成するツールは存在しますか?

私はこのようなものを書いてみることができると思いますが、このようなものがすでに存在するかどうか疑問に思っていました。

どのように解決するのですか?

MacOSX でアプリのバンドルを作成するには、Easy と Ugly の 2 つの方法があります。

簡単な方法は、単に XCode を使用することです。 完了です。

問題は、それができない場合があることです。

私の場合、他のアプリを構築するアプリを構築しています。 ユーザーが XCode をインストールしていると仮定することはできません。 また、私は MacPorts を使用して、私のアプリが依存するライブラリをビルドしています。 アプリを配布する前に、これらの dylibs がアプリにバンドルされていることを確認する必要があります。

免責事項。 私はこの投稿を書く資格が全くありません。 は Apple のドキュメントから得たものであり、既存のアプリケーションを分解し、試行錯誤したものです。 試行錯誤の結果です。私にとってはうまくいくのですが、おそらく間違っています。 お願い もし、訂正があれば、メールをください。

最初に知っておくべきことは、アプリバンドルは単なるディレクトリであるということです。

仮想的なfoo.appの構造を見てみましょう。

foo.app/
    コンテンツ/
        情報.plist
        MacOS/
            foo
        リソース
            foo.icns

Info.plistはプレーンなXMLファイルです。 テキストエディタか、XCodeにバンドルされているProperty List Editorアプリで編集することができます。 (これは /Developer/Applications/Utilities/ ディレクトリにあります)。

含める必要がある主なものは次のとおりです。

CFBundleName - アプリの名前です。

CFBundleIcon - Contents/Resources ディレクトリにあると仮定したアイコンのファイルです。 Icon Composerアプリを使用してアイコンを作成します。(Icon Composerは、/Developer/Applications/Utilities/ディレクトリにあります)。 このアプリのウィンドウにpngをドラッグ&ドロップするだけで、自動的にミップレベルを生成してくれます。

CFBundleExecutable - Contents/MacOS/サブフォルダ内にあると想定される実行ファイル名です。

上に挙げたものは最低限必要なもので、他にもたくさんのオプションがあります。 以下は 情報.plist ファイルおよび アプリのバンドル構造 .

また、Info.plistのサンプルはこちらです。

<?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>
  <キー>CFBundleGetInfoString</キー>
  <文字列>Foo</string>
  <キー>CFBundleExecutable</key>
  <文字列>foo</string>
  <キー>CFBundleIdentifier</key>
  <文字列>com.your-company-name.www</string>
  <キー>CFBundleName</key>
  <文字列>foo</string>
  <キー>CFBundleIconFile</キー>
  <文字列>foo.icns</string>
  <キー>CFBundleShortVersionString</key>
  <文字列>0.01</string>
  <キー>CFBundleInfoDictionaryVersion</key>
  <文字列>6.0</string>
  <キー>CFBundlePackageType</key>
  <文字列>APPL</string>
  <キー>IFMajorVersion</key>
  <integer>0</integer>
  <キー>IFMinorVersion</key>
  <integer>1</integer>
</dict>
</plist>

完璧な世界では、実行ファイルを にドロップして完了です。 しかし、アプリに標準以外の dylib の依存関係がある場合 標準的でない dylib の依存関係がある場合は、うまくいきません。 Windowsと同様、MacOS には、独自の特殊な DLL地獄 .

もし、あなたが MacPorts を使ってリンクするライブラリをビルドしている場合、dylibs の位置は実行ファイルにハードコードされます。 dylibs がまったく同じ場所にあるマシンでアプリを実行すれば、問題なく実行できます。 しかし、ほとんどのユーザーは dylibs をインストールしていないため、アプリをダブルクリックするとクラッシュします。

実行ファイルを配布する前に、それが読み込むすべての dylibs を収集し、アプリ バンドルにコピーする必要があります。 また、正しい場所にある dylibs を探すように、実行ファイルを編集する必要があります。

実行ファイルを手作業で編集するのは危険なように聞こえますが? 幸いなことに、コマンドライン ツールがあります。

otool -L 実行ファイル名

このコマンドは、アプリが依存するすべての dylibs をリストアップします。 System/Library または usr/lib フォルダーにないものがあれば、それらをアプリのバンドルにコピーする必要があります。 これらを /Contents/MacOS/ フォルダにコピーします。 次に、新しい dylibs を使用するために実行ファイルを編集する必要があります。

最初に、-headerpad_max_install_names フラグを使用してリンクしていることを確認する必要があります。 これは、新しい dylib のパスが以前のものより長い場合、そのためのスペースがあることを確認するだけです。

次に、install_name_tool を使用して、各 dylib パスを変更します。

install_name_tool -change existing_path_to_dylib @executable_path/blah.dylib executable_name

実際の例として、あなたのアプリが以下のものを使用しているとします。 libSDL を使用していて、otool がその場所を "/opt/local/lib/libSDL-1.2.0.dylib" としてリストしているとします。

まず、これをアプリバンドルにコピーします。

cp /opt/local/lib/libSDL-1.2.0.dylib foo.app/Contents/MacOS/にコピーします。

次に、新しい場所を使用するように実行ファイルを編集します (注意: -headerpad_max_install_names フラグを付けてビルドしたことを確認してください)。

install_name_tool -change /opt/local/lib/libSDL-1.2.0.dylib @executable_path/libSDL-1.2.0.dylib foo.app/Contents/MacOS/foo。

ふー、ほぼ完成です。 あとは、現在の作業ディレクトリに小さな問題があります。

アプリを起動すると、カレントディレクトリはアプリが置かれている上のディレクトリになります。 たとえば たとえば、/Applcations フォルダに foo.app を配置した場合、アプリを起動したときのカレント ディレクトリは /Applications フォルダになります。 期待されるような /Applications/foo.app/Contents/MacOS/ ではなく、/Applications フォルダになります。

このことを考慮してアプリを変更するか、または、カレント ディレクトリを変更してアプリを起動する、この魔法のような小さなランチャ スクリプトを使用することができます。

#!/bin/bash
cd "${0%/*}"
./foo

Info.plistファイルを調整して、次のようにすることを確認してください。 CFBundleExecutable が以前の実行ファイルではなく、起動スクリプトを指していることを確認します。

OK、これですべて完了です。 幸いなことに、一度このようなことをすべて知ってしまえば、ビルドスクリプトの中に埋めてしまうことができます。