Can I include a framework in another framework?

2019-01-25 11:43发布

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?

3条回答
手持菜刀,她持情操
2楼-- · 2019-01-25 11:56

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.

查看更多
萌系小妹纸
3楼-- · 2019-01-25 12:13

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/

查看更多
一纸荒年 Trace。
4楼-- · 2019-01-25 12:16

The easiest way is to use @rpath. Your configuration should look like:

  1. Set RegExKit.framework's Installation Directory to @rpath
  2. Set Lighthouse.frameworks's Installation Directory to @rpath
  3. Set Lighthouse.framework's Runpath Search Paths to @loader_path/Frameworks
  4. 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

查看更多
登录 后发表回答