Problem with prebinding and Frameworks

  • Hi all,
    I've got an external framework developed by somebody, and I'm
    developing a framework that uses this other one, and then an
    application that uses my own framework. Everything works just fine
    with my own framework, but because of some new ways to work with
    links with code developed from OSX 10.4, I don't need to prebind the
    frameworks, and when I try to build my application, it doesn't works.
    I get an this error:

    /usr/bin/ld: warning can't open dynamic library: @executable_path/../
    Frameworks/i1C.framework/Versions/A/i1C referenced from: /Users/
    jbianco/BuildProducts/Release/TCFwkEyeOne.framework/TCFwkEyeOne
    (checking for undefined symbols may be affected) (No such file or
    directory, errno = 2)

    /usr/bin/ld: Undefined symbols:

    _I1_GetTriStimulus referenced from TCFwkEyeOne expected to be defined
    in @executable_path/../Frameworks/i1C.framework/Versions/A/i1C
    _I1_IsConnected referenced from TCFwkEyeOne expected to be defined in
    @executable_path/../Frameworks/i1C.framework/Versions/A/i1C
    _I1_TriggerMeasurement referenced from TCFwkEyeOne expected to be
    defined in @executable_path/../Frameworks/i1C.framework/Versions/A/i1C

    And I was investigating, and I realize that the problem I get is
    generated because of the warning I see before, because  the symbols
    that are undefined are those ones I obtain from the original
    framework, I mean _I1_GetTriStimulus, _I1_IsConnected and
    _I1_TriggerMeasurement are defines in the header imported from
    i1C.framework, and I cannot see it, because it can't open this
    dynamic library.
    Can you tell me how to fix this issue?

    Thanx
    Julio
  • On May 3, 2006, at 3:00 PM, Julio Bianco wrote:

    > I've got an external framework developed by somebody, and I'm
    > developing a framework that uses this other one, and then an
    > application that uses my own framework. Everything works just fine
    > with my own framework, but because of some new ways to work with
    > links with code developed from OSX 10.4, I don't need to prebind
    > the frameworks, and when I try to build my application, it doesn't
    > works. I get an this error:
    >
    > /usr/bin/ld: warning can't open dynamic library:
    > @executable_path/../Frameworks/i1C.framework/Versions/A/i1C
    > referenced from: /Users/jbianco/BuildProducts/Release/
    > TCFwkEyeOne.framework/TCFwkEyeOne (checking for undefined symbols
    > may be affected) (No such file or directory, errno = 2)

    That has nothing to do with prebinding. For one thing, it says
    nothing about prebinding. For another, failure to prebind is a
    warning, not an error.

    The third-party framework is configured to be in MyApp.app/Contents/
    Frameworks, and the linker isn't finding it there. I'd guess that
    you've copied it into TCFwkEyeOne.framework/Contents/Frameworks instead.

    If you want to bundle a framework inside another framework, you can
    specify @loader_path (which is only supported on >= Tiger) instead of
    @executable_path in the inner framework's install_name.

    If Panther compatibility is important, you'll need to supply an
    install_name that begins with @executable_path. Whether the framework
    is actually in the .app or your .framework isn't important; what's
    important is that the install_path gives the correct location,
    whatever that location might be.

    > /usr/bin/ld: Undefined symbols:
    >
    > _I1_GetTriStimulus referenced from TCFwkEyeOne expected to be
    > defined in @executable_path/../Frameworks/i1C.framework/Versions/A/i1C
    > _I1_IsConnected referenced from TCFwkEyeOne expected to be defined
    > in @executable_path/../Frameworks/i1C.framework/Versions/A/i1C
    > _I1_TriggerMeasurement referenced from TCFwkEyeOne expected to be
    > defined in @executable_path/../Frameworks/i1C.framework/Versions/A/i1C
    >
    > And I was investigating, and I realize that the problem I get is
    > generated because of the warning

    The lesson here is not to investigate backwards. Build-time errors
    need to be debugged in the order in which they're reported, because
    it's very common for an error in one build step to "cascade" down and
    trigger other errors in later steps. Trying to solve the later errors
    first is guaranteed to lead to frustration.

    sherm--

    Cocoa programming in Perl: http://camelbones.sourceforge.net
    Hire me! My resume: http://www.dot-app.org
  • Thanx for this answer, That was just what I need, but I've some other
    questions
    On May 3, 2006, at 5:22 PM, Sherm Pendley wrote:

    > On May 3, 2006, at 3:00 PM, Julio Bianco wrote:
    >
    >> I've got an external framework developed by somebody, and I'm
    >> developing a framework that uses this other one, and then an
    >> application that uses my own framework. Everything works just fine
    >> with my own framework, but because of some new ways to work with
    >> links with code developed from OSX 10.4, I don't need to prebind
    >> the frameworks, and when I try to build my application, it doesn't
    >> works. I get an this error:
    >>
    >> /usr/bin/ld: warning can't open dynamic library:
    >> @executable_path/../Frameworks/i1C.framework/Versions/A/i1C
    >> referenced from: /Users/jbianco/BuildProducts/Release/
    >> TCFwkEyeOne.framework/TCFwkEyeOne (checking for undefined symbols
    >> may be affected) (No such file or directory, errno = 2)
    >
    > That has nothing to do with prebinding. For one thing, it says
    > nothing about prebinding. For another, failure to prebind is a
    > warning, not an error.
    >
    > The third-party framework is configured to be in MyApp.app/Contents/
    > Frameworks, and the linker isn't finding it there. I'd guess that
    > you've copied it into TCFwkEyeOne.framework/Contents/Frameworks
    > instead.

    That was exactly what was happened, and if I include this other
    framework in my application it works fine, but as you can imagine, I
    don't want to add every framework I use in may other frameworks, but
    those ones I needed to use and only those.

    > If you want to bundle a framework inside another framework, you can
    > specify @loader_path (which is only supported on >= Tiger) instead
    > of @executable_path in the inner framework's install_name.

    Yes, that's what I needed to do, but I don't find a way to perform
    that thing you tell me to do. What is that you tell me to modify?
    What variable should I touch? I don't find a way to add this
    variable, even when I realize you are telling me just what I need.

    > If Panther compatibility is important, you'll need to supply an
    > install_name that begins with @executable_path. Whether the
    > framework is actually in the .app or your .framework isn't
    > important; what's important is that the install_path gives the
    > correct location, whatever that location might be.

    I'm currently working with Tiger, but that information is to useful to.

    >> /usr/bin/ld: Undefined symbols:
    >>
    >> _I1_GetTriStimulus referenced from TCFwkEyeOne expected to be
    >> defined in @executable_path/../Frameworks/i1C.framework/Versions/A/
    >> i1C
    >> _I1_IsConnected referenced from TCFwkEyeOne expected to be defined
    >> in @executable_path/../Frameworks/i1C.framework/Versions/A/i1C
    >> _I1_TriggerMeasurement referenced from TCFwkEyeOne expected to be
    >> defined in @executable_path/../Frameworks/i1C.framework/Versions/A/
    >> i1C
    >>
    >> And I was investigating, and I realize that the problem I get is
    >> generated because of the warning
    >
    > The lesson here is not to investigate backwards. Build-time errors
    > need to be debugged in the order in which they're reported, because
    > it's very common for an error in one build step to "cascade" down
    > and trigger other errors in later steps. Trying to solve the later
    > errors first is guaranteed to lead to frustration.
    >
    > sherm--
    >
    > Cocoa programming in Perl: http://camelbones.sourceforge.net
    > Hire me! My resume: http://www.dot-app.org
    >

    Thanx for all

    Julio
  • On May 4, 2006, at 11:24 AM, Julio Bianco wrote:

    > On May 3, 2006, at 5:22 PM, Sherm Pendley wrote:
    >
    >> The third-party framework is configured to be in MyApp.app/
    >> Contents/Frameworks, and the linker isn't finding it there. I'd
    >> guess that you've copied it into TCFwkEyeOne.framework/Contents/
    >> Frameworks instead.
    >
    > That was exactly what was happened, and if I include this other
    > framework in my application it works fine, but as you can imagine,
    > I don't want to add every framework I use in may other frameworks,
    > but those ones I needed to use and only those.

    The key factor on where to put i1C is, how many frameworks will use it?

    So the question is, do any of your other frameworks link against i1C?
    If not, you can just copy it into your TCFwkEyeOne framework's
    Contents/Frameworks subdirectory and you're done.

    Now suppose you have multiple frameworks that all use the i1C
    framework. If you embed i1C in each of those, and then embed each of
    those in your app, you'll wind up with multiple redundant copies of
    i1C. In a case like that, it makes more sense to make one copy of i1C
    in the app's Contents/Frameworks instead.

    >> If you want to bundle a framework inside another framework, you
    >> can specify @loader_path (which is only supported on >= Tiger)
    >> instead of @executable_path in the inner framework's install_name.
    >
    > Yes, that's what I needed to do, but I don't find a way to perform
    > that thing you tell me to do. What is that you tell me to modify?
    > What variable should I touch? I don't find a way to add this
    > variable, even when I realize you are telling me just what I need.

    You can set the install_name in several ways; with an Xcode setting,
    with a linker option (which is what the Xcode setting does under the
    hood), or after the fact with the command-line install_name_tool
    utility.

    If you're building the i1C framework from source using Xcode, have a
    look at the "Installation Directory" target setting, under the
    "Deployment" collection. Change that from "@executable_path..." to
    "@loader_path...".

    Or, if it's built using *nix-style make files, add (or change) the -
    install_name option in LDFLAGS.

    And finally, if you don't have the source to the i1C framework, or
    you just don't feel like rebuilding it, you can use install_name_tool
    to change the install_name of a binary:
    install_name_tool -id '@loader_path/../Frameworks/i1C.framework/
    Versions/A/i1C'

    The "install_name_tool" only works if the new install_name is no
    longer than the old one. Fortunately, @loader_path is shorter than
    @executable_path, and the rest is identical. That limitation is worth
    keeping in mind for future use though.

    sherm--

    Cocoa programming in Perl: http://camelbones.sourceforge.net
    Hire me! My resume: http://www.dot-app.org
  • Hi,
    I'm sorry, but I have to ask because I try to do that you told me but
    I can't.

    On May 4, 2006, at 3:19 PM, Sherm Pendley wrote:

    > On May 4, 2006, at 11:24 AM, Julio Bianco wrote:
    >
    >> On May 3, 2006, at 5:22 PM, Sherm Pendley wrote:
    >>
    >>> The third-party framework is configured to be in MyApp.app/
    >>> Contents/Frameworks, and the linker isn't finding it there. I'd
    >>> guess that you've copied it into TCFwkEyeOne.framework/Contents/
    >>> Frameworks instead.
    >>
    >> That was exactly what was happened, and if I include this other
    >> framework in my application it works fine, but as you can imagine,
    >> I don't want to add every framework I use in may other frameworks,
    >> but those ones I needed to use and only those.
    >
    > The key factor on where to put i1C is, how many frameworks will use
    > it?
    >
    > So the question is, do any of your other frameworks link against
    > i1C? If not, you can just copy it into your TCFwkEyeOne framework's
    > Contents/Frameworks subdirectory and you're done.
    >
    > Now suppose you have multiple frameworks that all use the i1C
    > framework. If you embed i1C in each of those, and then embed each
    > of those in your app, you'll wind up with multiple redundant copies
    > of i1C. In a case like that, it makes more sense to make one copy
    > of i1C in the app's Contents/Frameworks instead.
    >
    >>> If you want to bundle a framework inside another framework, you
    >>> can specify @loader_path (which is only supported on >= Tiger)
    >>> instead of @executable_path in the inner framework's install_name.
    >>
    >> Yes, that's what I needed to do, but I don't find a way to perform
    >> that thing you tell me to do. What is that you tell me to modify?
    >> What variable should I touch? I don't find a way to add this
    >> variable, even when I realize you are telling me just what I need.
    >
    > You can set the install_name in several ways; with an Xcode
    > setting, with a linker option (which is what the Xcode setting does
    > under the hood), or after the fact with the command-line
    > install_name_tool utility.
    >
    > If you're building the i1C framework from source using Xcode, have
    > a look at the "Installation Directory" target setting, under the
    > "Deployment" collection. Change that from "@executable_path..." to
    > "@loader_path...".
    >
    > Or, if it's built using *nix-style make files, add (or change) the -
    > install_name option in LDFLAGS.
    >
    > And finally, if you don't have the source to the i1C framework, or
    > you just don't feel like rebuilding it, you can use
    > install_name_tool to change the install_name of a binary:
    > install_name_tool -id '@loader_path/../Frameworks/i1C.framework/
    > Versions/A/i1C'

    I do what you tell me to do, and it do that you tell me it will do,
    but I try to build the final application, and I get the same kind of
    error than before but with some difference

    /usr/bin/ld: warning can't open dynamic library: @loader_path/../
    Frameworks/i1C.framework/Versions/A/i1C referenced from: /Users/
    jbianco/BuildProducts/Release/TCFwkEyeOne.framework/TCFwkEyeOne
    (checking for undefined symbols may be affected) (No such file or
    directory, errno = 2)

    As you can notice, this new error differs to the previous one because
    the last one tels me @executable_path instead of @loader_path, then I
    don't know if I'm missing something or I need to try something else.

    I will describe a little more my case to you. I've 2 frameworks and
    an application. The A framework is a binary one, pre-build for
    somebody else, and I have no access to this code. The B framework is
    a framework I develop, and it uses the A framework. And an
    application that use B framework. When  I build the B framework
    (including the A framework), everything goes right, I get no error at
    all, and everything seams to be ok, but when I try to build de
    application it gives me a warning as that I show you before. I mean,

    /usr/bin/ld: warning can't open dynamic library: @loader_path/../
    Frameworks/A.framework/Versions/A/A referenced from: /Users/me/
    BuildProducts/Release/B.framework/B (checking for undefined symbols
    may be affected) (No such file or directory, errno = 2)

    I will show you my file tree, and you will see where I have everything
    ~
    |-> Project\
    |        |-> app\
    |        |        |-> app.xcodeproj
    |        |        '-> ...
    |        '-> frameworks\
    |                |-> Ours\
    |                |        '-> B\
    |                |            |-> B.xcodeproj
    |                |            '-> ...
    |                '-> thirdParties\
    |                        '-> A.framework\
    |-> BuildProducts\
      |-> app.build
      |-> Release\
      |  |-> app\
      |  '->B.framework\
      |    '-> Versions\
      |      '-> A\
      |      '-> Frameworks\
      |        '-> A.framework\
      |          '-> A
      '-> B.build\
    ...

    In consequence I physically see the files in the position it says it
    will take this files, but the program doesn't.
    I'm really messed UP with this. If you can help me, I will be more
    than glad.

    Please don't hesitate to ask anything about it, I will be glad to
    answer you.
    Thanx

    Julio

    > The "install_name_tool" only works if the new install_name is no
    > longer than the old one. Fortunately, @loader_path is shorter than
    > @executable_path, and the rest is identical. That limitation is
    > worth keeping in mind for future use though.
    >
    > sherm--
    >
    > Cocoa programming in Perl: http://camelbones.sourceforge.net
    > Hire me! My resume: http://www.dot-app.org
    >
  • On May 4, 2006, at 6:26 PM, Julio Bianco wrote:

    > /usr/bin/ld: warning can't open dynamic library: @loader_path/../
    > Frameworks/i1C.framework/Versions/A/i1C referenced from: /Users/
    > jbianco/BuildProducts/Release/TCFwkEyeOne.framework/TCFwkEyeOne
    > (checking for undefined symbols may be affected) (No such file or
    > directory, errno = 2)

    ...

    > |        '->B.framework\
    > |                '-> Versions\
    > |                        '-> A\
    > |                            '-> Frameworks\
    > |                                    '-> A.framework\
    > |                                            '-> A

    Note that the binary path in the message is TCFwkEyeOne.framework/
    TCFwkEyeOne - not Versions/A/TCFwkEyeOne. So @loader_path resolves to
    TCFwkEyeOne.framework- not Versions/A.

    If you want to put A.framework in a version-specific subdirectory,
    you need to set up a symlink at the expected path in Frameworks/ that
    points to it. It expects to see it there a compile time, so that it
    can read the install_path from it that will be used to find it at run
    time.

    B.framework\
      |->Frameworks\
      A.framework -> ../Versions/A/Frameworks/A.framework

    The same kind of symbolic linking is how versioning is done. The
    files under the .framework directory are just symlinks to the latest
    version in Versions/. When you're linking a new app, the linker is
    looking under the top-level .frameworks/ and you get the latest
    version. But the install_name is used at runtime, and that can bypass
    the symlinks and point directly to a specific version.

    That can help avoid the "dll hell" problem by allowing multiple
    versions of a bundle to exist at the same time, and the apps that
    link them to link against the specific version they need.

    sherm--

    Cocoa programming in Perl: http://camelbones.sourceforge.net
    Hire me! My resume: http://www.dot-app.org
  • Hi one more time,
    I'm trying to do that you tell me to do, but I have son issues with
    that.
    I create a framework with a basic class that have a float variable,
    and a method that assign 1.0 to this variable.
    I've another framework that uses the first one, and have a variable
    float and a method that initialize and assign to their variable the
    first class value (1.0) and increment in one, and I create an
    application that uses the second and shows the value of this method,
    and any time we press a button, calls the 2nd frame method,
    incrementing in one and showing the new value.
    When I run it as debug, everything goes right, but when I try to
    build it as release, I've got the same error I've with the previous
    configuration (that one that I use calling the framework provided for
    somebody else). I try to do everything you tell me to do in your
    previous email, but it doesn't work neither.
    I don't know what else to do. Can you guide me a little more?

    Thanx
    Julio

    On May 5, 2006, at 1:34 AM, Sherm Pendley wrote:

    > On May 4, 2006, at 6:26 PM, Julio Bianco wrote:
    >
    >> /usr/bin/ld: warning can't open dynamic library: @loader_path/../
    >> Frameworks/i1C.framework/Versions/A/i1C referenced from: /Users/
    >> jbianco/BuildProducts/Release/TCFwkEyeOne.framework/TCFwkEyeOne
    >> (checking for undefined symbols may be affected) (No such file or
    >> directory, errno = 2)
    >
    > ...
    >
    >> |        '->B.framework\
    >> |                '-> Versions\
    >> |                        '-> A\
    >> |                            '-> Frameworks\
    >> |                                    '-> A.framework\
    >> |                                            '-> A
    >
    > Note that the binary path in the message is TCFwkEyeOne.framework/
    > TCFwkEyeOne - not Versions/A/TCFwkEyeOne. So @loader_path resolves
    > to TCFwkEyeOne.framework- not Versions/A.
    >
    > If you want to put A.framework in a version-specific subdirectory,
    > you need to set up a symlink at the expected path in Frameworks/
    > that points to it. It expects to see it there a compile time, so
    > that it can read the install_path from it that will be used to find
    > it at run time.
    >
    > B.framework\
    > |->Frameworks\
    > A.framework -> ../Versions/A/Frameworks/A.framework
    >
    > The same kind of symbolic linking is how versioning is done. The
    > files under the .framework directory are just symlinks to the
    > latest version in Versions/. When you're linking a new app, the
    > linker is looking under the top-level .frameworks/ and you get the
    > latest version. But the install_name is used at runtime, and that
    > can bypass the symlinks and point directly to a specific version.
    >
    > That can help avoid the "dll hell" problem by allowing multiple
    > versions of a bundle to exist at the same time, and the apps that
    > link them to link against the specific version they need.
    >
    > sherm--
    >
    > Cocoa programming in Perl: http://camelbones.sourceforge.net
    > Hire me! My resume: http://www.dot-app.org
    >
  • On May 9, 2006, at 11:06 AM, Julio Bianco wrote:

    > When I run it as debug, everything goes right, but when I try to
    > build it as release, I've got the same error I've with the previous
    > configuration (that one that I use calling the framework provided
    > for somebody else).

    Have you tried doing a clean build? Deleting the build folder?

    > I try to do everything you tell me to do in your previous email,
    > but it doesn't work neither.
    > I don't know what else to do. Can you guide me a little more?

    It "doesn't work" in what way? I told you what was wrong, and where
    you should be copying the "inner" framework to:

    >> If you want to put A.framework in a version-specific subdirectory,
    >> you need to set up a symlink at the expected path in Frameworks/
    >> that points to it. It expects to see it there a compile time, so
    >> that it can read the install_path from it that will be used to
    >> find it at run time.
    >>
    >> B.framework\
    >> |->Frameworks\
    >> A.framework -> ../Versions/A/Frameworks/A.framework

    The "inner" A.framework can be either the framework itself, or as it
    indicates above, a symlink to a specific version of A.framework.

    Things to check:

    A.framework should have an install path of "@loader_path/../
    Frameworks/A.framework/A".

    B.framework should have an install path of "@executable_path/../
    Frameworks/B.framework/B".

    B.framework should include a "copy files" build phase that copies
    A.framework into its Frameworks folder.

    Foo.app should include a "copy files" build phase that copies
    B.framework into its Frameworks folder.

    sherm--

    Cocoa programming in Perl: http://camelbones.sourceforge.net
    Hire me! My resume: http://www.dot-app.org