Sunday 8 June 2008

C++0x with GCC from the SVN repository

Hi, that was rather fast that I wrote this blog, but don't get used to it, that was only because I got bored of the first one while writing, so I started this one and continued to work in parallel. Whatever, let's get going...

Introduction

If you want to try out the new features of C++0x, you'll need a compiler that supports at least a few of the features.
But there's a problem: C++0x is all new and hot. It's even so hot that you'll burn your fingers when trying to grope it to firm. What I mean by that is, that the standard is still developed and a few features are not yet completely defined and formulated. Yet, some compiler vendors have taken upon themselves the task to implement a few features of the new standard, to enable programmers to test the new features and get and idea of what the new standard is about.

The compiler landscape

The list of these vendors however is very short. There is:

Comeau C++ is a quite good but proprietary compiler. It supports few features, the most notable one is the "auto" keyword. The state of C++0x support can be viewed here: [4].
ConceptGCC is a fork of GCC, its main goal is to implement the Concepts feature and to rewrite the STL to use Concepts. ConceptGCC does barely support any other C++0x features, and was forked off because this feature requires fundamental changes in the Compiler. Right now effort is being made to merge the Concepts feature back into the mainline GCC compiler.
Starting from version 4.3, the GCC compiler adds experimental support for C++0x. This experimental support has now grown to a considerable amount of features. The current status can be viewed here: [5]. Unfortunately, my favourite, the "auto" keyword has not yet been implemented.
Of course, there are other compilers out there who support singular features as extensions to the language, but I don't know any examples I could mention here.


The compiler of choice

To test new features I chose to use the gcc 4.4 compiler. The reasons for this are simple: It's free (as in beer, as well as in freedom), it's good and it has the most support for C++0x.
You can for sure download a tarball from somewhere, compile it and use it. But I chose a different approach: get the most recent version from their svn repository. The advantages of getting the source from svn is that

  1. It's really up to date. When you check out the development trunk, you definitely get the latest version.
  2. Updates can be applied with low overhead: simply update your working copy and make will recompile only the updated and dependent files.
Of course there are disadvantages
  1. Where a tarball would achieve great compression performance, the sources here are downloaded uncompressed. That uses a lot of bandwidth.
  2. A working copy contains quite a lot of extra files, that are needed for versioning.
  3. Checking out the trunk repository will get you the up-to-date development version. The problem is, it can happen that this version is broken. That means when you check out this version, your copy will be broken too. But don't worry, if you wait a few days and then update the source, the problem will most likely be allready fixed.

Preparing to install

Allright, before we start we got do a few things.

First of all, install UNIX or a UNIX derivative, such as Linux. Ok, admittedly this is a bit unfair. But let me tell you one thing: the build process on Microsoft Windows is a pain in the ass. It is done by installing all kinds of tools, shells and compilers that let your system act as though it was Linux. If you really want to do that, you might want to read the instructions on building gcc 4.1 on a Windows host [6]. I'm pretty sure, the instructions for the current SVN version differ very little from the ones provided for 4.1. However, it's probably much faster and easier to install a GNU/Linux distribution such as Ubuntu [7]. This document only describes how to build the compiler on a GNU/Linux host, but I suppose with a few adaptions they will be also valid for other POSIX compliant systems.

Install a Subversion[8] (SVN) client. I won't discuss this, since installation of software is very specific to operating systems and most Linux/UNIX distributions provide easily installable packages. If you are on a Windows host, you might want to take a look at TortoiseSVN [9].

Now here comes the annoying part. You need to satisfy the build dependencies before you start doing anything. Here you can find the complete list of build dependencies for gcc: [10]. On a reasonably complete system that was allready used for development (which I assume, since you are interested in the new standard) you should allready have most of the stuff installed. The only items I had to install additionaly were

  • GNU Multiple Precision Library (GMP) version 4.1 (or later)
  • MPFR Library version 2.3.0 (or later)
Which was no problem, since my distribution [11] allready provided precompiled packages for these libraries. Of course, you will need a compiler to compile the compiler, or do you want to compile it with your word processor? ;-) I used gcc 4.1 for that, but basically any gcc version should work. (For compilers other than gcc, look at the build instructions [12])

Next, we need two directories. The first is the directory that contains the source code for the compiler. I will refer to this directory as $GCC_SOURCE. It will take about 2.5GB. "WHOA, WTF??? 2.5GB? Is that gigabytes?" you might ask. Yes. It is gigabytes. Two and a half. The reason for this is that first of all the SVN trunk of gcc contains a lot of additional files, such as tests, documentation and so on. Also, gcc is more than just a C/C++ compiler, its a compiler collection of several compilers. Especially the Java API takes a lot of space. (If you are smart enough to find a way to not download the whole collection but still being able to compile it, mail me, because I wasn't). And finally, don't forget that we have to actually build the compiler, so we need space for the object files and executables.
The second directory is the "installation directory", i will refer to it as $GCC_INSTALL. It contains libraries, header files and executables. If you really want to, you can "hard install" it into /usr/local or something, but I wouldn't recommend that. This directory uses about 100MB.

Last but not least, you need:
Time. The initial checkout downloads all the sources (and documentation and test and ...) since that's quite a lot, this step takes about an hour or so to complete, with a decent internet connection. The first compile also takes ages, that's about a 3/4 hour, on my good old Pentium D with 3 Ghz.

Get going

Now that we have all the prerequisites, we can start off. Verify that you have Subversion installed properly with svn help. This should display some help text. Change into $GCC_SOURCE, the directory you created earlier for the sources. Now is the time to stop watching videostreams and downloading porn, because you will need every bit/second you can get out of your internet connection. Find the subversion repository for gcc. This should be svn://gcc.gnu.org/svn/gcc/trunk

The big checkout

Start the initial checkout with
svn checkout svn://gcc.gnu.org/svn/gcc/trunk
If you want, you can add the -q option to the command line, this will cause to run the checkout to run quietly (without output). However, as the checkout takes so long I prefer to see that at least something is being done.
Do something else. This checkout takes a long time, so you might like to do play games, read ANSI/ISO papers about the new standard or talk with your wife. But don't do anything that consumes your bandwidth.

Configuring

When you have obtained all the sources, you can easily compile the source with

./configure
make
make install

Well, to be honest, it's not THAT easy. The above invocation installs the complete compiler suite into the default installation directory, which is /usr/local. That might not be what you want. To customize your copy of the compiler, we have to set a few flags. You can look up the flags by calling

./configure --help. These are the flags I used:

--prefix=$GCC_INSTALL
Set root directory of installation to the directory we created previously.
--program-suffix=suf
The suffix to the name of all binaries you will have. The compiler you have installed might have a suffix that looks somehow like "4.2". I used "svn" for that, to be clear that this is a svn version.
--enable-threads
Enable threads
--enable-languages=c, c++
IMPORTANT! This flag is used to indicate that only C and C++ compilers shall be built. If you don't specify this flag, you end up having all supported languages installed. Believe me, it takes long enough to compile these two compilers, I dont want to know how long it takes for all languages.
--enable-shared
This builds shared libraries that can be used by the programs you compile. If you omit this, you have to link those libraries to your programs -statically.
--disable-nls
This option disables Native Language Support. Although it's very nice of the Free Software Foundation to provide error messages for various different languages, I personally find it annoying to read the cryptic error messages in german (maybe just because I am not used to it). Leave this option out if you do like them.
Basically, it's a good idea to look at the flags your previously installed version of gcc was compiled with, and then adapt these flags to your needs. Invoke your old gcc version with gcc -v to retrieve this information. For all those who dont't have a gcc compiler, here are the flags of my vanilla pre- packaged compiler:

me@mybox:~$ gcc -v Using built-in specs. Target: i486-linux-gnu Configured with: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.2 --program-suffix=-4.2 --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --disable-libmudflap --enable-targets=all --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu Thread model: posix gcc version 4.2.4 (Debian 4.2.4-1)

Compilation

Now we are ready to compile. Now is the time to resume downloading porn or to watch videostreams, now you need the CPU, not your internet connection. Unless you have a multicore processor, stop all running programs, you will now need every CPU cycle you can get. type

make

and as soon as you hit the enter button the compilation will start. This step takes a LONG time (about 3/4 to 1 hour). You can leave your machine now, the build process should run automatically. Come back from time to time to check if the compilation finished or encountered errors.

When this step has finally finished, type

make install

into the command prompt to install the binaries into the directory you specified as '--prefix' flag for the configure script. Depending on wether you specified a system directory (e.g. /usr/local) or something in your home directory, you may have to run this command with root privileges.

You're nearly done. The only thing you need to do now is to reconfigure your dynamic linker to work with the libraries provided by the compiler. If you do not want that, you have to link those libraries statically to your programs, by adding the -static flag to the command line. To reconfigure your dynamic linker, find it's configuration file (maybe /etc/ld.so.conf), and add this line to it: $GCC_INSTALL/lib. (Note: on newer systems, the configuration file only includes the files in a configuration directory, like /etc/ld.so.conf.d/. In this case it is advisable to create an own file, e.g. gcc_svn.conf and put the line with the lib directory there.). Then run ldconfig and everything will be fine.


That's it! You're finished, finally. For convenience, you might want to add $GCC_INSTALL/bin to your PATH environment variable.

Testing the installation

To test this installation, open an editor and paste this code:


#include <iostream>
#include <vector>

static_assert(NULL == 0, "You live in a paralell universe!");

int main()
{
    long long a = 2; // new type
    decltype( a ) b = 5; // b is now long long    

    // binding rvalue reference to a temporary object
    std::vector<long long>&& vec_ref = std::vector<long long>();
    
    vec_ref.push_back(a);
    vec_ref.push_back(b);
    
#ifdef _HAS_AUTO
    // unfortunately, this doesnt compile yet...
    for (auto it = vec_ref.begin(); it < vec_ref.end(); it++)
#else
    for (std::vector<long long>::iterator it = vec_ref.begin(); it < vec_ref.end(); it++)    
#endif
        std::cout<<*it<<'\n';

}

Compile this code with the -std=c++0x to enable C++0x extensions:

$GCC_INSTALL/g++-svn -std=c++0x -o stdcxx09 stdcxx09.cpp

where $GCC_INSTALL is the directory you installed the new compiler, and the file stdcxx09.cpp is the file you pasted the above code in. If compilation succeeded, Congratulations, you made it!

How to handle updates

Now that you have obtained the binaries, you can use the compiler normally. But hey, what if two weeks later you read somewhere, that your favourite C++0x feature (maybe the auto keyword?) was added to GCC? All the other people would have to wait until a new gcc version was released. But now, we are special! Simply change back into the $GCC_SOURCE directory, and update your sources:

svn update

This will retrieve the updated files incrementally. That means that only new and updated files are retrieved. Even better, if a file was updated, only the diffpatch is transferred!
Next, recompile the sources, by issuing the

make

command. (but DONT do a ./configure, the previous configuration will be fine!) If you are lucky, make will only have to recompile the updated files and it's dependencies, then compilation will not take so long. When compilation has finished, do a make install and you're ready to go.


Allright, i hope this little howto helped you a bit in obtaining a compiler with C++0x support. Don't forget to have a look at the project status page [5] of the gcc compiler, and try out all features you find. They will definitely make your programming life easier.


[1]: http://www.comeaucomputing.com/
[2]: http://www.generic-programming.org/software/ConceptGCC/
[3]: http://gcc.gnu.org/
[4]: http://www.comeaucomputing.com/439features.html
[5]: http://gcc.gnu.org/projects/cxx0x.html
[6]: http://www.mingw.org/MinGWiki/index.php/How%20to%20Compile%20GCC%204.1
[7]: http://www.ubuntu.com/
[8]: http://subversion.tigris.org/
[9]: http://tortoisesvn.tigris.org/
[10]: http://gcc.gnu.org/install/prerequisites.html
[11]: http://www.debian.org/
[12]: http://gcc.gnu.org/install/

No comments: