7

私はXCodeの奇妙な振る舞いを扱っています:

dyld: Library not loaded: /Library/Frameworks/SBJson.framework/Versions/A/SBJson

基本的に、実際にはである私のRunpath Search PathLD_RUNPATH_SEARCH_PATHS)構成を無視します@loader_path/../Frameworks

現時点では、組み込みフレームワークをロードできません:/

otool言う

otool -L /Users/kilian/Library/Developer/Xcode/DerivedData/r-ghohkslxtxgpnuepmblogfjtuefx/Build/Products/Debug/r.app/Contents/MacOS/r
/Users/kilian/Library/Developer/Xcode/DerivedData/r-ghohkslxtxgpnuepmblogfjtuefx/Build/Products/Debug/r.app/Contents/MacOS/r:
  /System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa (compatibility version 1.0.0, current version 19.0.0)
  /Library/Frameworks/SBJson.framework/Versions/A/SBJson (compatibility version 1.0.0, current version 37.0.0)
  /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 945.0.0)
  /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
  /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0)
  /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1186.0.0)

PSフレームワークビルドフェーズにコピーを追加したかどうか疑問に思っているなら、答えはイエスです。

4

1 に答える 1

19

ショートバージョン

問題は、ビルド時SBJSON.frameworkに、インストール名がを使用するように構成されていないこと@rpathです。その結果、アプリがダイナミックライブラリをロードしようと/Library/Frameworksすると、アプリの実行パスが検索するように指示する場所ではなく、検索します。

SBJSON.frameworkこれを修正するには、ターゲットのビルド設定を変更する必要があります。ダイナミックライブラリのインストール名の設定をに変更し@rpath/${EXECUTABLE_PATH}ます。次に、新しく構築されたフレームワークに対してリンクして、再度構築するだけで、準備は完了です。

ロングバージョン

フレームワークは、基本的には単なるダイナミックライブラリです。これは、ライブラリに含まれているコードがアプリに埋め込まれているのではなく、実行時SBJSON.frameworkにバンドルから取得されることを意味します。これを行うには、アプリがダイナミックライブラリを探す場所を知る必要があります。

これが機能する方法は、フレームワークに対してリンクする場合、リンカーが実際にライブラリ全体をアプリに埋め込むことはないということです。代わりに、実行時にライブラリを見つける場所をアプリに指示する小さなセクションを追加するだけです。もちろん、これは、コンパイラが実行時にライブラリがどこにあるかを知る必要があることを意味します。ダイナミックライブラリの「インストール名」を調べることで、その情報を見つけます。

ダイナミックライブラリの「インストール名」は、基本的に、ライブラリが存在すると予想されるパスにすぎません。歴史的に、ほとんどのダイナミックライブラリとフレームワークはシステム全体で共有されてきました。たとえば、のようなものはに住んでFoundation.frameworkおり、すべてのアプリはそこにそれらを見つけることを合理的に期待できます。したがって、がビルドされると、そのインストール名はに設定されます。XcodeがアプリをCoreDataにリンクすると、フレームワークのインストール名が確認され、アプリの起動時にそのパスでフレームワークに読み込まれるように指示されます。CoreData.framework/System/Library/FrameworksCoreData.framework/System/Library/Frameworks/...

それはすべて問題ありませんが、アプリ内にフレームワークを埋め込む必要がある場合は役に立ちません。実行時にアプリがシステムのどこに配置されるかはわかりません。ユーザーはから実行できますが、から実行する/Applicationsこともできます~/Downloads。実行時にフレームワークを常に正しく指すインストール名として指定できる単一のパスはありません。

これに対処するために、フレームワークのインストール名をに設定できます@loader_path/../Frameworks。ダイナミックローダーが@loader_pathを検出すると、現在ロードしているアプリのパスに置き換えられます。このインストール名を使用すると、フレームワークをFrameworks任意のアプリのフォルダー内にインストールできます。

しかし、物事はまだ完璧ではありません。フレームワークはまだそれがどこに置かれるべきかを指示しています。たとえば、別のアプリがLibraries代わりにフレームワークをフォルダー内に配置したい場合、それは運が悪いです。フレームワークは、アプリではなく、配置できる場所を担当します。これは依存関係ツリーの反転であり、理想的ではありません。アプリは、他のフレームワークが何をするかに関係なく、フレームワークを隠したい場所からフレームワークをロードできる必要があります。

そのため、OSX10.5では@rpathが導入されました。dylibまたはフレームワークのインストール名がで始まる@rpath場合、ローダーは向きを変えてアプリに「Runpath検索パス」とは何かを尋ね、それらを置き換えます。これにより、アプリはフレームワークが存在する場所を指定できます。を使用することにより@rpath、フレームワークは決定をアプリに委任します。アプリは必要に応じて使用でき@loader_path、必要に応じて絶対パスを指定できます。アプリスイート全体が使用する共有フォルダーを指定することもできます。

あなたの問題

だから、あなたの問題に移ります。アプリの実行パス検索パスをに正しく設定しています@loader_path/../Frameworks。ただし、フレームワークのインストール名は@rpath;を使用していません。実際、それはまだへのハードコードされたパスを使用してい/Library/Frameworks/...ます。フレームワークのインストール名はを使用しないため@rpath、アプリの実行パスは参照されません。フォルダからSBJSONにリンクしようとしているだけ/Libraryです。そこにないため、アプリが起動する前にクラッシュします。

を使用するには、SBJSONフレームワークのインストール名を変更する必要があります@rpathダイナミックライブラリのインストール名の設定をに設定し@rpath/${EXECUTABLE_PATH}ます。(${EXECUTABLE_PATH}フレームワークを含むフォルダーからの内部ダイナミックライブラリへの相対パスです。)

新しいインストール名でフレームワークを構築すると、新しいフレームワークにリンクできるようになり、アプリバンドルのFrameworks/フォルダーにコピーされていることを確認できます。これで準備完了です。

PSこれがすべて明確ではない場合、マイクアッシュは@rpathと友人のかなり良いレビューをしました。ここで見つけることができます。

于 2012-09-01T06:19:41.557 に答える