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



