comp.lang.ada
 help / color / mirror / Atom feed
From: "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de>
Subject: Re: "Plugin°-based code
Date: Mon, 4 Jun 2018 13:59:14 +0200
Date: 2018-06-04T13:59:14+02:00	[thread overview]
Message-ID: <pf39ih$12k4$1@gioia.aioe.org> (raw)
In-Reply-To: 564cec8c-8da9-4e59-a687-5408fd3a429f@googlegroups.com

On 2018-06-04 12:29 PM, mockturtle wrote:

> I have a doubt about what it could be the best solution for some code that I am writing.  I am afraid that the introduction before the actual question is a bit long.
> 
> ** The problem **
> 
> Let me use an example.  Suppose I am writing a program to plot, say, a GANTT chart.  I want the user to be able to choose the output format (say, PDF, SVG or even LaTeX) by giving a suitable option on the command line and I want to be able to add new output format easily, maybe even load the "format handler" as a dynamic library at run-time (so I do not need recompilation).  (Incidentally, I did some experiments with the dynamic loading and it works)
> 
> The structure I give to the code is as follows: first I define an interface for an "abstract plotter," for example
> 
>    package Plotters is
>      type Abstract_Plotter is interface;
> 
>      procedure Line(P: Abstract_Plotter;
>                     X1,Y1, X2, Y2:Float)
>      is abstract;
> 
>      -- And so on...
>    end Plotters;
> 
> Every actual plotter will be a descendant of Abstract_Plotters, for example
> 
>    package Plotters.SVG is
>       type SVG_Plotter is
>       new Abstract_Plotter with private;
> 
>       -- Blah, blah ...
>    end Plotters.SVG;
> 
> In order to allow the user to select the actual plotter via the command line I use a generic package Plugin_Table that implements a kind of "map" from names to descendant of Abstract_Plotter.  Plugin_Table provides two operations:
> 
>    (1) Register_Plugin(T: Tag; Name: String)
> 
>           used by a concrete plotter to "register" itself to the table.  Usually it is called from the "initialization" part of the body of the package definynig the concrete plotter.  For example, plotters-svg.adb could call
> 
>       Register_Plugin(SVG_Plotter'Tag, "svg");

type Abstract_Plotter is interface;
function Get_Name (Plotter : Abstract_Plotter)
    return String is abstract;

type Abstract_Plotter_Ptr is access all Abstract_Plotter'Class;
procedure Register_Plugin (SVG_Plotter_Ptr);

>    (2) Get_Plugin (Name:String) return Abstract_Plotter'Class
> 
>         to be called to generate a concrete plotter.

If you need a factory, OK. But it easier to provide ready-to-use 
instance, then you simply pass its pointer as above. If you need a 
factory you can register a constructing function instead of the tag. I 
understand that you want to use a generic constructor but that is not 
really necessary here unless you want to use pools etc.

> In a future version Plugin_Table will be able to search for some dynamic library to be loaded if a plugin with the given name is not registered.
> 
>     ** The Question **
> 
> In order to have all the built-in plugins registered in my executable, I need to "with" them, so that they are linked to my code and the initialization part of their bodies is elaborated. However, no part of my code call explicitly, say, SVG_Plotter.  Therefore, my solution is to add something like
> 
>    with Plotters.SVG;
>    pragma Warnings(Off, Plotter.SVG);

No. You simply put a call to Register_Plugin in the body of the library 
package:

    package Plotters.SVG is
       Plotter : Abstract_Plotter_Ptr;
    private
      type SVG_Plotter is
        new Abstract_Plotter with private;
    end Plotters.SVG;

    package body Plotters.SVG is
       Plotter := new SVG_Plotter (...);
    begin
       Register_Plotter (Plotter);
    end Plotters.SVG;

When the library is loaded you check if it is the first load. If so, you 
call Ada_Initialize to elaborate it. That is when manual elaboration is 
used. GNAT supports automatic elaboration as well, but it is broken 
under Windows if you are going to use tasking. Elaboration will register 
the plotter and all is done. The rest need not to know anything.

> Also, I am not sure if I risk getting in trouble with Elaboration order.  I think not, but I am not 100% sure.

You must ensure that you elaborate the library strictly once if you load 
it several times.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de


  reply	other threads:[~2018-06-04 11:59 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-06-04 10:29 "Plugin°-based code mockturtle
2018-06-04 11:59 ` Dmitry A. Kazakov [this message]
2018-06-04 14:03 ` Dan'l Miller
2018-06-04 22:08 ` Plugin-based code Randy Brukardt
2018-06-05  8:42 ` "Plugin°-based code Brian Drummond
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox