This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Report: using GCC plugin to implement ORM for C++


Hi,

We have just released a C++ object-relational mapping (ORM) system,
called ODB, that uses the new GCC plugin architecture. I thought I
would report back to the GCC community on how the plugin part worked
out.

In a nutshell, the ODB compiler parses a C++ header with class 
declarations (and some custom #pragma's that control the mapping)
and generates C++ code that performs the conversion between these
classes and their database representation. I have included some more
information on ODB at the end of this email for those interested.

What worked well:

  - Access to pretty much all of the GCC functions, macros, and 
    internal data structures.

  - Ability to register custom pragmas and attributes.
  
  - The tree contains information about typedef aliases. Given the
    following code:

    class c {};
    typedef c c_t;
    c_t x;

    One can discover that 'x' was declared as 'c_t', not just that its
    type is 'c'. This is very useful when performing the source-to-source
    translation.

What didn't work so well:

  - The plugin header inclusion is a mess. You have to include the right
    set of headers in the right order to get things to compile. Plus, the
    GCC headers poison some declarations, so, for example, you cannot use
    std::abort. Maybe there is a good reason for this.

  - If the plugin needs to generate something other than assembly (C++
    in our case), then the code that suppresses the opening of the 
    assembly file is quite hackish.

  - There is no callback point after the tree has been constructed and
    before any other transformations have been performed. We use the
    first gate callback (PLUGIN_OVERRIDE_GATE) and do all our work
    there. There is also no well-defined way to stop the compilation
    process at this point. We simply use exit().

  - Working with the GCC tree is not for the faint of heart. Generating
    code from it is particularly hard. In fact, we have created our own
    C++ classes (called "semantics graph") to represent the translation
    unit being compiled. It is not as complete as the GCC's tree but it
    is a lot easier to traverse.


We have built and tested the ODB plugin with GCC 4.5.1 on the following
platforms:

GNU/Linux

 Predictably, everything works out of the box.

Solaris

 Had to add OBJDUMP=gobjdump (or /usr/sfw/bin/gobjdump) when configuring
 GCC. Otherwise, the -rdynamic test will fail. Tested both x86 and SPARC.

Mac OS X

 Had to apply a backported patch for PR 43715.

Windows

 Well, this one was fun. There is no dlopen/dlsym so no plugin support.
 What we did was this: we linked in the ODB plugin statically to the
 cc1plus binary. This required a small patch to the GCC plugin loading
 code. The patch is small instead of being large thanks to the way the
 plugin support is implemented in GCC. Even if plugin support is not
 enabled, most of the code (callback points, etc.) are still there. It's
 just there is no way to load a plugin. This way it was fairly straight-
 forward to add another method of "loading" a plugin. Kudos to whoever
 designed this. I can share the patch/build instructions with anyone
 interested.

Overall, I think, the GCC plugin architecture is a great addition. The
amount of flexibility it affords you is quite amazing.

Some more information on ODB:

ODB is an open-source, compiler-based object-relational mapping (ORM)
system for C++. It allows you to persist C++ objects to a relational
database without having to deal with tables, columns, or SQL and
without manually writing any mapping code. For example:

  #pragma db object
  class person
  {
    ...

  private:
    friend class odb::access;
    person ();

    #pragma db id auto
    unsigned long id_;

    string first_;
    string last_;
    unsigned short age_;
  };

ODB is not a framework. It does not dictate how you should write your
application. Rather, it is designed to fit into your style and 
architecture by only handling C++ object persistence and not 
interfering with any other functionality. As you can see, existing
classes can be made persistent with only a few modifications.

Given the above class, we can perform various database operations with
its objects:

  person john ("John", "Doe", 31);
  person jane ("Jane", "Doe", 29);

  transaction t (db.begin ());

  db.persist (john);
  db.persist (jane);

  result r (db.query<person> (query::last == "Doe" && query::age < 30));
  copy (r.begin (), r.end (), ostream_iterator<person> (cout, "\n"));

  jane.age (jane.age () + 1);
  db.update (jane);

  t.commit ();

The ODB compiler uses the GCC compiler frontend for C++ parsing and is
implemented using the new GCC plugin architecture. While ODB uses GCC
internally, its output is standard C++ which means that you can use
any C++ compiler to build your application.

ODB is written in portable C++ and you should be able to use it with
any modern C++ compiler. In particular, we have tested this release
on GNU/Linux (x86/x86-64), Windows (x86/x86-64), Mac OS X, and Solaris
(x86/x86-64/SPARC) with GNU g++ 4.2.x-4.5.x, MS Visual C++ 2008 and
2010, and Sun Studio 12. The dependency-free ODB compiler binaries
are available for all of the above platforms. The initial release
supports MySQL as the underlying database. Support for other database
systems is in the works.

More information, documentation, source code, and pre-compiled binaries
are available from:

http://www.codesynthesis.com/products/odb/

Boris


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]