Showing posts with label Linux. Show all posts
Showing posts with label Linux. Show all posts

Thursday, January 6, 2011

CMake - Install - Linux and OS X

As described in previous posts deploying a program that uses an embedded copy of Firebird requires shipping some database server files. For Windows this can be done by the software that creates the installation package.

For Linux and OS X it is possible to use the CMake INSTALL command. This command creates an INSTALL target in your development tool: buiding that target will copy files to the folder specified by the CMAKE_INSTALL_PREFIX variable.
This can be used to copy the compiled program, the Firebird runtime and other files as needed to the install folder. Then the install folder will contain a ready to run copy of the program, with all the needed files.

First use a variable to store the path of the files used by the Firebird embedded server. I keep them in a folder that has the same structure as the deployed files. Here is an example:

  # look for the folder containing the firebird embedded files to ship with the program
  find_path( FB_EMBEDDED_PATH firebird.conf ${PROJECT_SOURCE_DIR}/firebird_runtime ${PROJECT_SOURCE_DIR}/../../firebird_embedded_2.0.4_runtime )
  message( STATUS "Embedded firebird files path: " ${FB_EMBEDDED_PATH} )

At the end of CMakeLists.txt add code like this:

install( TARGETS vvv DESTINATION . )

if( APPLE )
  # copy the Firebird runtime
  install( DIRECTORY ${FB_EMBEDDED_PATH}/ DESTINATION vvv.app/Contents/MacOS USE_SOURCE_PERMISSIONS )
  install( FILES ${FB_EMBEDDED_PATH}/firebird/firebird.msg DESTINATION vvv.app/Contents/MacOS/firebird/bin/firebird )
  # fix filename references in the runtime
  set( FIXUP_COMMAND ${PROJECT_SOURCE_DIR}/MACOSX_fixup_bundle.sh " " ${CMAKE_INSTALL_PREFIX}/vvv.app )
  install( CODE "execute_process( COMMAND ${FIXUP_COMMAND} )" )
endif( APPLE )

if( UNIX AND NOT APPLE )
  # copy the Firebird runtime
  install( DIRECTORY ${FB_EMBEDDED_PATH}/ DESTINATION . USE_SOURCE_PERMISSIONS )
  # copy other files used only for the Linux version
  install( FILES ${PROJECT_SOURCE_DIR}/linux_specific/readme.txt
                 ${PROJECT_SOURCE_DIR}/linux_specific/License.txt
                 DESTINATION . )
  install( FILES ${PROJECT_SOURCE_DIR}/linux_specific/vvv-start.sh
                 DESTINATION . PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE
                                           GROUP_READ WORLD_READ WORLD_EXECUTE )
endif( UNIX AND NOT APPLE )

if( UNIX )
  # set the installation path of the executable file and the resources (in OS X they are inside the bundle )
  if( APPLE )
    set( EXECUTABLE_INTALL_PATH vvv.app/Contents/MacOS )
    set( RESOURCES_INTALL_PATH vvv.app/Contents/Resources )
  else( APPLE )
    set( EXECUTABLE_INTALL_PATH . )
    set( RESOURCES_INTALL_PATH . )
  endif( APPLE )



  # copy other files to the installation path
  install( FILES ${PROJECT_SOURCE_DIR}/vvv-struct-update.fdb
                 ${PROJECT_SOURCE_DIR}/VVV.fbk
                 ${PROJECT_SOURCE_DIR}/help/en/vvv.htb
                 DESTINATION ${EXECUTABLE_INTALL_PATH} )


endif( UNIX )

Under OS X CMake will execute a script named MACOSX_fixup_bundle.sh to patch the dylibs as described here. CMake has some support to automatically fix things like these: I struggled for some time but I was not able to understand how it works. Documentation is scarce to I gave up and I decided to directly run a script.
Here is the script used by CMake:

#!/bin/bash

# this script will fix the components of the Firebird runtime to make it run from any location

# the script receives the path of the bundle to fix
BUNDLEPATH=$*

# the following line contains the name of the executable file that will be patched
# it is the only line that should be changed when copying this file to another project
EXECFILE=${BUNDLEPATH}/Contents/MacOS/vvv

LIBPATH=${BUNDLEPATH}/Contents/MacOS/firebird
LIBBINPATH=${BUNDLEPATH}/Contents/MacOS/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}



You will need to edit the EXECFILE definition (near the file top) to change the name from "vvv" to your program's name.

Thursday, November 25, 2010

Compiling Firebird in Linux

Firebird is available as a precompiled binary for Linux, but it is compiled using very old software, probably to make sure that it can run in any distribution.
The software is compiled using libstdc++.so.5 while current compilers use libstdc++.so.6.

This is OK for normal use but it causes problems when my program links to the Firebird library. I just compiled a 64 bit version of a program and I had the same problems again. As usual the solution was building Firebird from source. This was not difficult but it took some time to figure out how to proceed, so this time I took notes for the future.

Here are the steps to build Firebird 2.0.x. I did not test other versions, but things should not be very different.

The following packages are required to build the software:


bison
automake1.4
libtool
libncurses5-dev


After installing the packages open a terminal window, move to the root folder of the downloaded code and enter the following commands:


./autogen.sh
./configure --prefix=/media/disco2/firebird-2.0.6-installed
make
make install


The "configure" line is needed only if you want to change the default install path, like in my example.
"make install" is needed to strip the files that otherwise would be very large.

Friday, June 4, 2010

Firebird embedded - Linux

A great feature of the Firebird database is the ability to ship an embedded database with you program. No need for a separate installation and no conflicts with other installations, just copy some files.
The embedded model is officially supported only for Windows. For this operating system everything is simple: just download the embedded server and follow the documentation.

It is possible to deploy an embedded Firebird database also under Linux, even if this is not officially documented. I started from information from Milan Babuskov, currently available here:

http://www.firebirdfaq.org/Firebird-Embedded-Linux-HOWTO.html

That page is about version 1.5: I made some simple changes and used version 2.0.x. It should also work with version 2.1.

First I downloaded the classic server (superserver does not work). For an embedded server you need to link to libfbembed.so, which contains a full server. libfbclient.so contains only the client library: it is smaller but it can only connect to a full server.
At first I linked to the files that I downloaded from the Firebird site, but I got warnings because the Firebird library used libstdc++.so.5 and my compiler used libstdc++.so.6. It turns out that Firebird is compiled with a very old compiler version for better portability.
This is not a problem when the server is used in the normal way, but it causes those warnings when I link a program to the Firebird library. I do not know if this could be a real problem, but I ended up compiling Firebird from source. It is a rather simple task (I have been able to do it!), just remember to run 'make install' to strip the resulting files. Here are some info about the compilation:

http://firebird.1100200.n4.nabble.com/Size-problem-compiling-Firebird-2-0-3-in-Linux-tt1120181.html#none

To ship an embedded Firebird database with your program you need to deploy the following files and subfolders in the folder that contains the program itself:

fulvio@fulvio-ubuntu:~/Desktop/VVV-Release-Pack$ ls --format=single-column -R
.:
firebird
firebird.conf
vvv (main program)
vvv-start.sh

./firebird:
bin
firebird.msg
intl
libfbembed.so
libfbembed.so.2
libfbembed.so.2.0.4
libicudata.so
libicudata.so.30
libicudata.so.30.0
libicui18n.so
libicui18n.so.30
libicui18n.so.30.0
libicuuc.so
libicuuc.so.30
libicuuc.so.30.0
security2.fdb

./firebird/bin:
fb_lock_mgr
gbak
isql

./firebird/intl:
fbintl
fbintl.conf

Notice that many .so files are symbolic links.

You will need to edit the firebird.conf file. Look for the line containing "RootDirectory" and change it in this way:
RootDirectory = ./firebird
Notice that lines starting with '#' are comments: you must remove that character from this line.

Now you must create a script to start your program. In the example above it is called vvv-start.sh. The file must contain the following lines:

export LD_LIBRARY_PATH=./firebird
export FIREBIRD=.
./vvv

where the last line contains the name if the program to run, in this case vvv.

Now you should be able to start your program executing the script. You cannot directly execute the program because it needs the environment variables set by the script.