Thursday 15 May 2008

Cross compiling Boost

Boost is a truly excellent C++ library, and something that all C++ programmers should be familiar with. It's a set of peer-reviewed extensions to the standard C++ library and is an excellent weapon in your C++ arsenal. Many core Boost libraries have gone on to be adopted in the C++ standard itself. I love it.

Mostly.

Building the Boost library is a swine. Seriously annoying. For most users, this isn't an issue. You can get binary versions for most platforms, and almost every Linux (or other Unix platform) distribution has a pre-packed version available. So that's fine. And to be fair, most of the Boost libraries are header-only (plenty of template mumbo-jumbo), so often it's irrelevant anyway.

But if you need to build Boost yourself you enter a weird world. Boost uses a homegrown variant of Perforce's Jam (which they call bjam - amusingly remeniscent of a 1980s UK white goods retailer). That's a little unusual, but fine. Then they layer their own build file magic on the top. That's fine. And then they document it. That's fine.

Apart from the bit where it's really hard to work out how to use it to do anything other than a simple build. For example, it's really, really hard to work out how to make the gcc build process use your own gcc compiler, rather than the standard gcc on $PATH. It's a real shame that such an excellent library requires you to become an expert in their non-standard build system in order to build it!

We run C++ on embedded ARM devices, so we cross compile to ARM from x86 Linux boxes. I recently needed to update our toolchain (from gcc 3.x to gcc 4), and I had to jump from Boost 1.33.x to 1.35 (the former had bugs when compiled with gcc 4). This newer Boost version saw subtle build system changes, and (IMVHO) a worsening of the build documentation.

In case you need to do the same thing - cross compile Boost with your own custom compiler - here's my recipe (this is for Boost 1.35, the process is annoyingly different for previous versions):

First you must make Boost jam. If you have a different jam it may not work. Specifically, if you want to use Cygwin you must use the correct jam from Boost not the Cygwin-supplied bjam, or things don't work in weird ways...

cd tool/src/jam
./build.sh
cp bin.*/bjam
PATH=:$PATH
cd -

Now, here's the magic. Brace yourself. This is how you use a custom gcc compiler, you write some odd rule into some very well hidden config file:

echo "using gcc : 4.2.2 : PATH_TO_DIR/arm-softfloat-linux-gnu-g++ ; " > tools/build/v2/user-config.jam

Obviously, tweak the version numbers to your requirements. Then use your fresh copy of jam to build Boost, changing the configuration magic below as you require...

bjam -d2 \
--toolset=gcc
'-sBUILD=release static multi/single' \
link=static \
--prefix= \
--layout=system \
--with-XXX --with-XXX \
install

And that should do the trick. (The --with-XXX lines specify which libraries you'd like built, e.g. "--with-thread --with-signals --with-filesystem")

Now, I'm not claiming that this recipe is the best way to do it. But from a lot of reading, it's the only half-way sane method that I've found. For example, it's possible to put symlinks to your custom toolchain early in your path, but that strikes me as a very clumsy way to persuade the Boost build system to use your compiler.

There is one problem thyat I have observed with this approach: it only uses your custom g++ compiler, but still uses the system ar. As it happens, this works fine (at least, it does for static libraries, which is what we use). Perhaps another using line in the randomly located jam config file might solve this?

That's my recipe. If you have to cross compile Boost then: good luck!

9 comments:

Unknown said...

Thanks for this information! It was very useful; I 'inherited' an application with a build system that was cross-compiling boost 1.33.1 and somehow managed to do this by setting the GCC_ROOT_DIRECTORY environment variable.
When trying to upgrade boost, I found out this doesn't work anymore, because of the new build system used now. After two days of expirimenting and browsing through the documentation, I had already (hum) figured out what to do; still, finding your information helped me a lot: it assured me I was on the right track, and probably saved me a lot of time figuring out exactly where to put this user-config.jam file.

Anonymous said...

Thanks for your article.

Are you cross compiling boost 1.35 in cygwin? Actually, when I'm trying to compile in cygwin for arm, I have to also change the configuration in gcc.jam file, otherwise, it would pass wrong option to compiler (it would pass -mthreads to gcc, which should be passed only when os.name equals windows, and I have to comment that line out).

Olivier said...

Hi Pete, thanks again for this information.

I met exactly the same problem but I just wanted to precise that this bug has been described in ticket 977 (http://svn.boost.org/trac/boost/ticket/977). In my situation, building bjam with -fno-strict-aliasing option seems to fix the problem.

Pete Goodliffe said...

Olivier - I'm not sure that the bug you're pointing to is the same thing at all, just another random bjam problem :-)

Anonymous said...

Thanks for the information, very useful!

Fulg said...

Thanks very much for posting this - very useful. As much as I despise Autotools, at least it's the same for most projects (and cross-compiling is usually supported out-of-the-box).

BTW in Boost 1.43, when cross-compiling with bjam, it uses the proper ar now, so I guess they fixed the build system.

Ansi said...

Thanks for the info! It helped me getting a build of Boost ver. 1.42 for ARM with gcc 4.1.2. The newest version, 1.47, however, failed due to "Error: invalid application of 'sizeof' to incomplete type 'boost::STATIC_ASSERTION_FAILURE'"

Anonymous said...

I am trying to cross-compile boost 1.33.1 for MIPS. I understood the user-config part you have mentioned but can someone please elaborate on "cp bin.*/bjam
PATH=:$PATH
cd -" part. I didn't get that part. Did you have to modify gcc.jam as well?
I appreciate your help.

Anonymous said...

I am cross compiling boost 1.49 for vxworks in cygwin on windows. The vague boost documentation baffles me and being new to cross configuration mumbo jumbo, i can't put my act together despite having tried out the steps that you have mentioned. It is obvious that am getting the path or the values incorrect...Either ways, can you help me out of my predicament ?

Another question that I had to ask was, if I simply ./configure, why don't I get a makefile ?