Build a MacOSX Universal Hugin bundle with Xcode
THIS IS STILL A DRAFT VERSION
- 1 Introduction
- 2 Prerequisites
- 3 Preparations for building the "External Programs"
- 3.1 Introduction
- 3.2 Installing Subversion (SVN)
- 3.3 Get Hugin from SVN
- 3.4 Location of the "External Programs" development tree
- 3.5 Creation of the "External Programs" development tree
- 4 Building the "External Programs"
- 5 Xcode compiling Hugin
- 6 Notes
- 7 External Links
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.
Installing Subversion (SVN)
(Note: Tiger users 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 install it yourself.
$ sudo port install subversion
If you use Fink:
$ fink -b install svn
$ sudo apt-get install svn
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.
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 then 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
$ myPathToHuginSource="/Users/<your_username>/development/hugin/hugin-svn" $ myExternalProgramsDir="/Users/<your_username>/development/hugin/ExternalPrograms" $ 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"
Building the "External Programs"
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 cannot resist to customise something for yourself.
The list of programs and their versions that you should compile are given in the hugin/mac/ExternalPrograms/readme.txt. Some libraries are recommended not to be compiled as dynamically linked library, but as statically linked library instead. The scripts for static build are found in hugin/mac/ExternalPrograms/scripts/static/.
Note: There is a good chance those build scripts not on the list are outdated and do not work.
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.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):
boost.sh, libexpat.sh, libjpeg.sh, libpng.sh, libtiff.sh, wxmac28.sh, ilmbase.sh, openexr16.sh, pano13.sh, static/libexiv2.sh, static/lcms.sh, static/libxmi.sh, (static/glew.sh)
And for the executables:
gnumake.sh, enblend31.sh, (autopano-sift-C.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
First, you should edit the configuration file. Duplicate BuildConfig.xcconfig.orig and name the new copy "BuildConfig.xcconfig".
Inside, you will find variables that needs be matched with your External Programs configuration. Please edit at least the following variables accordingly:
REPOSITORY_ABSOLUTE_PATH WX_LOCALE_DIR EXIFTOOL_DIR
If you have chosen to compile 4-way universal binary with 64bit support, uncomment RELEASE_ARCHS_64 line.
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.
You can use Subversion with Xcode. It is a very handy feature to use in order to keep the files up-to-date and, especially with Xcode 3's improved Subversion integration, to commit changes back to repository. Follow the configuration of "SCM System".
The second tab is the "Build" tab (see below).
This is the list of master configuration of the project. The values that you have set in BuildConfig.xcconfig (above) are reflected, and referenced by other settings. All relative paths are relative to the location of the hugin.xcodeproj directory structure. You should not need to change anything, but do check. Please note some of the settings are different among "Configuration", e.g. Release, Debug, Development, etc. but paths should not be different among them.
The other tabs are not relevant, but feel free to expand your knowledge.
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.
This build target updates the pre-release version tags, and is not propagated (does not automatically run) from other targets. You should run this target after every SVN update. Also, before compiling anything that you give away to other people, make sure that you "Clean all targets" and then build this "configure" target first.
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 PPC64 and x86_64. If you want to do this, you should refer to SetEnv-leopard.txt. At this moment this is "utterly experimental" as:
- some "Linux derived" libraries and binaries may not work properly.
- they are not well optimized for Core 2 processors.
- most users do not benefit from 64bit because it is required only when making a huge panorama (>2GB).
- 64bit part is only for Leopard users on 64bit hardware (G5, Xeon, or Core 2). Those platforms can run 32bit anyway.
- almost doubles the binary size. The 2-part universal version alone weighs more than 65MB.
Use at your own risk.
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.