• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Different versions of framework?
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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


  • Follow-Ups:
    • Re: Different versions of framework?
      • From: Mark Lilback <email@hidden>
References: 
 >Different versions of framework? (From: Fabian Lidman <email@hidden>)

  • Prev by Date: Re: NSString initWithData: NSUTF8StringEncoding - returns 'nil'
  • Next by Date: Re: NSBezierCurve and Line Width
  • Previous by thread: Different versions of framework?
  • Next by thread: Re: Different versions of framework?
  • Index(es):
    • Date
    • Thread