Saturday, April 07, 2012

Playing with (almost) the latest C++ features -- groundwork

Having had my interest in playing with native code reawoken by the new C++11 features, the first thing I went to look at was portability. One of the advantages of managed code -- JVM or CLR -- is that the VM handles portability for you and the code can be built pretty much anywhere; with native code we have to see what the compilers have in common.

I've been using VC++2010 on Windows as having many of the "big rocks" for the new standard, while being backward compatible onto OS versions before Win7 (unlike the VC++11 compiler and its runtime); and for *nix-like systems, I have cygwin and debian squeeze... Well the distro support for these is a bit behind-hand (gcc versions 4.5 and 4.4 respectively), whereas gcc 4.7 is now out with quite a broad coverage of the new standard. While 4.5 has a good chunk of the new stuff, 4.4 doesn't -- in particular, it doesn't have the new lambda syntax. So, it's build from source time to get an upgrade to a sensible version there, which means I might as well go to the latest and greatest on both platforms...

Building gcc 4.7 from source


Fortunately there are some handy instructions out there which can be used as a baseline for debian. Following them, I found that I needed to tweak how I built GMP to fit PPL's requirements, by modifying the configure step to be:

CPPFLAGS=-fexceptions ../../sources/gmp-5.0.4/configure --prefix=$PROJECT_DIR/output/ --enable-cxx

before PPL would go through happily. The --enable-cxx is required for the PPL ./configure stage to run through, the CPPFLAGS=-fexceptions is optional, but it avoids a make-time warning about possible unwanted runtime behaviours if you don't.

ClooG also needed a CPPFLAGS=-I$PROJECT_DIR/output/include CFLAGS=-L$PROJECT_DIR/output/lib on the configure line to find GMP.

In the gcc build, as well as pointing at ../../sources/gcc-4.7.0/configure it's also worth taking the advice from the MacOS build instructions and only selecting languages of interest to you i.e. to play with new C/C++ there's no need for Java or Fortran, at a considerable saving in time.

Then it's a matter of just adding soft links from whichever g*-4.7 files to the unadorned versions, and

export LD_LIBRARY_PATH=~/gcc-4.7/output/lib/
export PATH=~/gcc-4.7/output/bin:$PATH

to your .bashrc or equivalent


Cygwin is more fun -- I've not yet managed to get that to build all the way through with the loop optimization libraries. When you get to PPL, you find you also need to go back and re-configure GMP with --disable-static --enable-shared, as explained in the friendly manual, to build the shared library version. However then when building gcc, we get a mismatch with the earlier libraries in the configure stage, where it just stops:

checking for the correct version of gmp.h... yes
checking for the correct version of mpfr.h... yes
checking for the correct version of mpc.h... yes
checking for the correct version of the gmp/mpfr/mpc libraries... no

It is possible that if you start by building PPL and CLooG with shared library GMP in a first pass, then build the rest starting with reconfiguring and building a static GMP it will work, but life is too short. The MacOS build instructions didn't use the PPL/ClooG/graphite libraries either, so we can do this to configure gcc instead:

$ ../../sources/gcc-4.7.0/configure          \
>     --prefix=$PROJECT_DIR/output/    \
>     --with-gmp=$PROJECT_DIR/output/  \
>     --with-mpfr=$PROJECT_DIR/output/ \
>     --with-mpc=$PROJECT_DIR/output/  \
>     --program-suffix=-4.7            \
>     --without-ppl --without-cloog    \
>     --enable-languages=c,c++

which sits and cooks for quite some time to get you the new compiler build.

Linkbait: fixing cygwin "mkdir foo mkdir: cannot create directory `foo': Permission denied"

I got into a state where I had this error, which other people have seen, after having tried to trash the build output of one of the failed PPL/CLooG attempts from Windows Explorer, where anywhere under in my home directory and down it was rejecting mkdir with "mkdir foo mkdir: cannot create directory `foo': Permission denied". Having spotted a tangentially related mailing list message about this sort of problem happening on network shares and there being ACL related, I tried the following and it worked to clear things up:

  1. Start a PowerShell console as Administrator window
  2. Run Get-Acl a folder (like /tmp) which you can mkdir in in cygwin (this will be %cygwin_root%\tmp where %cygwin_root% is where you installed cygwin)
    $acl = Get-Acl C:\cygwin\tmp
  3. In Windows Explorer set yourself Full Control on all the affected folders -- %cygwin_root%\home and %cygwin_root%\home\%USERNAME% at least
  4. In the PowerShell, Set-Acl on each folder you've just frobbed with the saved ACL object
    Set-Acl C:\cygwin\home $acl
    Note that the Set-Acl call may take considerable time (tens of seconds) to execute when it gets to the really problematic node and has to roll permissions down.

SCons -- Death to makefiles

Since I last did native code seriously at home (c. year 2000), I had discovered the very handy MiniCppUnit tool as a nice light-weight unit testing framework, so of course I went and fetched a copy to be going on with. This time, curiosity prompted me to wonder "WTF is this SConstruct file anyway?" and now when I opened it, I immediately recognised that it was some form of Python script, and wondered what sort of Python based make system this might be.

It was simple enough to find where it came from -- -- and looking at the user guide, I felt that it is much more intuitive system than makefiles (admittedly there's not a high barrier there), and far less cluttered than declarative XML based systems like Ant or MSBuild; so I'll be using that for my *nix builds -- it works very nicely for doing things like running unit tests as part of the build e.g.

MiniCppUnit -- Building it under modern C++

Just like I had to patch it to build in C++/CLI, I needed to make some changes to MiniCppUnit to get it to build clean under VC++2010, the out-of-the-box gcc 4.5 on cygwin 1.7.x and gcc 4.7 debian squeeze with -Wall -std=gnu++0x or -Wall -std=c++11 on respectively. First MiniCppUnit.hxx:

< #if _MSC_VER < 1300
> #if defined(_MSC_VER) && _MSC_VER < 1300
> /* Without the "defined(_MSC_VER) &&" this code gets included when building on cygwin 1.7.x with gcc 4.5.3 at least */
<  static void assertTrue(char* strExpression, bool expression,
>     static void assertTrue(const char* strExpression, bool expression,
<  static void assertTrueMissatge(char* strExpression, bool expression, 
>     static void assertTrueMissatge(const char* strExpression, bool expression, 
<    catch ( TestFailedException& failure) //just for skiping current test case
>    catch ( TestFailedException& /*failure*/) //just for skiping current test case

and the corresponding signature change in the .cxx file:

< void Assert::assertTrue(char* strExpression, bool expression,
> void Assert::assertTrue(const char* strExpression, bool expression,
< void Assert::assertTrueMissatge(char* strExpression, bool expression, 
> void Assert::assertTrueMissatge(const char* strExpression, bool expression, 

Of course there may be other things lurking to be scared out when I ramp up my standard warning levels to beyond the misleadingly named -Wall (when you have -Wextra, formerly -W, provided to switch on a whole bunch more including spotting signed/unsigned comparisons, before getting onto the really specialized ones) and switch on -Werror to force everything to be really clean.

No comments :