Deploying an embedded Firebird database in an OS X bundle is similar to deploying it for Linux, but there are more problems to solve. This might not be the best solution, but it works so it can be at least a good starting point.
First I copied the files that I needed from the Firebird Framework folders to another folder. For example, let's call it
/Users/fulvio/firebird_runtime.
Then I renamed the
Firebird file to
libfbembed.dylib: this is probably not necessary but I feel better using the same filename as in other platforms.
Files structureI create the application as a bundle. The executable file is stored in the folder
Contents/MacOS inside the bundle. In this same folder i also store:
firebird.conf
firebird (a folder)
..firebird.msg
..libfbembed.dylib
..libicudata.dylib
..libicui18n.dylib
..libicuuc.dylib
..security2.fdb
..bin (a folder)
....fb_lock_mgr..
....gbak
....isql
....firebird (a folder)
......firebird.msg
..intl (a folder)
....fbintl.conf
....fbintl.dylibI used dots instead of spaces to indent because the blog editor keeps ignoring leading spaces.
Indented files are stored it the folder above them so, for example, gbak is stored in the bundle as
Contents/MacOS/firebird/bin/gbak.
I added some "copy files" build phase in XCode to copy the Firebird files from
/Users/fulvio/firebird_runtime to the bundle.
LinkingI link the program against
/Users/fulvio/firebird_runtime/libfbembed.dylib adding the following text to
Other linker flags:
-L/Users/fulvio/firebird_runtimeand adding the Firebird .dylib files to the "Link Binary With Libraries" build phase in XCode.
Environment variablesThe next step is to set the FIREBIRD environment variable to the executable folder.
The command line is "export FIREBIRD=."
The same result can be obtained adding
<key>LSEnvironment</key>
<dict>
<key>FIREBIRD</key>
<string>.</string>
</dict>
to the
Info.plist file contained in the bundle.
firebird.confOpen the "firebird.conf" file and look for
#RootDirectory. The leading pound sign means that the line is commented. Change it to:
RootDirectory = ./firebirdnote that the line is not commented any more.
PatchingThe bundle still doesn't work because the program looks for the libraries in the original framework's location, not in the bundle.
.dylib files contain their original full path and the original full path of all the used libraries, and executable files do the same. You can verify this running the
otool -L and
otool -D commands.
I solved this problem using the
install_name_tool command that changes the file reference contained in libraries and executables. It only works if the new paths are not longer than the old ones, but this is not a problem for us. I use a "Run Script" build phase in XCode to execute the following script:
#!/bin/bash
EXECFILE=${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}
LIBPATH=${BUILT_PRODUCTS_DIR}/${EXECUTABLE_FOLDER_PATH}/firebird
LIBBINPATH=${BUILT_PRODUCTS_DIR}/${EXECUTABLE_FOLDER_PATH}/firebird/bin
# path of library files relative to the main executable
NEWLIBPATH="@executable_path/firebird"
# path of library files relative to other library files
NEWLIBPATH_FOR_LIBS="@loader_path"
# path of library files relative to executables in the "firebird/bin" folder
NEWLIBPATH_FROM_BIN="@loader_path/.."
OLDLIBPATH="/Library/Frameworks/Firebird.framework/Versions/A/Libraries"
OLDLIBFBEMBEDFILENAME="/Library/Frameworks/Firebird.framework/Versions/A/Firebird"
# change the references in the files contained in the "firebird" folder
for TARGET in libfbembed.dylib libicudata.dylib libicui18n.dylib libicuuc.dylib ; do
LIBFILE=${LIBPATH}/${TARGET}
OLDTARGETID=${OLDLIBPATH}/${TARGET}
NEWTARGETID=${NEWLIBPATH}/${TARGET}
NEWTARGETID_FOR_LIBS=${NEWLIBPATH_FOR_LIBS}/${TARGET}
install_name_tool -id ${NEWTARGETID_FOR_LIBS} ${LIBFILE}
install_name_tool -change ${OLDTARGETID} ${NEWTARGETID} ${EXECFILE}
for POSSIBLECALLERNAME in libfbembed.dylib libicudata.dylib libicui18n.dylib libicuuc.dylib ; do
POSSIBLECALLERFILE=${LIBPATH}/${POSSIBLECALLERNAME}
install_name_tool -change ${OLDTARGETID} ${NEWTARGETID_FOR_LIBS} ${POSSIBLECALLERFILE}
done
done
# change the references in the files contained in the "firebird/bin" folder
for TARGET in gbak isql ; do
FILE=${LIBBINPATH}/${TARGET}
for POSSIBLECALLEDNAME in libfbembed.dylib libicudata.dylib libicui18n.dylib libicuuc.dylib ; do
OLDTARGETID=${OLDLIBPATH}/${POSSIBLECALLEDNAME}
NEWTARGETID=${NEWLIBPATH_FROM_BIN}/${POSSIBLECALLEDNAME}
install_name_tool -change ${OLDTARGETID} ${NEWTARGETID} ${FILE}
done
# change the reference to libfbembed into the program, that contains a reference to a different name (the framework name)
NEWTARGETID=${NEWLIBPATH_FROM_BIN}/libfbembed.dylib
install_name_tool -change ${OLDLIBFBEMBEDFILENAME} ${NEWTARGETID} ${FILE}
done
# change the reference to libfbembed into the caller program, that contains a reference to a different name (the framework name)
NEWTARGETID=${NEWLIBPATH}/libfbembed.dylib
install_name_tool -change ${OLDLIBFBEMBEDFILENAME} ${NEWTARGETID} ${EXECFILE}
I learned something about .dlybs patching from
http://ynniv.com/blog/2006/02/deploying-app-that-use-dylibs-on-mac.htmlbut this link does not seem to work any more.