Can I include a framework in another framework?
I'm writing a framework (called Lighthouse.framework) that, in turn, uses code from another framework (RegexKit.framework, to be precise). I have copied RegexKit.framework into my own framework, so that it has a structure like the following:
Lighthouse.framework/
Versions/
A开发者_开发问答/
Frameworks/
RegexKit.framework
Lighthouse
However, when I try to run an application that uses Lighthouse.framework (my framework), I get the following error:
dyld: Library not loaded: @executable_path/../Frameworks/RegexKit.framework/Versions/A/RegexKit
Referenced from: /Users/mdippery/Developer/Projects/Current/lighthouse/build/Debug/Lighthouse.framework/Versions/A/Lighthouse
Reason: image not found
Obviously, the loader isn't finding RegexKit.
Here're the paths the loader expects to load, courtesy otool
:
build/Debug/Lighthouse.framework/Versions/A/Lighthouse:
/Users/mdippery/Library/Frameworks/Lighthouse.framework/Versions/A/Lighthouse (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa (compatibility version 1.0.0, current version 12.0.0)
@executable_path/../Frameworks/RegexKit.framework/Versions/A/RegexKit (compatibility version 0.4.0, current version 0.6.0)
/usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.1.4)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 227.0.0)
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 476.19.0)
/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 677.26.0)
Can I include a framework in another framework? Is this the proper way to do it? How can I resolve my error?
The easiest way is to use @rpath. Your configuration should look like:
- Set RegExKit.framework's Installation Directory to @rpath
- Set Lighthouse.frameworks's Installation Directory to @rpath
- Set Lighthouse.framework's Runpath Search Paths to @loader_path/Frameworks
- Ensure that RegExKit.framework is copied into Lighthouse.framework's Framework subfolder (use a custom build phase for this)
Finally, any applications linking to Lighthouse.framework should set Runpath Search Paths to @loader_path/../Frameworks
Yes, you can.
However, you need the included framework to "know" what its installed location will be at the time that it is built; otherwise, dyld
won't be able to find it at run time, as you saw.
The relevant settings in XCode, if I recall correctly, are "Installation Directory" and "Framework Install Name". The latter probably won't matter for your usage, but you're going to need the former to be something along the lines of: @executable_path/../Frameworks/Lighthouse.framework/Versions/A/Frameworks/RegexKit.framework/Versions/A/
I discovered a fix for this problem. I incorporated some ideas from sbooth's answer, but the fix was simpler. I ran this script:
install_name_tool -change @executable_path/../Frameworks/RegexKit.framework/Versions/A/RegexKit @loader_path/Frameworks/RegexKit.framework/Versions/A/RegexKit "${TARGET_BUILD_DIR}/${PRODUCT_NAME}.framework/Versions/A/${PRODUCT_NAME}"
as a Run Build Script phase.
Note that, for the general case, you have to change @executable_path/../
to @loader_path/
, and all is well.
精彩评论