Re: Different versions of framework?
Re: Different versions of framework?
- Subject: Re: Different versions of framework?
- From: Bob Ippolito <email@hidden>
- Date: Fri, 3 Dec 2004 13:13:17 -0500
On Dec 3, 2004, at 10:40 AM, Fabian Lidman wrote:
Q: What is the correct procedure to link a framework into the
application bundle, making sure the application looks there first
instead of in /Library/Frameworks?
We have run into a situation where several different applications each
require a separate version of a framework; namely, Apache's Xerces.
Version 2.3 of the framework is installed into Library/Frameworks. The
application i'm responsible for needs to use Xerces 2.6, so i guess
i'll need to link it into the bundle somehow. Unfortunately, i'm
unable to figure out how to handle this without creating conflicts
between the two frameworks.
I've been meaning to post this to my blog, but I've been having
software issues so I'm in between blogging software.. but here's the
content, which might answer some of your question:
------------------
It has recently come to my attention that using versioned frameworks
without binary compatible APIs simply doesn't work. This isn't a
problem with the dyld runtime, simply a problem with gcc's compiler and
linker. A big one.
**Frameworks**
Mac OS X frameworks are structured in such a way that allow for
versioned code, data, and headers. A typical multi-versioned framework
looks something like this::
Foo.framework/
Foo -> Versions/Current/Foo
Headers -> Versions/Current/Headers
Resources -> Versions/Current/Resources
Versions/
Current -> 2.0
2.0/
Foo
Headers/
Resources/
1.0/
Foo
Headers/
Resources/
**Mach-O, MH_DYLIB, and the dyld runtime**
The ``MH_DYLIB`` object file, the part that you link to, is "Foo". If
this were not a framework, it would have the following layout, and it
would be application-specific to put the headers and resources in the
right place::
libFoo.dylib -> libFoo.2.0.dylib
libFoo.1.0.dylib
libFoo.2.0.dylib
Due to the way that ``MH_DYLIB`` object files work, each of these
dylibs know their own (supposed) location on the filesystem. This is
called the "install name" or the "id" of the dylib. Technically, this
is a ``LC_ID_DYLIB`` load command in the Mach-O header. When you
create an Mach-O object file (executable, dylib, bundle, etc.) that
depends on another, it will generate a load command (``LC_LOAD_DYLIB``)
referencing the other dylib. The data associated with the
``LC_LOAD_DYLIB`` is exactly the same data that was provided by the
linked-to ``MH_DYLIB`` in its ``LC_ID_DYLIB`` load command, unless
explicitly overrided with the ``-dylib_file`` option to `ld(1)`_ or
rewritten post-link with a tool such as `install_name_tool(1)`_. The
`otool(1)`_ tool can be used to view these load commands in a Mach-O
file, among other things. It's very important to have these values set
correctly because they are used by the dyld runtime to locate the
intended ``MH_DYLIB``.
**gcc, ld, and frameworks**
Apple's GCC includes many changes to support Objective C/C++ and
framework based development. Unfortunately, none of them have any
explicit support for versioned frameworks. For example, `gcc(1)`_
states that it uses the following algorithm for finding frameworks in
headers::
-Fdir
In Apple's version of GCC only, add the directory dir to the
head
of the list of directories to be searched for frameworks.
The framework search algorithm is, for an inclusion of
<Fmwk/Header.h>, to look for files named
path/Fmwk.framework/Head-
ers/Header.h or path/Fmwk.framework/PrivateHeaders/Header.h
where
path includes /System/Library/Frameworks/
/Library/Frameworks/, and
/Local/Library/Frameworks/, plus any additional paths
specified by
-F.
All the ``-F`` options are also passed to the linker.
`ld(1)`_ has an similar option, ``-framework``, which has a similar
algorithm::
-framework name[,suffix]
Specifies a framework to link against. Frameworks are
dynamic
shared libraries, but they are stored in different
locations,
and therefore must be searched for differently. When this
option
is specified, ld searches for framework
`name.framework/name'
first in any directories specified with the -F option,
then in
the standard framework directories
/Library/Frameworks, /Net-
work/Library/Frameworks, and
/System/Library/Frameworks. The
placement of the -framework option is significant, as it
deter-
mines when and how the framework is searched. If the
optional
suffix is specified the framework is first searched for
the name
with the suffix and then without.
Note that neither of these options allow for any consideration for the
Versions directory in a framework, and therefore only link to whichever
version was installed last, because the installation process for a
framework will create the symlinks that point to locations inside the
Versions directly.
**Workaround**
Unfortunately, since there is no support or hook that will allow proper
usage of versioned frameworks, the workarounds are all ugly. I think
the following workaround is the most appropriate: *Just Don't Use GCC's
Search Algorithms*.
- Always use the compiler option
``-I/Path/To/Foo.framework/Versions/IntendedVersion/Headers``
- use ``#include "Foo.h"`` instead of ``#include <Foo/Foo.h>`` in your
sources
- Always use the direct path to the ``MH_DYLIB`` rather than any
combination of ``-framework`` and ``-F``.
- Or, if you're building extension bundles that will be used by an
executable that already has the correct version of Foo linked in, use
the ``-undefined dynamic_lookup`` linker option
A minimal compiler/link line for an executable would look like the
following::
cc -I/Path/To/Foo.framework/Versions/IntendedVersion/Headers -o
usesFoo usesFoo.m /Path/To/Foo.framework/IntendedVersion/Foo
And a minimal compiler/link line for an extension bundle would look
like::
env MACOSX_DEPLOYMENT_TARGET=10.3 cc
-I/Path/To/Foo.framework/Versions/IntendedVersion/Headers -o
fooUsingExtension.bundle fooUsingExtension.m -bundle -undefined
dynamic_lookup
Quite ugly, eh? At least it works as intended. Unfortunately you'll
need to emulate enough of GCC's search algorithms to find the
framework, which is probably quite problematic from Xcode, but
shouldn't be too hard from say, `distutils`_, `SCons`_, `autoconf`_,
etc. Note that you should also probably consider the ``NEXT_ROOT``
environment variable for when building against an SDK.
.. _`gcc(1)`: x-man-page://1/gcc
.. _`ld(1)`: x-man-page://1/ld
.. _`install_name_tool(1)`: x-man-page://1/install_name_tool
.. _`otool(1)`: x-man-page://1/otool
.. _`distutils`:
http://www.python.org/doc/current/lib/module-distutils.html
.. _`SCons`: http://www.scons.org/
.. _`autoconf`: http://www.gnu.org/software/autoconf/
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden