I have created a new cocoa framework in Xcode, removed all the libraries and files it includes at the beginning except the supporting files.
I have 2 files:
add.h
#ifndef add_add_h
#define add_add_h
void add(void);
#endif
and
add.c
#include <stdio.h>
#include "add.h"
void add(void)
{
printf("adfding");
}
in build phases I add add.c to compile sources and add.h to compile headers public. The project build without a problem but in the framework there is no dylib file and when I drag and drop the framework to another project it says that dylib file could not be found.
dyld: Library not loaded: @rpath/add.framework/Versions/A/add
Referenced from: /Users/vjoukov/Desktop/Projects/test/build/Debug/test.app/Contents/MacOS/test
Reason: image not found
How can I make a simple framework and keep dylib files inside it ?
I think you're misunderstanding the error message.
A .framework
works as a dynamic library, but there won't be any Mach-O loadable object file with an actual .dylib
filename extension inside the .framework folder.
There are a couple of reasons you might be getting that error message from dyld
, the dynamic link library loader, at runtime. The first is that you forgot to copy the .frameworks into the built application bundle during the build process. While they can be copied to about any location inside the app bundle, the traditional place is in AppName.app/Contents/Frameworks/. If you haven't done so already, choose Project > New Build Phase > New Copy Files Build Phase. Change the Destination popup to Frameworks like in the image below.
You'll then drag the icon of the framework into the folder so that it's copied during the build process.
The second and more likely reason the framework can't be found at runtime is that you haven't specified any runpath search paths for your main executable. (This is needed, because, as we saw from your error message, your framework was built using the newer @rpath/
style install name (@rpath/add.framework/Versions/A/add
) rather than the older @executable_path/
or @loader_path/
styles).
Provided you copy the custom frameworks to the location mentioned above, you'd add a runpath search path entry of @loader_path/../Frameworks
, like shown in the image below:
The following excerpt that explains how dynamic libraries are found at runtime is from the manpage of dyld
:
DYNAMIC LIBRARY LOADING
Unlike many other operating systems, Darwin does not locate dependent dynamic libraries via their leaf file name. Instead the full path to each dylib is used (e.g.
/usr/lib/libSystem.B.dylib
). But there are times when a full path is not appropriate; for instance, may want your binaries to be installable in anywhere on the disk. To support that, there are three@xxx/
variables that can be used as a path prefix. At runtimedyld
substitutes a dynamically generated path for the@xxx/
prefix.
@executable_path/
This variable is replaced with the path to the directory containing the main executable for the process. This is useful for loading dylibs/frameworks embedded in a .app directory. If the main executable file is at
/some/path/My.app/Contents/MacOS/My
and a framework dylib file is at
/some/path/My.app/Contents/Frameworks/Foo.framework/Versions/A/Foo
, then the framework load path could be encoded as@executable_path/../Frameworks/Foo.framework/Versions/A/Foo
and the .app directory could be moved around in the file system anddyld
will still be able to load the embedded framework.
@loader_path/
This variable is replaced with the path to the directory containing the mach-o binary which contains the load command using
@loader_path
. Thus, in every binary,@loader_path
resolves to a different path, whereas@executable_path
always resolves to the same path.@loader_path
is useful as the load path for a framework/dylib embedded in a plug-in, if the final file system location of the plugin-in unknown (so absolute paths cannot be used) or if the plug-in is used by multiple applications (so@executable_path
cannot be used). If the plug-in mach-o file is at/some/path/Myfilter.plugin/Contents/MacOS/Myfilter
and a framework dylib file is at/some/path/Myfilter.plugin/Contents/Frameworks/Foo.framework/Versions/A/Foo
, then the framework load path could be encoded as@loader_path/../Frameworks/Foo.framework/Versions/A/Foo
and theMyfilter.plugin
directory could be moved around in the file system anddyld
will still be able to load the embedded framework.
@rpath/
Dyld maintains a current stack of paths called the run path list. When
@rpath
is encountered it is substituted with each path in the run path list until a loadable dylib if found. The run path stack is built from theLC_RPATH
load commands in the depencency chain that lead to the current dylib load. You can add anLC_RPATH
load command to an image with the-rpath
option told
(1). You can even add aLC_RPATH
load command path that starts with@loader_path/
, and it will push a path on the run path stack that relative to the image containing theLC_RPATH
. The use of@rpath
is most useful when you have a complex directory structure of programs and dylibs which can be installed anywhere, but keep their relative positions. This scenario could be implemented using@loader_path
, but every client of a dylib could need a different load path because its relative position in the file system is different. The use of@rpath
introduces a level of indirection that simplies things. You pick a location in your directory structure as an anchor point. Each dylib then gets an install path that starts with@rpath
and is the path to the dylib relative to the anchor point. Each main executable is linked with-rpath @loader_path/zzz
, wherezzz
is the path from the executable to the anchor point. At runtimedyld
sets it run path to be the anchor point, then each dylib is found relative to the anchor point.