Author Archives: Stephan Friedl

About Stephan Friedl

Stephan is a software architect, husband and father of three and his depth of experience in each domain follows the same ordering. The Friedl family lives and plays in Frederick, CO which is north of Denver and east of Boulder. Stephan Works for Cisco Systems in the Boulder, CO office. The content of this blog and opinions expressed herein are entirely Stephan's and should not be construed as reflecting Cisco's corporate position on anything whatsoever.

Building GCC Plugins – Part 2: Introduction to GCC Internals

Once the basic scaffolding is in place for a GCC Plugin, the next step is to analyze and perhaps modify the Abstract Syntax Tree (AST) created by GCC as a result of parsing the source code.  GCC is truly a marvel of software engineering, it is the de-facto compiler for *nix environments and supports a variety of front ends for different langauages (even Ada…).  That said, the GCC AST is complex to navigate for a number of reasons.  First, parsing and representing a variety of languages in a common syntax tree is a complex problem so the solution is going to be complex.  Second, history – looking at the GCC internals is a bit like walking down memory lane; this is the way we wrote high-performance software when systems had limited memory (think 64k) and CPUs had low throughput (think 16Mhz clock cycles).  Prior to GCC 4.8.0, GCC was compiled with the C compiler, so don’t bother looking for C++ constructs in the source code.

The AST Tree

The primary element in the GCC AST is the ‘tree’ structure.  An introduction to the tree structure appears in the GCC Internals Documentation.  Figure 1 is extracted from the tree.h header file and provides a good starting place for a discussion of the GCC tree and how to approach programming with it.


union GTY ((ptr_alias (union lang_tree_node),
 desc ("tree_node_structure (&%h)"), variable_size)) tree_node {
 struct tree_base GTY ((tag ("TS_BASE"))) base;
 struct tree_typed GTY ((tag ("TS_TYPED"))) typed;
 struct tree_common GTY ((tag ("TS_COMMON"))) common;
 struct tree_int_cst GTY ((tag ("TS_INT_CST"))) int_cst;
 struct tree_real_cst GTY ((tag ("TS_REAL_CST"))) real_cst;
 struct tree_fixed_cst GTY ((tag ("TS_FIXED_CST"))) fixed_cst;
 struct tree_vector GTY ((tag ("TS_VECTOR"))) vector;
 struct tree_string GTY ((tag ("TS_STRING"))) string;
 struct tree_complex GTY ((tag ("TS_COMPLEX"))) complex;
 struct tree_identifier GTY ((tag ("TS_IDENTIFIER"))) identifier;
 struct tree_decl_minimal GTY((tag ("TS_DECL_MINIMAL"))) decl_minimal;
 struct tree_decl_common GTY ((tag ("TS_DECL_COMMON"))) decl_common;
 struct tree_decl_with_rtl GTY ((tag ("TS_DECL_WRTL"))) decl_with_rtl;
 struct tree_decl_non_common GTY ((tag ("TS_DECL_NON_COMMON"))) decl_non_common;
 struct tree_parm_decl GTY ((tag ("TS_PARM_DECL"))) parm_decl;
 struct tree_decl_with_vis GTY ((tag ("TS_DECL_WITH_VIS"))) decl_with_vis;
 struct tree_var_decl GTY ((tag ("TS_VAR_DECL"))) var_decl;
 struct tree_field_decl GTY ((tag ("TS_FIELD_DECL"))) field_decl;
 struct tree_label_decl GTY ((tag ("TS_LABEL_DECL"))) label_decl;
 struct tree_result_decl GTY ((tag ("TS_RESULT_DECL"))) result_decl;
 struct tree_const_decl GTY ((tag ("TS_CONST_DECL"))) const_decl;
 struct tree_type_decl GTY ((tag ("TS_TYPE_DECL"))) type_decl;
 struct tree_function_decl GTY ((tag ("TS_FUNCTION_DECL"))) function_decl;
 struct tree_translation_unit_decl GTY ((tag ("TS_TRANSLATION_UNIT_DECL")))
 translation_unit_decl;
 struct tree_type_common GTY ((tag ("TS_TYPE_COMMON"))) type_common;
 struct tree_type_with_lang_specific GTY ((tag ("TS_TYPE_WITH_LANG_SPECIFIC")))
 type_with_lang_specific;
 struct tree_type_non_common GTY ((tag ("TS_TYPE_NON_COMMON")))
 type_non_common;
 struct tree_list GTY ((tag ("TS_LIST"))) list;
 struct tree_vec GTY ((tag ("TS_VEC"))) vec;
 struct tree_exp GTY ((tag ("TS_EXP"))) exp;
 struct tree_ssa_name GTY ((tag ("TS_SSA_NAME"))) ssa_name;
 struct tree_block GTY ((tag ("TS_BLOCK"))) block;
 struct tree_binfo GTY ((tag ("TS_BINFO"))) binfo;
 struct tree_statement_list GTY ((tag ("TS_STATEMENT_LIST"))) stmt_list;
 struct tree_constructor GTY ((tag ("TS_CONSTRUCTOR"))) constructor;
 struct tree_omp_clause GTY ((tag ("TS_OMP_CLAUSE"))) omp_clause;
 struct tree_optimization_option GTY ((tag ("TS_OPTIMIZATION"))) optimization;
 struct tree_target_option GTY ((tag ("TS_TARGET_OPTION"))) target_option;
};

Figure 1: The tree_node structure extracted from the GCC code base.

Fundamentally, a tree_node is a big union of structs.  The union contains a handful of common or descriptive members, but the majority of union members are specific types of tree nodes.  The first tree union member: tree_base is common to all tree nodes and provides the basic descriptive information about the node to permit one to determine the precise kind of node being examined or manipulated.  There is a bit of an inheritance model introduced with tree_base being the foundation and tree_typed and tree_common adding another layer of customization for specific categories of tree nodes to inherit but from there on out the remainder of the union members are specific types of tree nodes.  For example, tree_int_cst is an integer constant node whereas tree_field_decl is a field declaration.

Tree nodes are typed but not in the C language sense of ‘typed’.  One way to think about it is that the tree_node structure is a memory-efficient way to model a class in C prior to C++.  Instead of member functions or methods, there is a large library of macros which act on tree nodes.  In general, macros will fall into two categories: predicate macros which will usually have a ‘_P’ suffix and return a value which can be compared to zero to indicate a false result and transformation macros which take a tree node and usually return another tree node.  Despite the temtpation to dip directly into the public tree_node structure and access or modify the data members directly – don’t do it.  Treat tree nodes like a C++ classes in which all the data members are private and rely on the tree macros to query or manipulate tree nodes.

Relying on the macros to work with the tree_node structure is the correct approach per GCC documentation but will also simply make your life easier.  GCC tree_node structures are ‘strongly typed’ in the sense that they are distinct in the GCC tree type-system and many of the macros expect a specific tree_node type.  For example the INT_CST_LT(A, B) macro expects to have two tree_int_cst nodes passed as arguments – even though the C++ compiler cannot enforce the typing at compile time.  If you pass in the wrong  tree_node type, you will typically get a segmentation violation.  An alternative approach is to compile GCC with the –enable-checking flag set which will enforce runtime checking of node types.

In terms of history, this type of modelling was common back in the day when machines were limited in memory and compute cycles.  This approach is very efficient in terms of memory as the union overlays all the types and there are no virtual tables or other C++ class overhead that consumes memory or requires compute overhead.  The price paid though is that it is 100% incumbent on the developer to keep the type-system front-of-mind and insure that they are invoking the right macros with the right arguments.  The strategy of relying on the compiler to advise one about type mis-matches does not work in this kind of code.

Basics of AST Programming

There are 5 key macros that can be invoked safely on any tree structure.  These three are: TREE_CODE, TREE_TYPE, TREE_CHAIN, TYPE_P and DECL_P.  In general after obtaining a ‘generic’ tree node, the first step is to use the TREE_CODE macro to determine the ‘type’ (in the GCC type-system) of the node.  The TREE_TYPE macro returns the source code ‘type’ associated with the node.  For example, the node result type of a method declaration returning an interger value will have a TREE_TYPE with a TREE_CODE equal to INTEGER_TYPE.  The code for that statement would look like:


TREE_CODE( TREE_TYPE( DECL_RESULT( <em>methodNode</em> ))) == INTEGER_TYPE

Within the AST structure, lists are generally represented as singly-linked lists with the link to the next list member returned by the TREE_CHAIN macro.  For example, the DECL_ARGUMENTS macro will return a pointer to the first parameter for a function or method.  If this value is NULL_TREE, then there are no parameters, otherwise the tree node for the first parameter is returned.  Using TREE_CHAIN on that node will return NULL_TREE if it is the only parameter or will return a tree instance for the next parameter.  There also exists a vector data structure within GCC and it is accessed using a different set of macros.

The TYPE_P and DECL_P macros are predicates which will return non-zero values if the tree passed as an argument is a type specification or a code declaration.  Knowing this distinction is important as it then quickly partitions the macros which can be used with node.  Many macros will have a prefix of ‘TYPE_’ for type nodes and ‘DECL_’ for declaration nodes.  Frequently there will be two sets of identical macros, for instance TYPE_UID will return the GCC generated, internal numeric unique identifier for a type node whereas DECL_UID is needed for a declaration node.  In general, I have found that calling a TYPE_ macro on a declaration or a DECL_ macro on a type specification will result in a segmentation violation.

Other frequently used macros include: DECL_NAME and TYPE_NAME to return a tree node that contains the source code name for a given element.  IDENTIFIER_POINTER can then be used on that tree to return a pointer to the char* for the name.  DECL_SOURCE_FILE, DECL_SOURCE_LINE and DECL_SOURCE_LOCATION are available to map an AST declaration back to the source code location.  As mentioned above, DECL_UID and TYPE_UID return numeric unique identifiers for elements in the source code.

In addition to the above, for C++ source code fed to g++, the compiler will inject methods and  fields not explicitly declared in the c++ source code.  These elements can be identified with the DECL_IS_BUILTIN and DECL_ARTIFICIAL macros.  If as you traverse the AST you trip across oddly named elements, check the node with those macros to determine if the nodes have been created by the compiler.

Beyond this simple introduction, sifting through the AST will require a lot of time reviewing the tree.h and other header files to look for macros that you will useful for your application.  Fortunately, the naming is very consistent and quite good which eases the hunt for the right macro.  Once you think you have the right macro for a given task, try it in your plugin and see if you get the desired result.  Be prepared for a lot of trial-and-error investigation in the debugger.  Also, though there are some GDB scripts to pretty-print AST tree instances, looking at these structure in the debugger will also require some experience, as again the debugger isn’t able to infer much about GCC’s internal type system.

Making the AST Easier to Navigate and Manipulate

I have started a handful of C++ libraries which bridge the gap between the implicit type system in the GCC tree_node structure and explicit C++ classes modelling distinct tree_node types.  For example, a snippet from my TypeTree class appears below in Figure 2.


class TypeTree : public DeclOrTypeBaseTree
 {
 public :

TypeTree( const tree& typeTree )
 : DeclOrTypeBaseTree( typeTree )
 {
 assert( TYPE_P( typeTree ) );
 }

TypeTree& operator= ( const tree& typeTree )
 {
 assert( TYPE_P( typeTree ) );

(tree&)m_tree = typeTree;

return( *this );
 }

 const CPPModel::UID UID() const
 {
 return( CPPModel::UID( TYPE_UID( TYPE_MAIN_VARIANT( m_tree ) ), CPPModel::UID::UIDType::TYPE ) );
 }

 const std::string Namespace() const;

std::unique_ptr<const CPPModel::Type> type( const CPPModel::ASTDictionary& dictionary ) const;

CPPModel::TypeInfo::Specifier typeSpecifier() const;

CPPModel::ConstListPtr<CPPModel::Attribute> attributes();
 };

Figure 2: TypeTree wrapper class for GCC tree_node.

Within this library I make extensive use of the STL, Boost libraries and a number of C++ 11 features.  For example, ConstListPtr<> is a template alias for a std::unique_ptr to a boost::ptr_list class.


template <class T> using ListPtr = std::unique_ptr<boost::ptr_list<T>>;
 template <class T> using ConstListPtr = std::unique_ptr<const boost::ptr_list<T>>;

template <class T> using ListRef = const boost::ptr_list<T>&;

template <class T> ConstListPtr<T> MakeConst( ListPtr<T>& nonConstList ) { return( ConstListPtr<T>( std::move( nonConstList ) ) ); }

Figure 3: Template aliases for lists.

At present the library is capable of walking through the GCC AST and creating a dictionary of all the types in the code being compiled.  Within this dictionary, the library is also able to provide detailed information on classes, structs, unions, functions and global variables.  It will scrape out C++ 11 generalized attributes on many source code elements (not all of the yet though) and return proper declarations with parameters and return types for functions and methods.  The ASTDictionary and the specific language model classes have no dependency on GCC Internals themselves.

The approach I followed for developing the library thus far was to get enough simple code running using the GCC macros that I could then start to refactor into C++ classes.  Along the way, I used Boost strong typedefs to start making sense of the GCC type system at compile time.  Once the puzzle pieces started falling into place and the programming patterns took shape, developing a plugin on top of the libraries is fairly straightforward.  That said, there is a long and painful learning curve associated with GCC internals and the AST itself.

Getting the Code and Disclaimers

The library code is available on Github: ‘stephanfr/GCCPlugin’.  All of the code is under GPL V3.0 which is absolutely required as it runs within GCC itself.  I do not claim that the library is complete, stable, usable or rational – but hopefully some will find it useful if for nothing more than providing some insight into the GCC AST.  For the record, this is not my job nor is it my job to enrich or bug fix the library so you can get your compiler theory class project done in time.  That said, if you pick up the code and either enrich it or fix some bugs – please return the code to me and I will merge what makes sense.

The code should ‘just run’ if you have a GCC Plugin build environment configured per my prior posts.  One detail is that the ‘GCCPlugin Debug.launch’ file will need to be moved to the ‘.launches’ directory of Eclipse’s ‘org.eclipse.debug.core’ plugin directory.  If the ‘.launches’ directory does not exist, then create it.

Building GCC Plugins – Part 1: C++ 11 Generalized Attributes

Historically with C and C++ compilers, you get what you get and you don’t get upset.  There was little or no facility for extending the compiler or for the kind of meta-programming models available in other languages.  Macro or template meta-programming and source code generation has been an option for many, many years but annotation based meta-programming which is a prominent feature of many popular Java frameworks has been very difficult to replicate in C++.

Starting with version 4.5.0, the GCC compiler supports ‘plugins’ which are dynamically loaded modules which make it possible for developers to enrich the compiler without having to modify the GCC source code itself.  There is a bit of information on the GCC Wiki and an excellent set of articles by Boris Kolpackov on the basics of writing GCC plugins.  Beyond those references, I found little else.  I spent a lot of time digging through GCC header files and using trial-and-error to work through decoding the GCC internal data structures.

Starting with GCC version 4.8.0, the compiler supports the C++ 11 standard for ‘generalized attributes’.  GCC (and many other C/C++ compilers) have had attributes for quite some time, but C++ 11 now specifies a standard syntax for both attributes and attribute namespaces.

Taken together, plugins and C++ 11 generalized attributes provide a framework within which annotation based meta-programming may be approached in the GCC compiler.  To be clear, it is not necessarily easy to do – there is a long learning curve for GCC internals – but at least it is achievable without requiring pragmas, code generators or direct modification of the GCC compiler itself.

In this and a series of followup posts, I’ll walk through creating a GCC plugin, adding custom attributes, decoding and traversing the Abstract Syntax Tree (AST) and simple modifications to the AST.

C++11 Generalized Attributes

The GCC compiler has had attributes for quite some time, primarily to provide hints to the compiler or for injecting debugging code.  The GCC syntax appears below:

__attribute__ ((aligned (16)))

Contrast the above with the equivalent C++ 11 syntax:

[[gnu::aligned (16)]]

In the C++ specification, the __attribute__ keyword is gone and double brackets are used to surround the attribute.  Also, the new specification introduces namespaces for attributes.  In the above example, the ‘gnu’ namespace is implicit in the GCC style attribute but must be called out explicitly when using the C++ standard syntax.

Development Environment

In general, I start by creating a VM for the project I will be working on – essentially one VM per project.  In a series of prior posts I walk through creating an Ubuntu development VM, the process required to build a debug version of GCC and how to debug GCC in the Eclipse CDT IDE.  The rest of this post assumes that base environment but there is no reason why the process presented herein could not be modified for a different but functionally similar environment.

For generalized attributes, you will need GCC version 4.8.0 or later.

Creating a GCC Plugin

Step 1: Create a pair of C++ Projects in Eclipse CDT

Perhaps the most straightforward way to build and debug a plugin in Eclipse is to create one  C++ project for the plugin itself and a second ‘dummy’ C++ project which is used to hold the source files to be compiled by a debug instance of GCC with the plugin loaded.  Figure 1 shows the Eclipse Project Explorer window for this simple project.  The ‘GCCAttributesAndPlugin’ project should be an empty shared object and a ‘HelloWorld’ executable is fine for the ‘TestProject’.

Two C++ Projects

Figure 1: Two C++ Projects in Eclipse Explorer

Step 2: Modify the Compiler Settings for the Plugin Project

A small number of modifications to the plugin project C++ compiler settings are necessary to insure the correct version of the compiler is used and the plugin header files are found.  Figure 2 contains an image of the Eclipse C++ Settings dialog with the ‘Command’ changed to point to the 4.8.0 version of the g++ compiler built previously.  Other changes are found in the ‘All Options’ but those will actually be introduced in the next steps.

Figure 2: C++ Compiler Settings

Figure 2: C++ Compiler Settings

Next, the include path for the GCC plugin header files needs to be added to the project.  For an environment configured per my prior post, the correct path is: ‘/usr/gcc-4.8.0/lib/gcc/x86_64-linux-gnu/4.8.0/plugin/include’ and can be seen in the C++ Settings Includes Dialog in Figure 3.

Figure 3: C++ Settings Include Dialog

Figure 3: C++ Settings Include Dialog

Next, a couple of options need top be added to the Miscellaneous dialog as shown in Figure 4.  The two that will need to be added to a vanilla project are: ‘-std=c++0x’ to indicate the C++ 11 language specification should be used and ‘-gdwarf-3’ to force the compiler to emit debugging symbols in dwarf-3 format, as the latest version of the gdb debugger will not accept the default compiler dwarf formation.

Figure 4: C++ Settings Miscellaneous

Figure 4: C++ Settings Miscellaneous

Finally, just as the ‘Command’ was changed for the C++ compiler, the same needs to be done for the Linker as shown in Figure 5.

Figure 5: Linker Settings Dialog

Figure 5: Linker Settings Dialog

Step 3: Modify the Discovery Options for the Plugin Project

To insure that the Eclipse IDE finds the correct include path paths and indexes the project properly, the ‘Discovery Options’ need to be changed to reflect the compiler being used for the project itself.  Figure 6 shows the modification to the ‘Compiler Invocation Command’ for the discovery function.

Figure 6: Discovery Options Dialog

Figure 6: Discovery Options Dialog

Step 4: Source Code for the Plugin

Little source code is required to register custom attributes and build a plugin.  The code for a very simple plugin with attributes appears below.

/*
 * gccplugin.cpp
 *
 * Created on: May 17, 2013
 * Author: steve
 */
#include <iostream>
#include "config.h"
#include "gcc-plugin.h"
#include "tree.h"
#include "cp/cp-tree.h"
#include "diagnostic.h"
#include "plugin.h"

//
// The following global int is needed to let the compiler know that this plugin is//     GPL licensed
//

int plugin_is_GPL_compatible;

static tree HandleAttribute( tree* node,
                             tree attrName,
                             tree attrArguments,
                             int flags,
                             bool* no_add_attrs )
{
    std::cerr << "Encountered Attribute: " << IDENTIFIER_POINTER( attrName );

    // Print the arguments

    std::string separator = " ";
    for( tree& itrArgument = attrArguments; itrArgument != NULL_TREE; itrArgument = TREE_CHAIN( itrArgument ) )
    {
        std::cerr << separator << TREE_STRING_POINTER( TREE_VALUE ( itrArgument ));
        separator = ", ";
    }

    std::cerr << std::endl;

    // Just return a null tree now.

    return( NULL_TREE );
}

static struct attribute_spec g_GeneralizedAttribute1 =
{
 "generalized_attribute_1", 0, -1, false, true, false, HandleAttribute, false
};

static struct attribute_spec g_GeneralizedAttribute2 =
{
 "generalized_attribute_2", 0, -1, false, false, false, HandleAttribute, false
};

//    The array of attribute specs passed to register_scoped_attributes must be NULL terminated
attribute_spec demoScopedAttributes[] = { g_GeneralizedAttribute1, g_GeneralizedAttribute2, NULL };

static void RegisterAttributes( void* eventData,
                                void* userData )
{
 register_scoped_attributes( demoScopedAttributes, "demo" );
}

static void GateCallback( void* eventData, void* userData )
{
     // If there has been an error, fall through and let the compiler handle it
    if( errorcount || sorrycount )
    {
        return;
    }
    std::cerr << "IPA Passes Starting for File: " << main_input_filename << std::endl;
}

int plugin_init( plugin_name_args*   info,
                 plugin_gcc_version* ver )
{
    std::cerr << "Starting Plugin: "<< info->base_name << std::endl;
    register_callback( info->base_name, PLUGIN_ATTRIBUTES, &RegisterAttributes, NULL );
    register_callback( info->base_name, PLUGIN_ALL_IPA_PASSES_START, &GateCallback, NULL );
    std::cerr << "Plugin Initialized, attribute registered" << std::endl;
    return( 0 );
}

The set of includes are pretty much the bare minimum needed for a plugin.  The ‘config.h’ file is the compiler configuration which is generated during the build process and can be found with the compiler includes.  Aside from the inclusion of ‘<iostream>’ to provide output to the console, the remaining includes are for plugin and attribute support.  Since GCC 4.8.0 is compiled using the g++ compiler, it is no longer necessary to wrap the plugin includes with ‘extern C{}’ to denote the difference in name mangling.  Also of note is the global symbol ‘plugin_is_GPL_compatible’ which the compiler checks for in the plugin library when it loads the plugin.  If the compiler does not find this global symbol, it will not finish loading the plugin.

The ‘HandleAttribute()’ function is a callback that is invoked by the compiler when it encounters a custom attribute registered by the plugin.  A separate function pointer to a callback is associated with each attribute registered, so it would be completely reasonable to have a separate callback for each custom attribute.  Within the handler, all we do is print out the attribute name and the attribute arguments.  The arguments are a GCC tree list of constant values – more on how to interpret GCC trees will appear in followup posts.

Next are static specifications of the two custom attributes.  This structure is defined in ‘tree.h’ which also contains good descriptions of the meanings of the fields.  I will not re-iterate that documentation here, but be sure to read through the definition to insure you are  passing the right values.  The ‘RegisterAttributes()’ callback function appears next.  The namespace for scoped attributes appears as the second argument to the ‘register_scoped_attributes()’ – for this case the namespace is ‘demo’.

The ‘GateCallback()’ function is invoked by the plugin framework in response to registrations for notification when specific passes have been completed by the compiler.

Finally, the ‘plugin_init()’ function is the entry point for the plugin.  After the compiler loads the plugin shared object then it will call this function.  There is an argument block and a version information block passed to the function, neither of those arguments are used in this simple example.  This function registers two callbacks: the first to register the custom attributes and the second to register a gate callback on the PLUGIN_ALL_IPA_PASSES_START event.  Once again, for further detail on the parameters for the ‘plugin_init()’ function, the best bet is to refer to the inline documentation in the GCC source code.

Step 5: Source Code for the Test Project

The source code for a test project with a pair of classes with attributes appears below.  This file is just the auto-generated ‘HelloWorld’ project source code with the two demo classes added.  Note the C++ 11 syntax for the attributes with the ‘demo’ namespace.


/============================================================================
// Name : TestProject.cpp
// Author :
// Version :
// Copyright : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
using namespace std;

class [[demo::generalized_attribute_1( "arg1", "arg2" )]] ClassWithAttribute1
{
};

class [[demo::generalized_attribute_2( "arg3" )]] ClassWithAttribute2
{
};

int main() {
 cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!
 return 0;
}

Step 6: Create the .gdbinit file

The ‘.gdbinit’ file contains configuration information for the GDB debugger when it is invoked by the Eclipse IDE.  For debugging a GCC plugin, the file should have at least the following contents:

set schedule-multiple
dir ~/gcc_build/4.8.0/build/gcc
dir ~/gcc_build/4.8.0/gcc
dir ~/gcc_build/4.8.0/gcc/cp
dir ~/gcc_build/4.8.0/gcc/lto
source ~/gcc_build/4.8.0/build/gcc/gdbinit.in

The ‘.gdbinit’ file may be placed in the root directory of the plugin project.

Step 7: Create a Debugger Profile for the Plugin Project

To debug the plugin inside of Eclipse, the approach I use is to adjust the debugging launch profile for the plugin project so that it launches GCC and loads the plugin to compile the source code in the ‘Test Project’.  The first step is to set the ‘C/C++ Application’ to the compiler itself in the ‘Main’ dialog of the Debug Launch Configuration Properties, as shown in Figure 7.

Figure 7: Debug Profile Main Dialog

Figure 7: Debug Profile Main Dialog

The next step is to tell the compiler to load the plugin, specify C++ 11 semantics and point the compiler at the source code file in ‘TestProject’, as shown in Figure 8.

Figure 8: Arguments Tab for the Debug Launch Profile

Figure 8: Arguments Tab for the Debug Launch Profile

Next, the LD_LIBRARY_PATH and the PATH environment variables need to be enriched to add the paths to the GCC 4.8.0 compiler executables and libraries.  This is done on the ‘Environment’ tab as shown in Figure 9.  Additional detail is shown in Figures 10 and 11.

Figure 9: Debug Profile Environment Tab

Figure 9: Debug Profile Environment Tab

Figure 10: LD_LIBRARY_PATH setting

Figure 10: LD_LIBRARY_PATH setting

Figure 11: PATH environment variable setting

Figure 11: PATH environment variable setting

Finally, on the ‘Debugger’ tab, insure that the ‘GDB Command Line’ points to your ‘.gdbinit’ file created above and check the ‘Automatically debug forked process’ box.  GCC forks the g++ compiler from a main controller process, so if this checkbox is blank, then GDB will not debug the forked g++ process where the plugin actually gets loaded.

Figure 12: Debug Profile Debugger Tab

Figure 12: Debug Profile Debugger Tab

Step 8: Pass arguments to the plugin

 The command line syntax to pass one or more arguments to a plugin is a little tricky.  Given that a multiplicity of plugins may be simultaneously loaded into GCC, the disambiguation of which arguments are associated with which plugin are embedded in the command line.  The syntax to pass an argument to a plugin is:


-fplugin-arg-'plugin name'-'argument name'='argument value'

For this example, the program arguments tab would contain the following:

Figure 9 : Debug Arguments Tab with Plugin Arguments

Figure 13: Debug Arguments Tab with Plugin Arguments

Upon entering plugin_init(), the info->argc argument will contain the count of plugin arguments and the info->argv->key and info->argv->value arrays will contain the key value pairs passed on the command line.

Not that the attached example code does not include plugin arguments.

Step 9: Run the code

If you run the debug profile just created for the plugin project you should see output like this in the console:

Figure 13: Debug Console Output

Figure 14: Debug Console Output

That should do it, you have a basic GCC plugin and attribute framework in place.

Prepackaged Projects

If you have a development environment build as described in my prior posts, then you should be able to take the contents of the attached zip file and simply extract them into your workspace to get the two projects.  Also in the zip file is the debug profile which is in the ‘.launches’ directory.  This directory needs to be placed under the ‘.metadata/.plugins/org.eclipse.debug.core’ directory for Eclipse to recognize the profile.  If you drop in the directory while Eclipse is running, then you will need to re-start Eclipse.

Project Files

Creating an OpenStack Keystone ‘HelloWorld’ Extension

The OpenStack ‘cloud operating system’ provides a model, framework and  a core set of platform services managing core virtualized datacenter resources.  As of the Folsom release, the following services are packaged as part of the solution:

  • Keystone – Identity, Authentication and Authorization
  • Glance – Image Management
  • Nova – Compute
  • Quantum – Network
  • Swift – Object Storage
  • Cinder – Block Storage
  • Horizon – Web App Dashboard

Development of OpenStack is a collaborative venture between a global community of individuals and organizations.  Given the loosely coupled, standards based approach to development, a systems architecture composed of loosely coupled services adhering to a standardized API specification was needed to permit the project to move forward rapidly with a minimum of centralized coordination.

One of the core elements of the OpenStack architecture is support for extensibility.  The evolution of OpenStack will in part be governed by the development of experimental extensions to the base platform which may be promoted to first-class members of the platform should the extension prove generally valuable.  Beyond that, extensibility is needed to permit ‘customization’ of a base OpenStack package for specific deployment configurations or service requirements.

Though the Extension API has some sparse documentation on the OpenStack.org site, there don’t yet appear to be any simple ‘Hello World’ type examples for adding an extension to the Keystone service.  The process is not difficult but it took me some poking around in the code to figure out how to add one of my own.

Development Environment :

I use the DevStack distribution installed on an Ubuntu 12.04 Server OS for development.  In the absence of intrusive network proxies or firewalls, the DevStack distribution ‘just works’.  That said, DevStack is neither intended nor suitable for production deployments.  Be sure to read the DevStack caveats before you start using it so that you minimize potentially unpleasant surprises

Creating an Extension :

Step 1: Create subdirectory under ‘contrib’

For a vanilla DevStack installation, the solution root directory is ‘/opt/stack’.  Keystone extensions are typically placed in individual subdirectories of ‘/opt/stack/keystone/keystone/contrib’.  For this example create a directory named ‘hello_world’.

Step 2: Create a core.py file for the extension mapper and controller

The OpenStack extension architecture relies on the wsgi python framework.  There are some OpenStack wrapper classes that simplify creating an extension.  The code should be placed in the ‘contrib’ directory.  The python code for the hello_world extension appears below.

# vim: tabstop=4 shiftwidth=4 softtabstop=4

# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

from keystone.common import wsgi

from keystone import identity
from keystone import token

class HelloWorldExtension(wsgi.ExtensionRouter):

    def add_routes(self, mapper):
        controller = HelloWorldController()

        mapper.connect( '/example/hello_world',
                        controller=controller,
                        action='get_hello_world',
                        conditions=dict(method=['GET']))

        mapper.connect( '/example/hello_world/{identifier}',
                        controller=controller,
                        action='get_hello_world_with_id',
                        conditions=dict(method=['GET']))

class HelloWorldController(wsgi.Application):

    def __init__(self):
        self.token_api = token.Manager()
        super(HelloWorldController, self).__init__()

    def get_hello_world(self, context):
#       self.assert_admin(context)
        return {
            'SEF-EXAMPLE:hello_world': [
                {
                    'hello': 'world',
                    'description': 'Simple Hello World Keystone Extension',
                },
            ]
        }

    def get_hello_world_with_id(self, context, identifier):
#       self.assert_admin(context)
        return {
            'SEF-EXAMPLE:hello_world_id': [
                {
                    'hello': 'world',
                    'description': 'Simple Hello World Keystone Extension with Identifier',
                    'identifier': identifier,
                },
            ]
        }

The code is fairly straightforward.  The HelloWorldExtension class creates a controller an in the add_routes() method it associates URLs with code handlers.  The code handlers are defined in the HelloWorldController class.

There are two elements of the controller that merit a bit of explanation.  First, the example contains the commented out command: ‘self.assert_admin(context)’ in both code handlers. This command enforces authentication for the extension. It is commented out in the example to make the example easier to invoke with curl. Second, in the mapper the connection: “mapper.connect( ‘/example/hello_world/{identifier}'” specifies ‘{identifier}’ as an argument to the handler. The handler signature: ‘def get_hello_world_with_id(self, context, identifier)’ includes ‘identifier’ as the parameter parsed from the URL.

There are formalized naming conventions for extensions and their namespaces described in the OpenStack documentation.  For anything more than a HelloWorld example, these conventions should be followed.

Step 3: Create __init__.py to load the extension

The ‘__init__.py’ file below should be placed in the  ‘contrib’ subdirectory with the extension code. The file is very straightforward, it just loads the extension.


# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

from keystone.contrib.hello_world.core import *

Step 4: Add an entry for the extension filter in keystone.conf

With the extension created and the ‘__init__.py’ file to load it, the next step is to modify the keystone configuration file to add a filter entry for the extension and then add the filter to the admin API pipeline.  For a standard OpenStack install, this would be the ‘/etc/keystone/keystone.conf’ file.  For DevStack, modifications should be made to the ‘/opt/stack/keystone/etc/keystone.conf.sample’ file which serves as a template for the ‘keystone.conf’ file generated during DevStack start-up.  The content to be added to the configuration file appears below:


[filter:hello_world_extension]
paste.filter_factory = keystone.contrib.hello_world:HelloWorldExtension.factory

[pipeline:admin_api]
pipeline = access_log sizelimit stats_monitoring url_normalize token_auth admin_token_auth xml_body json_body debug stats_reporting ec2_extension s3_extension crud_extension hello_world_extension admin_service

The ‘[filter:hello_world_extension]’ should be added to the end of the list of filters in the configuration file.  The ‘[pipeline:admin_api]’ should already exist in the file, so all that is necessary for that line should be to add the name of the filter to the pipeline.

Step 5: Add self.extensions entry to controllers.py

Extensions are not self-describing so when querying an OpenStack Keystone instance for the extensions it has loaded, it is necessary to add the descriptive metadata to the ‘controllers.py’ class.  For DevStack, this file can be found at ‘/opt/stack/keystone/keystone/controllers.py’.  The code fragment below should be inserted in to the ‘__init__()’ method.


self.extensions['SEF-HELLO-WORLD'] = {
 'name': 'Hello World Example Extension',
 'namespace': 'http://docs.openstack.org/identity/api/ext/'
     'SEF-HELLO-WORLD/v1.0',
 'alias': 'SEF-HELLO-WORLD',
 'updated': '2013-03-18T13:25:27-06:00',
 'description': 'Openstack extensions to Keystone v2.0 API '
 'enabling Admin Operations.',
 'links': [
         {
             'rel': 'describedby',
             'type': 'text/html',
             'href': 'https://github.com/openstack/identity-api',
         }
     ]
 }

Step 6: Check Extension Functionality

If you are using DevStack, the easiest thing to do is to restart it and it will compile and load the new extension. After it has started, there should be two new files: ‘core.pyc’ and ‘__init__.pyc’ in the ‘contrib/hello_world/’ subdirectory. Files with ‘.pyc’ extensions are ‘compiled python’ files which contains python byte code. To check the new extension description, use the following ‘curl’ command and you should see the description in the response:


$ curl http://<em>openstack_ip_addr</em>:35357/v2.0/extensions

{"extensions": {"values": [{"updated": "2013-03-18T13:25:27-06:00", "name": "Hello World Example Extension", "links": [{"href": "https://github.com/openstack/identity-api", "type": "text/html", "rel": "describedby"}], "namespace": "http://docs.openstack.org/identity/api/ext/SEF-HELLO-WORLD/v1.0", "alias": "SEF-HELLO-WORLD", "description": "Openstack extensions to Keystone v2.0 API enabling Admin Operations."}}

To actually invoke the extension, use the following for the two non-authenticated operations:

$ curl http://<em>openstack_ip_addr</em>:35357/v2.0/example/hello_world

{"SEF-EXAMPLE:hello_world": [{"hello": "world", "description": "Simple Hello World Keystone Extension"}]}

$ curl http://<em>openstack_ip_addr</em>:35357/v2.0/example/hello_world/token

{"SEF-EXAMPLE:hello_world_id": [{"identifier": "token", "hello": "world", "description": "Simple Hello World Keystone Extension with Identifier"}]}

Note in the second example that the URL parameter ‘token’ has been passed to the extension handler as the ‘{identifier}’.

Conclusion:

The above gets you going with a Keystone extension, at least for Folsom.  Given the rate at which OpenStack is evolving, it is quite possible that the extension framework may well change in an upcoming release.  One nice enhancement would be to make extensions self-describing which would eliminate the need to add that descriptive meta-data to the ‘controllers.py’ file.

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.