The plugin loader is based on the package Util.Dll and Util.Abstract_Plugin which provides the actual loader.
The code for this example is located in the ./test directory. How to use the code outside of the configured plugin pls. check the installation section.
The procedure below demonstrate how a plugin is loaded and invoked.
The package Plugin_Interface provides the interface definition of the plugin. It contains an extension of the abstract class Abstract_Plugin which is used to dispatch into any implementation of the Plugin_Interface.
Example 2-1. The main Program
with Ada.Exceptions; use Ada.Exceptions; use Ada; with Util.Plugin_Interface; use Util.Plugin_Interface; with Util.Trace; use Util.Trace; use Util; with Lib; use Lib; with Testplugin_Interface; use Testplugin_Interface; procedure Main is L : Plugin_Interface.Handle := new Lib.Object; H : Testplugin_Interface.Handle ; begin Trace.Start_Trace( Trace_File => "client" ); Trace.Trace_Level( 20 ); H := Load( "test", L ) ; Initialize( H.all ); Finalize( H.all ); exception when Error : Others => LOG( Trace.Flow, "Exception " & Exception_Name( Error ) & " at " & Exception_Message( Error ) ); end Main;
The calls to Trace.Start_Trace and Trace_Level are setting up a trace which is used by all components of the Util packages. It may be omitted but it is help full for debugging.
The Load function loads the actual plugin and provides the pointer to the interface object which might be used by the plugin to call methods from the loading applications. The abstract class Plugin_Interface always requires the implementation of the function Loaderpath. This function return the path where the plugin is expected to be located. In this path the Load function expects to find a library test/libobject.so which will be loaded into the memory.
After this step the application communicates with the plugin code by means of dispatching via the extensions of the type Tesplugin_Interface.Object.
The idea of the Testpluin_Interface is used to separate the plugin code from the application. The Testplugin_Interface is derived from the Abstract_Plugin.Object and as an example extended by an Initialize and Finalize procedure. The actual plugin implementation will use this abstract interface class.
Structure of example
Example 2-2. Interface towards the plugin
with Util.Plugin_Interface; use Util.Plugin_Interface; with Util.Abstract_Plugin; use Util.Abstract_Plugin; use Util; package Testplugin_Interface is type Object is abstract new Abstract_Plugin.Object with private; type Handle is access all Object'Class; procedure Initialize( This : in out Object ) is abstract; procedure Finalize( This : in out Object ) is abstract; function Load( Name : in String; Lib : in Plugin_Interface.Handle ) return Handle ; private type Object is abstract new Abstract_Plugin.Object with null record; end Testplugin_Interface;
The reason for this interface is simply to avoid, that during linking the plugin code is included in the binary of the main program.
The actual plugin is derived from the Testplugin_Interface.Object and it has to provide a function called Initialize which is not part of the Abstract_Plugin interface. During dynamic linking this is the only function which is to be mapped by the linker. In order to avoid the GNAT convention for entries names (module__entry) the Export_Function pragma is used to assign an external name to this function.
The intitialize function is called with the pointer to the interface object (Plugin_Interface.Handle) and returns a pointer to the plugin object which is defined in the plugin code.
The procedures Initialize and Finalize are simply implementations of the Testplugin_Interface which defines our project specific interface to the plugin.
Example 2-3. The plugin package specificaiton
with Util.Plugin_Interface; use Util.Plugin_Interface; with Util.Abstract_Plugin; use Util.Abstract_Plugin; use Util; with Testplugin_Interface; use Testplugin_Interface; package Testplugin is type Object is new Testplugin_Interface.Object with private; type Handle is access all Object'Class; function Initialize( Interface : in Plugin_Interface.Handle ) return Handle; pragma Export_Function(Internal => Initialize, External => initialize, Parameter_Types => (Plugin_Interface.Handle), Result_Type => Handle ); private type Object is new Testplugin_Interface.Object with null record; procedure Initialize( This : in out Object ) ; procedure Finalize( This : in out Object ) ; end Testplugin;
Example 2-4. The plugin package
with Util.Trace; use Util.Trace; use Util; package body Testplugin is ............ function Initialize( Interface : Plugin_Interface.Handle ) return Handle is Result : Handle := new Object; begin LOG( Trace.Flow, "Testplugin Initialized" ); return Result; end Initialize; procedure Initialize( This : in out Object ) is .... procedure Finalize( This : in out Object ) is ..... end Testplugin;