Build a MacOSX Universal Hugin bundle with Xcode
THIS IS STILL A DRAFT VERSION
The "normal" way of compiling Hugin is via Cmake. With the current versions of MacPorts, Fink and Cmake it is very difficult to make a universal bundle due to the way endianness is dealt with in MacPorts and Fink. This HowTo explains how to make a universal bundle with Xcode.
The creation of a bundle is actually a two step process:
- Build all libraries and binaries which Hugin depends on. This is done outside Xcode. From here on we will call these libraries and binaries "External Programs". To compile and build all "External Programs" as universal, we will follow a different process compared to the normal "straight-forward" process of building libraries with MacPorts or Finks as described in Hugin Compiling OSX. We do not need nor use MacPorts and/or Fink. Some may even prefer to put them "out of the way" in order to make sure we will not link with the libraries they provide. However, they provide convenient ways to install a few of the tools that we require in the later process.
- Build Hugin and it's "internal" tools in Xcode and create the bundle. As the title suggests: This is done in Xcode.
Note: This Howto does not explain how to build a Hugin the "cmake way". Follow the Howto Hugin Compiling OSX.
You should have Mac OS X 10.4 or above. Older systems are not recommended and how to build on those systems will not be included in this document.
Download and install XCode
Download and install the latest version of XCode Tools for your Mac OS X: Xcode 2.4.x for Mac OS X 10.4 (Tiger) and Xcode 3.x for 10.5 (Leopard). For Mac OS X 10.3.9 compatibility, we currently use 10.3.9 SDK which you can either turn on with custom install, or install separately from MaxOSX10.3.9.pkg in the "Packages" folder.
Leopard comes with SVN installed. If you are on Tiger, you need to install it yourself. The simplest way to get SVN is to use MacPorts or Fink.
If you fancy a nice GUI you can download the Open-Source SVNX. You still need svn installed as it is only a graphical shell and I won't explain SVNX here (I only used it once, I still prefer the terminal).
You may also find SCPlugin handy for some quick operations.
Preparations for building the "External Programs"
Building the necessary "External Programs" (the libraries and binaries Hugin depends on) is completely scripted. This part describes not how to use "./configure" or "make; make install". It will explain (advise) how and where to create the necessary directory structure, configure the base environment script and, more or less, tell you in which order to run the package build scripts.
Location of the "External Programs" development tree
This part describes where we want to place the development tree for our "External Programs" that hugin depends on. Although the "External Programs" directory structure is placed inside the Hugin SVN tree by default, this does not necessarily need to be in the same place as the Hugin source itself. The easiest way to place those files in custom places is to put symbolic link in the default place.
The first question is: where do you want to have your development tree? As you (might) know, the "normal" location is /usr/local, and MacPorts uses /opt/local by default and Fink, /sw. We do not want to use these locations!
Apart from the fact that it is a bad idea to mix up development trees, another drawback is that these directories are not in "user space", therefore always requiring a root authorization, e.g. "sudo make install" as a last step. When keeping the development tree in user space (e.g. /Users/<your_username>/development/ or /Users/Shared/development/), you don't need to "sudo". Note that the latter option also creates a development directory but keeps it away from your "normal" user data.
So, from this moment "we" have decided to build our development tree in user space.
Note: As mentioned before: If you position your development tree outside user space, you need to run everything as root user. The scripts are not tailored towards that "sudo" kind of use and need modification to work that way.
Inside hugin SVN tree
The "External Programs" development tree is placed inside the hugin SVN tree when you download Hugin. After you downloaded Hugin from SVN, you will find inside the hugin directory the following directory structure:
- /...other directories inside hugin
- /<more files inside mac>
- /...other directories inside hugin
Say you have downloaded hugin in /Users/<your_username>/development (Remember that "we" decided to keep it in user space?), than your "External Programs" build tree will be inside /Users/<your_username>/development/hugin/hugin/mac/ExternalPrograms/.
Note: You will also find a mac directory inside the platforms directory. This hugin/platforms/mac/ directory is not meant for compiling cross-platform tools, but for hosting platform specific tools like Erik Krause's droplet scripts, which you will find in platforms/windows.
Outside Hugin SVN tree
Based on what I explained above you could also decide to place your build tree for the "External Programs" outside the hugin SVN tree. An option might be /Users/<your_username>/development/ExternalPrograms/.
Pro's and Cons of "outside" Hugin SVN tree
- You have your "External Programs" build tree separate from the hugin source. You can delete and recreate the Hugin SVN directory anyway and anytime you want without touching your carefully built "External Programs".
- If you plan to build more universal software using this approach, you can share this directory (or just as well build another one).
- Many of the default paths assume the "inside" approach; you will have to map some of the directories with symbolic link.
Creation of the "External Programs" development tree
If you leave the "External Programs" development tree inside the Hugin SVN tree, you don't have to do anything and for simplicity this HowTo focuses on that way of working.
If you want to create it outside the hugin svn tree, I advise you to first create a development directory inside your home directory and to create the ExternalPrograms directory inside that development directory. Currently some part of hugin's Xcode project assumes the "binary repository" (explained below) is located at mac/ExternalPrograms/repository, inside the same directory as the source code you have downloaded with SVN.
The recommended for "outside" approach is to:
- make your "External Programs" directory
- place symbolic link to the "binary repository" directory in your "External Programs" directory at /<path_to_hugin_source>/mac/ExternalPrograms/repository
- optionally place symbolic link to /<path_to_hugin_source>/mac/ExternalPrograms/scripts in your "External Programs" directory
$ mkdir -p "$myExternalProgramsDir"
$ mkdir -p "$myExternalProgramsDir/Repository-dynamic"
$ ln -s "$myExternalProgramsDir/Repository-dynamic" "$myPathToHuginSource/mac/ExternalPrograms/repository"
$ ln -s "$myPathToHuginSource/mac/ExternalPrograms/scripts" "$myExternalProgramsDir/scripts"
Prepare the build environment
Our build environment uses a lot of preset environment variables. The template of those variables can be found inside hugin/mac/ExternalPrograms/scripts, named "SetEnv-universal.txt" and "SetEnv-leopard.txt". SetEnv-universal.txt is for conventional 2-way universal binary, and SetEnv-leopard.txt is for 4-way universal binary with 64bit computing support. We take SetEnv-universal.txt in this document. Read #32bit versus 64bit for more info.
First, you should copy either of those files and name it "SetEnv.txt". In the top of this new file you will find the following two lines:
# has to be the absolute path from / myREPOSITORYDIR="/PATH2HUGIN/mac/ExternalPrograms/repository";
The path in the myREPOSITORYDIR variable needs to exactly match the path you use. This example show the (current) default one from the SVN. So, if you are Spiderman and you build inside your HOME directory you need to specify:
Check it, and check it again !!
You do not need to modify anything below this line, unless you are brave enough to customise something for yourself.
Building the "External Programs"
Building Subversion (SVN)
(Note: Tiger and earlier only)
Before being able to download Hugin from svn we need to have svn in place. If you are on Leopard (MacOSX 10.5.x), you are fine and you can skip this step. If you are on Tiger (MacOSX 10.4.x) or an earlier version you need to build it yourself.
You first need to Install Macports (if you did not already do so) as described in Hugin Compiling OSX. Then you need to install Subversion (svn) like:
$ sudo port install subversion
Get Hugin from SVNCd into your development tree and download hugin from svn like:
$ cd ~ $ cd development $ svn co https://hugin.svn.sourceforge.net/svnroot/hugin/hugin/trunk hugin
Inside /Users/<your_username>/development, you will now have a directory hugin. The full path to your "External Programs" development tree will be /Users/<your_username>/development/hugin/mac/ExternalPrograms.
Get MacPorts and/or Fink out of the way
Now we really need to get MacPorts and/or Fink out of the way. We want to make a completely separate development tree. This means that we do not want to link to any library or binary outside our "External Programs" development tree (unless they are true Mac system libraries that are part of your MacOSX version). If we accidentally do link to non-system libraries outside our tree we will have problems when we build the bundle and certainly when we want to distribute it. So to get them out of the way, we do the following:
$ sudo mv /opt /opt.org $ sudo mv /sw /sw.org $ sudo mv /usr/local /usr/local.org
Note: The usr/local is in case you have built libraries or binaries without MacPorts or Fink.
Note 2: Do not use "sudo mv /usr /usr.org" as /usr is vital for proper system functioning!!! If you accidentally do this, you need to reboot using your Mac DVD, go into the terminal and move it back.
Build the "External Programs"
Building the necessary libraries and binaries which Hugin depends on, the so called "External Programs" is now relatively easy.
- You cd into your ExternalPrograms subdirectory, like
- Download the necessary source packages (Google for it, copy them from your MacPorts and/or Fink base if available). The script names tell you which ones you need.
- untar/unbzip2 the source packages. It's best to do this in the ExternalPrograms directory so that you will have all kind of subdirectories containing the source, like jpeg-6b, tiff-3.8.2, enblend, wxMac-2.8.7 and so on.
And as an example for libpng:
$ bunzip2 libpng-1.2.24.tar.bz2 $ tar -xvf libpng-1.2.24.tar $ cd libpng-1.2.24
As mentioned in #Prepare the build environment we need to set our build environment before we can start compiling our libraries and binaries. This setting can be done anywhere from the system and doesn't need to been done from our library directory. But assuming we are still in our libpng directory we issue the command:
$ source ../scripts/SetEnv-universal.txt
Now we can really start building our libraries and binaries. You do this by calling the right shell compilation script (still using libpng as an example).
$ sh ../scripts/libpng.sh
Order of building the "External Programs"
Some libraries and programs are dependent on other libraries. This means that these libraries need to be built first. As a rule of thumb, build your libraries in the following order (shell script names): libjpeg.sh, libtiff.sh, libpng.sh, expat.sh, lcms.sh, ilmbase.sh, openexr16.sh, boost.sh, wxmac28.sh, pano13.sh, libexiv2.sh
And for the binaries: gnumake.sh, autopano-sift-C.sh, enblend31.sh, panomatic.sh
Note: You need to examine the scripts before executing them as some script use major and minor library numbers. These numbers are set from the script and need to be changed if your library version changes.
Apart from the wxmac (wxwindows) source tree, you can remove every library source tree if you want to.
The wxmac source tree is necessary for the Xcode project. Xcode needs the “localization” source files.
When you are finished building you can also reinstate the Macports or Fink directories you had disabled (see #Get MacPorts and/or Fink out of the way).
Xcode compiling Hugin
XCode basic walk-through
This HowTo will not discuss how to use XCode. It will only explain some very basic steps to get you going. The rest is up to you (Xcode - the Final Frontier...............To boldly go where no man has gone before.) Sometimes small changes need to be made to the Xcode project due to added tools (matchpoint recently) or added or removed source files. These kind of actions will not be explained either in this HowTo.
When you double-click the hugin.xcodeproj, Xcode will start and show you the following screen:
In the Top section you see the Menu/Toolbar.
On the left side you see the navigation panel.
On the right side you see the File section.
|In the left Navigation panel you see little triangles in front of the icons and their descriptions. These triangles can be used to open or close the sub-sections. Double-clicking the icons has another function and will bring you to the properties of that subsection. If you click the little triangle in front of Hugin, you see the directory structure of the files the Hugin project uses. Please note that this is not a real representation of the hugin directory but a user-created representation. Note however that the "files" in here are actually links to your real files. If you double-click them, the Xcode editor will open them for editing and save them back to the file system.|
|Below the Hugin icon/description, you'll find the Targets section. Here you need to define what needs to be compiled, linked, copied and so on to create a binary or library, or a bundle containing these binaries and libraries. In case of a complex build project like Hugin, you first need to compile underlying tools and libraries, than build hugin and link hugin against these underlying tools and libraries, and finally create the bundle including "some copy work" to get the "External Programs" like autopano-sift-c, panomatic, the PT* tools, enblend, enfuse and the like inside the bundle.|
Other options in the Navigation panel are not relevant or interesting, although you might see the error part quite frequently in your early attempts.
Prepare the project for our configuration
You need to tell the project where you installed your "External Programs" (wxmac, boost, libtiff and so on) to be able to compile Hugin. Also a couple of shell scripts need to be adapted. This can all be done from inside Xcode.
The first thing to do is to double-click the blue icon before Hugin in the top-left corner of the Navigation pane. If you do this, the following screen will open.
This "General" tab defines the location where your Hugin.app, and the intermediate files, will be built. By default a build directory will be created in the same directory where your Hugin.xcodeproj resides. If you want another location you can change that here, but unless you know what you're doing leave it as it is.
The second tab is the "Build" tab (see below).
You need to check, and if necessary change, the values for:
- Library Search Paths
- WX_MAJOR_VERSOIN (note that it says VERSOIN in stead of VERSION. Leave it like that!)
All path's are relative to the location of the hugin.xcodeproj directory structure. If you did build the libraries that Hugin depends on according the steps described above, you do not need to change anything. But do check!
The other tabs are not relevant, but feel free to expand your knowledge.
Prepare the scripts before building
| The project uses a couple of shell scripts to get everything into the bundle. In an Xcode project you can define steps for this in your Targets. These steps then consist of these scripts.
Note though that if these scripts are not correct, Xcode will generate a non-fatal error. However, this non-fatal error for Xcode will quite often be a fatal error for your final bundle as it will miss "something" and it will simply not run or not run correctly. Yoy can take a look at the target Hugin: Open Targets -> Hugin and double-click (for example) the entry "Complete bundle". This will show you how to embed scripts.Note however, that you do not edit the scripts from the Target(s) position. You edit the script inside the files section (see #XCode basic walk-through). In this project everything is already at it's correct position.
Move (back) in the navigation pane to the top of your project and open the top section (the "file" section), open the mac "directory" and locate localised.sh. Double-click localised.sh to open it. In the top of the script you will find the following lines:
huginVer="$HUGIN_PACKAGE_VERSION" wxDir="./ExternalPrograms/wxMac-2.8.7" resdir="$TARGET_BUILD_DIR/Hugin.app/Contents/Resources" huginsrcdir="../src/hugin1/hugin" xrcsrcdir="$huginsrcdir/xrc" translationsdir="../src/translations"
Change the wxDir to the directory where your wxmac source code resides. Click (Menu) File->Save or <Command>-S to save the script. Close it.
Locate the Complete-bundle.sh script and double-click to open it. In the top of the script you will find the following lines:
dylib_dir="../mac/ExternalPrograms/repository/lib" old_install_name_dirname="/Users/Shared/development/hugin_related/hugin/mac/ExternalPrograms/repository/lib" dylib_install_loc="Libraries" new_install_name_dirname="@executable_path/../$dylib_install_loc"
Change the dylib_dir to the correct relative path.
Change the old_install_name_dirname to the correct absolute path. Click (Menu) File->Save or <Command>-S to save the script. Close it.
If you have Exiftool on your system, you need to edit this script too. As mentioned in the early lines of #Prepare the scripts before building Xcode will generate a non-fatal error if Exiftool is not available (or if you configured the script incorrectly), but in this case Hugin will run without it as it is an "extra" tool and Hugin can run without it.
Locate the copyExifTool.sh script and double-click to open it. In the top of the script you will find the following lines:
Change the exiftoolDir path to the path where your Exiftool resides.
Click (Menu) File->Save or <Command>-S to save the script. Close it.
Compile and build our Hugin.app
Set the "Active Target" to "configure" and "Active Build Configuration" to "Release". Now click the "Build" icon. This will only take a few seconds or less. In the status bar you will see the message concerning this step. It should say "Build succeeded" on the left and "Succeeded" on the right.
If this is the status message, you can really start building your Hugin.app.
Note that the build has succeeded even though you see two error messages (in this screen dump). These are the non-fatal errors mentioned before. Double-click the "error" icon to display the errors. In this case it mostly means that some language files (*.po) could not be found. The available languages (= *.po files) differ between Hugin and wxmac, the scripts can not solve this entirely and will generate errors. These *.po errors are non-fatal errors for the Hugin.app. Hugin or wxmac will simply not be able to show messages/text in that language and will fall back to English.
If you did stick to all the "default settings", you will find your Hugin.app inside ../mac/build/Release among lots and lots of other files. All these other (intermediate build) files are not relevant. If built correctly, the Hugin.app is a completely portable application and everything is inside Hugin.app.
Now you need to test run your bundle. The first test is to see whether your application runs at all. Double-click it and try to make a panorama. If this works, it's party time!!! So, go party and when you're finished come back for the next test.
Now that you managed to get a working Hugin.app via Xcode we need to check if it is really a portable application.
If you were completely successful in building your Hugin.app, than all binaries, tools and libraries should be "inside" the bundle and should know "how to find each other". The best way to test this is to copy the Hugin.app to another Mac and run Hugin.app there. As this is not always possible, copy your Hugin.app to another location on your mac and rename
- your mac directory inside your hugin source directory to mac.org,
- your /opt/local to /opt/local.org (in case you have Macports),
- your /sw directory to /sw.org (in case you have Fink),
- your usr/local directory to /usr/local.org
(You can off course rename your directories to anything you like).
Renaming your directories will prevent Hugin from trying to link to the libraries inside these directories. If Hugin does it will crash and show an error message that Hugin tried to link to <path to>/ExternalPrograms/repository/lib/<some library> instead of the bundle library (or even worse for example to /opt/local/lib/<some library>, which means that you did not correctly #Get MacPorts and/or Fink out of the way).
The Complete-bundle.sh script mentioned in #Edit Complete-bundle.sh will alter the "hard linked" paths inside Hugin and inside the libraries to "internal" paths, using the install_name_tool, to make sure that they can find each other inside the bundle. If this did not work correctly (one of the non-fatal errors for Xcode), your Hugin.app will not run on another system as it will still try to use the libraries inside your build environment. This build environment is not available on another "Xcode and Hugin free" Mac.
$ open Hugin.app &to do that (in case you didn't know). If you double-click Hugin.app from Finder you won't see (error) messages.
Next to this you should check the logs (in case of crashes that is). You will find these in /Users/<user name>/Library/Logs/CrashReporter/. If "things" go wrong you can find there logs like Hugin.crash.log. These logs are not recreated but new error reports are just added to the log, making them bigger and bigger (But off course you won't run into errors).
If everything worked fine you really made a portable application. Congratulations!
32bit versus 64bit
Tiger (Xcode 2.4) enables you to build universal binaries and libraries for PPC and i386. Leopard (XCode 3.0) enables you to build universal binaries for PPC and i386, but also for PPC_64 (theoretically) and X86_64. If you want to do this you need to use SetEnv-leopard.txt. At this moment this is "extremely and utterly experimental" as:
- most "Linux derived" libraries and binaries will not compile for Apple 64bit.
- If they compile and build, they are not well optimized.
- only enblend can use the full potential of 64bit (currently).
- You build the 64bit part only for Leopard users on 64bit hardware. 32bit universal will run on every Mac.
- The current bundle is 85 MB. If you build for three architectures (ppc/i386/x86_64) it will be approx 120 MB.
Use at your own risk. But for the time being: stay away from it.
Command line building with Xcode
Xcode has also a command line version named xcodebuild. If you prefer the command line than this tool is nice. You miss the nice integrated editor off course, so you need vi or pico (or some other editor) to change source code. (I use it for for remote ssh builds using vi as code editor).
Say you want to use (or experiment) with the command line builder, you need to cd into the mac directory and issue the following commands:
$ cd <path_to>/hugin/mac $ xcodebuild -project Hugin.xcodeproj -alltargets -configuration Release
Note: Even if you run the build from the command line, the complete environment will be opened. When finished, it will close again.
If you want more info just issue a xcodebuild --help for short help or a man xcodebuild for more extensive help. And you can read the docu/helpfiles from inside Xcode.
If you want to make automated nightly builds of Hugin you can easily script that with the command line version (svn refresh, command line build, command line creation of the dmg, ftp to website). You could even issue the svn, dmg creation and ftp commands from the Xcode project which means that you only have to script the xcodebuild.