Click here to Skip to main content
15,885,757 members
Articles / Programming Languages / C++

DynObj - C++ Cross Platform Plugin Objects

Rate me:
Please Sign up or sign in to vote.
4.95/5 (34 votes)
27 Sep 200727 min read 142.1K   3.4K   132  
DynObj is an open source library that provides a C++ application with run-time class loading facilities
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
  <meta name="generator" content="HTML Tidy for Windows (vers 14 February 2006), see www.w3.org">

  <title>Dynamic C++ Objects - Solution</title>
  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
  <meta content="MSHTML 6.00.2900.2963" name="GENERATOR">
  <link rel="stylesheet" type="text/css" href="sqs.css">
</head>

<body>
  <table summary="" style="width: 600px; height: text-align: left;" border="1" cellpadding="2" cellspacing="2">
    <tbody>
      <tr>
        <td class="contents">  <br>
          <h2>
              DynObj - C++ Cross platform plugin objects
          </h2>
          <h3>Solution</h3>
          This describes the properties of the DynObj library solution to the plugin/linking problem. <br><br>
          <h4>Cross-platform</h4>
          The library is written in C++, a decent C++ compiler should build it (tested with MSVC 8 and G++ (4.1.2 and 3.4.5). It relies on a minimalistic cross-platform layer for dynamic linking and a spartan threading interface.<br><br>
          <h4>Cross compiler</h4>
          The library/plugin compiler can be a different one than the main application compiler. All casting between types is allways done based on offsets from the source (library) compiler.<br><br>
          <h4>C++ classes used across DLL/SO boundary</h4>
          DynObj supports ordinary C++ classes across the plugin boundary. Any class that consists of:
	  <ul><LI>Zero, one or more base classes/interfaces</LI>
          <LI>Virtual functions (overloading not supported)</LI>
          <LI>Inline functions</LI>
          <LI>Operators</LI>
          <LI>Data members (keep track of member alignment!)</LI>
          </ul>
          So a fairly large subset of the C++ class concept can be used over the boundary. This is what cannot be used:
	  <ul><LI>Non-virtual member functions implemented in a separate source file</LI>
          <LI>Static members (functions,data)</LI>
	  </ul>&nbsp;
          <h4>Object model</h4>
          The object from a plugin represents a full C++ object, including the possibility of having multiple nested base classes. At source code level, a tagging scheme is used to decide which bases to expose. The whole (exposed part) of the inheritance tree is communicated to users of the object.<br><br>
          The object is usually accessed using a single inheritance interface/class. Using a cast operation (query type) one can move between the different interfaces/sub-objects that are implemented.
          <br><br>
          <h4>C++ type query</h4>
          An object can implement a number of interfaces and/or classes. To query an object for another type, the C++ template:
          <p class="code">template&lt;class U, class T&gt; U do_cast(T t)</p> 
          is used. It operates the same way as C++ <em>dynamic_cast&lt;&gt;</em> and provides typed safe casts across the plugin boundary. <em>do_cast</em> (and related functions) provides similar functionality to <em>QueryInterface</em> in COM.<br><br>
          An example:
          <p class="code">
          &nbsp;&nbsp;&nbsp;DynI pdi = /* Basic DynI pointer from somewhere */;<br>
          &nbsp;&nbsp;&nbsp;DynSharedI pdsi = do_cast&lt;DynSharedI*&gt;(pdi)
          </p><br>
          <h4>Arbitrary types and DynI derived types</h4>
          The library introduces a small interface and class collection, based on <em>DynI</em> (a class which knows its own type and can be queried for other types). 
          Both classes based on <em>DynI</em> and arbitrary classes with virtual methods may be used across the plugin boundary.  <br><br>
          When using classes derived from <em>DynI</em>, a separate registration step may be skipped, since a <em>DynI</em> object always knows its own type. <br><br>
          The provided classes derived from <em>DynI</em> also provides for a certain way of instantiating and destroying objects (<em>DynObj</em>), for handling objects with shared ownership (<em>DynSharedI</em>), and also for weak references. <br><br>
          When using arbitrary classes, they must have <strong>at least one</strong> virtual member function. The library provides templates that safely detect if an object has a vtable or not. To use such objects across a plugin boundary, one instance of the type must be registered first.<br><br>
          <h4>Simple type identifiers</h4>
          Types are identified based on the pair:
          <ul><li>Type string</li>
          <li>Type identifier (32-bit integer)</li></ul>
          This is a simple scheme that does not guarantee global (world-wide) type uniqueness. It can however guarantee that the types used inside the application are unique. It is always simple to find the string name for a types. In cast operations, usually only the type integer is carried around (no 128 bit ID structures).<br><br>
          Most times we don't need to know these, we just use the C++ types (which in their turn use the type strings/IDs when needed). 
          <br><br>
          <h4>Plugin role</h4>
             Plugins can use types from the main application (as long as it has headers for it) and also from other loaded plugins. It can also instantiate plugin objects (from itself, ther plugins or the main app).
            <br><br>
          <h4>Light-weight</h4>
          The library is self-contained and relatively small, including the cross-platform layer. A compressed archive of the source is around 200 kb. It does not rely on STL, Boost or any other big component library. It is not tied to a single platform API.<br><br>
          <h4>Facilities</h4>
          The library includes a collection of practical classes, to handle libraries, object instantiation/destruction, smart pointers and more. <br><br>
          Optionally (and recommended) one can use the class <em>DoRunTimeI</em>, which provides shared resources to the application and the plugins. Among other things it makes sure that the various libraries access the same type information, it provides for a pool of named 'published' objects, per-object and per-thread error handling.<br><br>
          A run-time string class, <em>DynStr</em> (in itself a plugin object) is provided, giving plugins a way to deal with Unicode strings. 
          <br><br>
          <h4>Source code preprocessor</h4>
          To setup a C++ class as a plugin type, some registration needs to be done and a library file must be created. To help with this, a tool <em>pdoh</em> is used. It reads C++ source file and triggers on <em>// %%DYNOBJ</em> tags in the source code. <br><br>
          The <em>pdoh</em> tool outputs most of the glue code that is needed, including generating type ID:s.<br><br>
          <h4>With other languages</h4>
          The library relies on the default way of using vtables in C++ together with a binary type description structure. This is a simple binary scheme. So, plugin classes could be used from any language that can use these. A C implementation is straight forward (an object would be a structure with the first member being a pointer to an array of functions). Also, a plugin class could be implemented in another language and used from C++.<br><br>
          Inline functions cannot be shared with another language (they are really compield on both host and plugin side).
          <br><br>
          
          <h4>Requirements</h4>
          The library relies on these features from the C++ compiler:
          <ul>
          <LI>It uses vtables in the default way (one pointer per function, first function at index 0, new functions are stored in declaration order)</LI>
          <LI>Support for <strong>extern "C"</strong> style of exposing non-mangled function names</LI>
          <LI>Support for <strong>__cdecl</strong> function calling convention</LI>
          </ul>
          When a library is compiled, this information is stored and made available at load time, so an incompatible library can be detected.<br><br>
          Virtual destructors are not used across plugin boundaries, since compilers implement them in slightly different ways.<br><br>
          Some earlier versions of g++ (prior to version 2.8) used two slots per function in the VTable, that would not have been compatible.<br><br>
          When exposing data members in a class across a plugin boundary, the best is to make each member fill up one word (32/64-bit) in the structure. That avoids any possibility of unaligned data access.<br><br>
          The size of an exposed type (using sizeof from the plugin compiler) is stored in the type information. The user of a plugin class could detect if data members are aligned differently.<br><br>
          The calling convention can be configured when the library is compiled, some other convention could be used as long as the main and plugin compiler agree on it.<br><br>
          On Linux, the default (implicit) calling convention is <em>__cedcl</em>.
          <br><br>
          Next: A <A href="DynObj-sample.html">sample</A> using the DynObj library.
          <br><br>&nbsp;<br>
         
          </td>
      </tr>
    </tbody>
  </table><br>
</body>
</html>

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions