Fun with clang or: How to build Qt 4.8 with clang 3 without going insane
Given that XCode 4 on Mac ships with the the clang frontend for LLVM now, I wanted to give this new compiler a try and see if it can replace gcc for me.
To compile the CRJ plugin, I need Qt of course, and given this entry in the Qt blogs I thought it would be fairly easy to get this to work.
I was wrong.
First try: I checked out the Qt 4.8 branch from gitorious, and configured with -platform unsupported/macx-clang but I soon ran into a compile error complaining about an undeclared identifier "SetRect".
Second try: I checked out the specific git revision mentioned in the blog post, and re-configured. Build stops with the same error.
Thrid try: Given that the most recent clang is the 3.0 branch and that Apple ships 2.1, I decided to get myself a more recent clang. I checked out the llvm sources via svn, then the clang sources in the appropriate subdirectory, configured for a release-optimzed build (to boldly go...) and make'd. Some 10 or 20 minutes later I had a clang 3.0. I edited the mkspecs/common/clang.conf to point to my freshly compiled clang in /usr/local/bin and reconfigured Qt (I checked out master/HEAD before). Now the built took longer before it stopped, this time everything of QtCore compiled, but when linking, I got an "undefined symbol for architecture i386: ___eprintf". Oh well.
Fourth try: Google pointed me to this thread which indicated I must built the compiler runtime also. So I did another svn checkout (compiler-rt into llvm/projects/), make clean'd, re-configured and built llvm/clang/compiler-rt again. The built aborted mocking about some missing headers for ARM.
Fifth try: I reconfigured llvm with --enable-architecture=x86 instead of the default --enable-architecture=all, which would built all kinds of backend. The next built took somewhat longer and perhaps 30 minutes later I was ready to try again: with the freshly installed clang I went ahead to compile Qt again. This time it actually linked QtCore, but when compiling QtGui it stopped again with a compiler error:
src/gui/kernel/qt_cocoa_helpers_mac_p.h:218:10: error: cannot initialize return object of type 'NSString *' with an rvalue of type 'const NSString *'
Apparently, clang doesn't like Cocoa.
Sixth try: I make confclean'd and re-configured Qt to build with -carbon. Unfortunately, the next make stopped at exactly the same location, at the Cocoa-helpers. Apparently this header is pulled in every time regardless whether we actually use Cocoa or not.
At this point, I decided to give up on OSX and try my luck on Linux.
I svn co'd llvm, clang and compiler-rt to my Suse, configured for optimzed built and started make. Short time after that *KABOOOM!*. No, not a compile error. GCC crashed. My compiler trapped during compiling. Seriously, WTF? I was first confused by the print output of GCC, that referred to a source file that I wasn't compiling at all, until it occurred to me that the indicated source was a source of GCC, a GCC function that crashed.
Oh the humanity! I went to the #clang channel on irc.freenode.net and luckily some helpful soul indicated what I should do. GCC would break regularly during optimized clang compiles. The way to go would be to build clang with clang
- First, build clang in debug mode without optimizations with gcc
- Then, use the un-optimized clang to build an optimized clang
Luckicly, this guy was spot on. I had encountered this error that prevents GCC 4.5.0 to build clang with -ftree-vectorize. So the non-optimized built succeeded, and then I was able to bootstrap the optimized clang from it.
I checked out Qt master again and configured with -platform unsupported/linux-clang. Build was uneventful, and my minimal testing-Qt (without webkit, Javascript, QtScript, QDeclarative, etc...) was ready within some 30 or 45 minutes.
Configuring Qt-Creator 2.3 to recognize clang as compiler and display its warnings was straightforward.
Now I took a deep breath and compiled my airnav library on -Wall, which is a lot more pedantic than the -Wall of gcc. And bingo!!
The -Wall -Wextra compile however showed some minor warnings that I've never seen with gcc - it complained about an explicit template instantiation outside the namespace of the template. This was fixed changing two lines of code, and after that I got it through -Werror -Wall -Wextra. W00t!
Lessons learned:
- clang is not yet ready to be used on a regular day-to-day basis and still requires lots of fiddling
- Qt's codebase is relatively clean, as it compiles with clang with relatively few warnings
- the Cocoa headers of the 10.7 SDK however are not
- It is great to have yet another reference compiler to check for code-cleanliness
So I reached at least one of my goals: I have another reference compiler I can test my code against: I regularly compile my whole codebase with Visual C++ 10 and gcc 4. Now I have another testing point that reveals more potential issues (portability, unsafe assumptions).
I won't ship clang-compiled plugins to end-users soon, but I will definitely use clang-build plugins myself now for testing purposes.















