2013-01-08

Quick and dirty hack to build OpenJDK6 with clang and libc++ on FreeBSD

FreeBSD is in the process of replacing the GNU toolchain with the LLVM based clang compiler suite. I wanted to check out how far they got in the latest release (9.1R), so I set out to build our internal test server running a jboss application server with clang and the new c++ standard library: libc++.

Unfortunately, an important patch hasn't made it into the 9.1 release (without this patch it's not possible to statically link programs with -stdlib=libc++), so I switched my sources to stable/9 and rebuilt the base system.

Instructions for using the new toolchain in FreeBSD can by found here, and for using libc++ instead of libstdc++ here, but in a nutshell, you just have to add the following lines to /etc/make.conf:

# use clang:
CPP=clang-cpp
CC=clang
CXX=clang++
# use libc++ instead of libstdc++:
CXXFLAGS+=-stdlib=libc++
# build libc++:
WITH_LIBCPLUSPLUS=yes
# skip building gcc:
WITHOUT_GCC=yes

Note: first you'll have to build and install the base system without setting -stdlib=libc++ in CXXFLAGS if you don't already have libc++ installed. Then rebuild everything with the above settings to let the base system link against libc++ instead of libstdc++.

Most of the ports I needed built fine, but some didn't use the CXXFLAGS from make.conf, so I had to trick them by adding the following lines to make.conf:

.if ${.CURDIR:M*/usr/ports/archivers/p7zip*}
CXX+=-stdlib=libc++
.endif
.if ${.CURDIR:M*/usr/ports/databases/db42*}
CXX+=-stdlib=libc++
.endif
.if ${.CURDIR:M*/usr/ports/java/openjdk6*}
CXX+=-stdlib=libc++
.endif

Now everything was building with libc++ but the openjdk6 build blew up, because they defined their own assert() macro in hotspot/src/share/vm/utilities/debug.hpp which got wiped when one of the libc++ headers included <assert.h> [Quote from the standard: "The assert macro is redefined according to the current state of NDEBUG each time that <assert.h> is included."]. I'm surprised this issue hasn't bitten them yet...

I changed the macro definition in debug.hpp to assert_vm (since this macro is used solely in the vm subsystem) and updated all references to it. This wasn't so easy, as the "real" assert() was also used in some files, and my sed script replaced some of those at first, too, but after some trial-and-error, I got it right (see patch-zzz-assert-vm). The patch also fixes a minor typo in debug.hpp that would cause a compilation failure if USE_REPEATED_ASSERTS were defined (a backlash was forgotten from the first line of the macro definition).

With this patch the java/openjdk6 port built successfully, but libmawt.so was still linking against libstdc++, so I had to dig deeper into the build scripts / Makefiles. It turned out that the Makefile under jdk/make/sun/headless wasn't requesting to use a c++ compiler to do the linking, even though it links with -lstdc++, so libmawt.so was linked with CC instead of CXX. I fixed this with patch-jdk-make-sun-headless.
[Note: apparently linking libmawt.so with -lstdc++ on FreeBSD is wrong, as libmawt.so isn't linked agains libstdc++ on linux, for example. I'll revise this section as soon as I find out why -libstdc++ is added to the link line here...]

After a short recompile (an hour or so on this old box ;), I got everything up and running built with clang and linked against libc++. My initial tests with jboss went well, nothing scary happened so far.

Update: I filed a bug report with a proposed patch to openjdk: Bug 100297 (probably moved to Bug 8007770 by the java devs while I wasn't paying attention), but I won't have time now to find a sponsor for this among the openjdk folks, so if you have any connections with openjdk devs, I'd be thankful if you could help me push this along.

I'd like here to thank dim and various other folks at irc://irc.oftc.net/#freebsd-clang for their help with this experiment, and the clang and FreeBSD developers for the wonderful software they created.

No comments: