Monthly Archives: October 2012

Debugging GCC in Eclipse CDT 4.2

My favored C++ development environment on Linux is Eclipse CDT.  There are a number of different IDEs available for Linux but I use the Eclipse IDE for Java development and find it easier to stick to that tool for C++.  Eclipse 4.2 CDT is mature and many of the rough edges found in prior releases have been filed off in Juno.

As I am working on a GCC plugin, I needed to create a debug build of GCC and then figure out how to debug it in the IDE.  The procedure to build a debug version of GCC 4.7.2 in Ubuntu 12.04 can be found in my post here.  Once you have a debug GCC built, adding Eclipse CDT and configuring a project for GCC debugging is a straightforward process – but there are a few details that can be added to the environment that make GCC development in Eclipse much more tractable.

Step 1:  Install Java 1.7

Eclipse is supported with the Oracle, IBM and OpenJDK packages.  In the past I’ve typically relied on the Sun JDKs and feel most comfortable using those JDKs for Eclipse.  I use the Web Upd8 PPA repository for Ubuntu to install the JDK.

$ sudo add-apt-repository -y ppa:webupd8team/java
$ sudo apt-get update
$ sudo apt-get install -y oracle-jdk7-installer
$ sudo update-java-alternatives -s java-7-oracle

You can check that the JDK installed correctly by asking for the java version

$ java -version

Step 2: Install Eclipse 4.2

Eclipse 4.2 is not yet in the official Ubuntu repository, so it must be installed manually.  I haven’t been able to find a way to use wget to pull the Eclipse archive directly, so I use the version of Firefox bundled with Ubuntu 12.04 to download the archive.  The Eclipse archives can be found at: http://www.eclipse.org/downloads/?osType=linux.  For Eclipse 4.2 CDT you want to download: eclipse-cpp-juno-linux-gtk-x86_64.tar.gz, assuming you are using 64 bit Ubuntu.

$ mkdir ~/eclipse
$ cd ~/eclipse
$ mkdir 4.2
$ cd 4.2

#
# Download Eclipse 4.2 from: http://www.eclipse.org/downloads/?osType=linux
# The archive you want should be: eclipse-cpp-juno-linux-gtk-x86_64.tar.gz
#

$ tar -xzvf eclipse-cpp-juno-linux-gtk-x86_64.tar.gz
$ sudo cp -r eclipse /usr/lib/
$ sudo cp eclipse/icon.xpm /usr/share/pixmaps/eclipse.xpm

If this is a first install of Eclipse, you will probably want to create a script in /usr/bin that simply launches Eclipse from /usr/lib/eclipse.

$ sudo sh -c "echo '/usr/lib/eclipse/eclipse' >> /usr/bin/eclipse"
$ sudo chmod +x /usr/bin/eclipse

If you want to create a menu entry for the IDE, the best bet is to use the menu management tool: Applications > System Tools > Preferences > Main Menu.  It should automatically pick up the icon from the pixmaps directory.

Step 3: Create two Simple C++ Projects to Debug GCC

From here on, the example assumes that GCC was built with –prefix=/usr/gcc-4.7.2 and –program-suffix=-4.7.2.  If your debug version of GCC was built with different values, then substitute accordingly.

Inside Eclipse, create two new ‘Hello World’ C++ Projects.  Use the ‘Executable’ project – not a ‘GNU Autotools’ project.  For this example I labelled the first project ‘GCC Debug Test’ and the second ‘Project To Build’.  ‘GCC Debug Test’ will be configured to build ‘Project to Build’ using the debug version of GCC.  For clarity, ‘GCC Debug Test’ isn’t even built, it is needed to configure the debug settings for GCC.

First, create a custom .gdbinit file in the ‘GCC Debug Test’ working directory.  Do this by copying the .gdbinit file from the gcc build directory into the project working directory and then fixup the paths in the file to point back to the build directory. The .gdbinit file created during the gcc build process provides a collection of scripts that can be used to print gcc data structures while debugging – this will prove invaluable.   FInally, add ‘set schedule-multiple’ as the first line of the  file – this option causes gdb to track multiple processes in a single debugging session.  The .gdbinit file should look something like this:

set schedule-multiple

dir ~/gcc_build/4.7.2/build/gcc
dir ~/gcc_build/4.7.2/gcc
dir ~/gcc_build/4.7.2/gcc/cp
dir ~/gcc_build/4.7.2/gcc/lto
source ~/gcc_build/4.7.2/build/gcc/gdbinit.in

In the ‘GCC Debug Test’ project, go to the ‘Run > Debug Configurations’ dialog and create a new ‘C/C++ Application’ debug configuration.  On the ‘Main’ tab, enter the path to the ‘gcc-4.7’ debug executable in the ‘/usr/gcc-4.7.2/bin’ directory in the ‘C/C++ Application:’ field in the dialog and click ‘Apply’.

After completing the ‘Main’ tab dialog, click on the ‘Arguments’ tab and enter the path to the test file to be compiled and click ‘Apply’.

Next, click on the ‘Environment’ tab and create two variables: LD_LIBRARY_PATH and PATH.  For LD_LIBRARY_PATH, add the paths to the ‘lib’, ‘lib64’ and ‘lib64/debug’ directories for the GCC build to the front of the environment variable.  For PATH, add the path to the ‘bin’ directory to the front of the path as well.  For both environment variables, add the original paths to the end of the variable.  Make sure the ‘Replace native environment with specified environment’ radio button is selected.

Finally, click on the ‘Debugger’ tab.  In that dialog, insure the ‘Stop on startup at: main’ checkbox is checked.  Enter the path to the .gdbinit file created above into the ‘GDB command file’field.  Finally, check the ‘Automatically debug forked processes’ checkbox.  Since the gcc-4.7.2 application is just a driver for the actual compiler, unless this field is selected the debugger will not debug into the actual compiler when that process is forked by gcc.  Click ‘Apply’ and the configuration is complete.

 

With the debug configuration finished, click ‘Debug’ and gdb should launch and stop at the ‘main’ function for gcc-4.7.

Step 4 : Making Debug GCC the version of GCC to use for Builds

This step is not *strictly* necessary, though building a plugin or modifying the gcc suite and compiling those modifications with a different version of gcc is ill advised for all sorts of good reasons.  Changing compilers in GCC is straightforward, though a multi-step process.

First, navigate to the Project->Properties->Settings dialog and select ‘GCC C++ Compiler’.  Set the ‘Command’ field to the debug version of g++.  I also set the CXX0X experimental symbol and the -std=c++0x option.

Set the ‘Command’ field for the ‘GCC C++ Linker’ as well.

After pressing ‘OK’, the newly built compiler will not be used by Eclipse for compiling this project.  There doesn’t appear to be a way to set these options globally, so the same changes will have to be made for each project you wish to compile with the the debug GCC suite.

Build a Debug Version of GCC 4.7.2 or 4.8.0 for Ubuntu 12.04

Prerequisites:

This procedure is predicated on using Ubuntu 12.04 LTS amd64 as the development OS and GCC version 4.6.3 packaged in that version of Ubuntu to bootstrap the GCC build itself.  A key complication for the build process is that the multiarch changes being made to GCC to support improved cross-compilation functionality are not yet supported by out-of-the-box Debian based Linux distributions, like Ubuntu.  The following link contains the details and the extra symbolic links needed to get the build to complete.

http://askubuntu.com/questions/128987/ubuntu-12-breaks-gcc-4-7-build-from-source

I have tried to build GCC 4.6.3 on Ubuntu 12.04 i386 (i.e. 32 bit) but with marginal success.  The build process required a bit more patching than I normally like.  With Ubuntu 12.04 64 bit, one set of initial modifications was all I needed to get the build to run from start to finish without intervention.

Step 1: Prepare VM (Optional)

I strongly suggest using a purpose-built VM for GCC development.  Since GCC forms the foundation of a development environment, mixing GCC compiler development with development of other software elements could be ill advised.  As described below, GCC doesn’t build seamlessly on  Ubuntu, so isolating your GCC development system with the extra symbolic links added to build GCC will eliminate the risk of those changes to the environment affecting other projects sharing the same environment.  Additionally, GCC has a very configurable build system and you may well end up experimenting with configurations that might not play well with other software you are building.

See: Building an Ubuntu 12.04 VM for Development for my short post on creating a development VM using ESXi.

Step 2: Install Required Build Support and Source Code Packages

If you wish to build GCC 4.8.0, read over the modifications section at the end of this post for the tweaks to this process for 4.8.0.

As my goal is to build a debug version of GCC for plugin development, I have no desire to build some of the dependencies from source.  If you want to build debug versions of the libraries gcc depends upon, then follow the process outlined here.  The information provided by Solarian Programmer on that link was quite helpful to me as I plowed through the build process.  The most straightforward way to insure your environment has the right dependencies in place for the build is to get the ‘build-dep’ package for the GCC 4.7 series.  Once the dependencies are in place, I pull the archive containing the GCC source and put it into a separate build directory in my home folder.  Mirrors for GCC source may be found here: http://gcc.gnu.org/mirrors.html, choose one appropriate for your geography.

The script below captures my sequence of commands:

$ sudo apt-get build-dep gcc-4.7-base
$ mkdir gcc-build
$ cd gcc-build
$ mkdir 4.7.2
$ cd 4.7.2
$ wget 'your mirror here'/gcc-4.7.2.tar.bz2
$ tar -jxvf gcc-4.7.2.tar.bz2

Step 3 : Patch the OS for the Build :

Patching the OS for the GCC build requires defining a pair of symbolic links to insure the build system can find the right include files and libraries for the build:

$ cd /usr/include
$ ln -s x86_64-linux-gnu/* .
$ cd /usr/lib
$ sudo ln -s x86_64-linux-gnu/crt* .

You will get some ‘failed to create symbolic link’ messages when creating links in the include directory, these don’t appear to cause problems.  I used elevated permissions to insure all the links in /usr/lib directory were created.

Step 4 : Configure and Build GCC

I typically create a build directory inside of the GCC version specific directory and build in it.  This keeps all the source code and executables together in one directory structure and makes it easy to remove broken builds by simply removing the entire directory.  There are a fair number of configuration options for the build; I run ‘gcc -v’ to get the configuration of the stock build for the platform and then pick the options that seem to make sense.  For this build, be sure to add the –disable-multilib option to prevent the build system from trying to build the multi-arch versions of gcc.  If you are interested in building gcc plugins, then also include the –enable-plugin configuration option.

If you plan on installing this debug build into an environment which already has a version of GCC installed, then you ought to use the –prefix and –program-suffix configuration options to distinguish your build from the stock build.  Ubuntu 12.04 includes GCC 4.6.3 and it is not generally a good idea to replace the version of GCC that ships with an OS image; parts of the system may depend on that version of the compiler suite.  The –prefix configuration option specifies the directory into which the newly built gcc suite should be installed.  The –program-suffix option allows you to specify a label to be appended to all the executable files generated in the build.  For example –program-suffix=-4.7.2 would result in the gcc executable being labelled ‘gcc-4.7.2’.

For make, the ‘-g3’ flag causes the compiler to emit the maximum level of debug information, including debugging of macros in gdb.  The ‘-O0’ option turns off optimizations, as some optimizations result in changes to the AST tree that don’t map well to the source code for debugging.  The ‘-j4’ option allows make to fork up to 4 child processes to parallelize the build.  Stage1 builds the C compiler with the compiler packaged with the Ubuntu distribution, 4.6.3 in my case.  Once the C compiler has been built, the rest of the gcc suite will be built with that compiler.

$ cd ~/gcc-build/4.7.2/gcc-4.7.2
$ mkdir build
$ cd build
$ ../configure --build=x86_64-linux-gnu --disable-multilib --prefix=/usr/gcc-4.7.2 --program-suffix=-4.7.2 --with-system-zlib --without-included-gettext --enable-threads=posix --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-plugin --disable-werror --with-arch-32=i686
$ make -j4 STAGE1_CFLAGS="-g3 -O0" all-stage1
$ make -j4 CXXFLAGS="-g3 -O0"

After issuing the last make command, you will have plenty of time to get a refreshing beverage while the build system churns away.  When the build completes, you should have a complete gcc compiler suite built for debugging.

Step 5 : Install GCC

With the suite built, you have the choice of leaving the build directory alone and specifying the appropriate paths to the compiler, includes and libraries in the build tree or you can install the compiler into appropriate system directories.  In the absence of specifying –prefix, the suite will install into /usr/local.  If you have specified –prefix, then the suite will install into a tree rooted in the specified directory.  For the example above, the suite would install below /user/gcc-4.7.2.  The suite may be installed wit the following command.

$ sudo make install

The sudo command is needed if you will be installing into a system directory.

Modifications for GCC 4.8.0:

This approach works as-is for gcc 4.8.0; needless to say you must substitute ‘4.8.0’ for ‘4.7.2’ throughout the process.  There is not yet a ‘build-dep’ package for ‘gcc-4.8-base’ but I found that using the package for ‘gcc-4.7-base’ works.

One issue you will encounter when using GCC 4.8.0 on an otherwise stock Ubuntu 12.04 is that GCC 4.8.0 now defaults to the DWARF-4 format for debugging info whereas the current version of gdb packaged with Ubuntu 12.04 (gdb version 7.4) expects DWARF-3 debugging information.  You have two choices: 1) you can upgrade to gdb 7.5 or above as DWARF-4 is the default format for 7.5 and beyond or 2) add the compiler setting: ‘-gdwarf-3’ to your projects to force the compiler to emit DWARF-3 debugging information.

I found GCC 4.8.0 to work every bit as well as GCC 4.7.2 and 4.8.0 has a couple of nice C++ 11 enhancements, generalized attributes for example.

Building an Ubuntu 12.04 VM for Development

I use the ESXi hypervisor, I find it ‘just works’ and the VSphere client is easy to use.  That said, as the bulk of virtualization is moving into the CPU silicon there is increasing parity amongst the mainstream hypervisors.  There is no reason why Xen, KVM, Hyper-V or VirtualBox won’t work equally well.

For Ubuntu 12.04 on ESXi, I take the defaults presented for a ‘typical’ Ubuntu 64Bit VM.  I allocate 48GB of thin-provisioned storage and 2GB of memory.  For this example I used the 12.04.1 64Bit Desktop Ubuntu Desktop build:

Ubuntu 12.04.1 Desktop 64 Bit

I prefer the Gnome Classic desktop and I install it immediately after the obligatory update and upgrade.

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install gnome-shell

Reboot after the update and gnome-shell install.  When the login screen reappears, click on the Ubuntu icon to the right of the user name.  A dropdown menu will appear with a number of desktop selections, I choose ‘GNOME Classic’.

For remoting the Ubunutu GUI, I find FreeNX provides the easiest to use, most responsive platform.  The install and configuration of that package may be found here: https://help.ubuntu.com/community/FreeNX and the condensed procedure for 12.04 follows:

sudo add-apt-repository ppa:freenx-team
sudo apt-get update
sudo apt-get install freenx
cd /usr/lib/nx
sudo wget https://bugs.launchpad.net/freenx-server/+bug/576359/+attachment/1378450/+files/nxsetup.tar.gz
sudo tar xvf nxsetup.tar.gz
sudo ./nxsetup --install --setup-nomachine-key
cd ~

I use the NX Client for Windows to connect to the development server.  The client may be found here: http://www.nomachine.com/select-package-client.php

For ESXi, I also install open-vm-tools, it is easier than adding the VMWare repositories or installing the tools from the server itself (which bypasses the package systems as well).


sudo apt-get install open-vm-tools

After all of the above is complete, I typically export the VM as an OVF so I can quickly rebuiild the OS if I damage the one I am working with or create new VMs without the handiwork.