• Plugin with controlled variable for initialization.

    From hreba@21:1/5 to All on Wed Feb 2 18:21:03 2022
    For the plugin scheme in my actual program I worked along the
    corresponding gnat example, but while the original works, mine doesn't.
    So I boiled it down to a minimum.

    plugin.ads
    ----------

    package Plugin is
    procedure Empty;
    end Plugin;

    plugin.adb
    ----------
    with Ada.Finalization;
    with Ada.Text_IO;

    package body Plugin is

    type Life_Controller is new Ada.Finalization.Limited_Controlled with
    null record;
    overriding procedure Initialize (lc: in out Life_Controller);
    overriding procedure Finalize (lc: in out Life_Controller);

    procedure Empty is
    begin
    null;
    end Empty;

    overriding procedure Initialize (lc: in out Life_Controller) is
    begin
    Ada.Text_IO.Put_Line("Hello world!");
    end Initialize;

    overriding procedure Finalize (lc: in out Life_Controller) is
    begin
    Ada.Text_IO.Put_Line("Bye world!");
    end Finalize;

    lc: Life_Controller;

    end Plugin;

    main.adb
    --------
    with System;
    with Interfaces.C.Strings;
    with Ada.Text_IO;

    procedure Main is

    use type System.Address;
    RTLD_LAZY: constant := 1;
    handle: System.Address;

    function dlopen (Lib_Name: String; Mode: Interfaces.C.int)
    return System.Address;
    pragma Import (C, dlopen, "dlopen");

    begin
    handle:= dlopen ("../Plugin/lib/libplugin.so" & ASCII.NUL, RTLD_LAZY);
    if handle = System.Null_Address then
    Ada.Text_IO.Put_Line("unable to load plugin");
    end if;
    end Main;


    Main executes without any output. My understanding is the following:

    - When plugin loading with dlopen fails, I get an error message.
    - Otherwise, the controlled variable lc in plugin.adb comes to life and
    I get an output from the Initialize procedure.

    Where is my misconception?
    --
    Frank Hrebabetzky, Kronach +49 / 9261 / 950 0565

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dmitry A. Kazakov@21:1/5 to hreba on Wed Feb 2 19:05:19 2022
    On 2022-02-02 18:21, hreba wrote:
    For the plugin scheme in my actual program I worked along the
    corresponding gnat example, but while the original works, mine doesn't.
    So I boiled it down to a minimum.

    plugin.ads
    ----------

    package Plugin is
       procedure Empty;
    end Plugin;

    plugin.adb
    ----------
    with Ada.Finalization;
    with Ada.Text_IO;

    package body Plugin is

       type Life_Controller is new Ada.Finalization.Limited_Controlled with null record;
       overriding procedure Initialize (lc: in out Life_Controller);
       overriding procedure Finalize (lc: in out Life_Controller);

       procedure Empty is
       begin
          null;
       end Empty;

       overriding procedure Initialize (lc: in out Life_Controller) is
       begin
          Ada.Text_IO.Put_Line("Hello world!");
       end Initialize;

       overriding procedure Finalize (lc: in out Life_Controller) is
       begin
          Ada.Text_IO.Put_Line("Bye world!");
       end Finalize;

       lc:    Life_Controller;

    end Plugin;

    main.adb
    --------
    with System;
    with Interfaces.C.Strings;
    with Ada.Text_IO;

    procedure Main is

       use type System.Address;
       RTLD_LAZY:    constant := 1;
       handle:    System.Address;

       function dlopen (Lib_Name: String; Mode: Interfaces.C.int)
               return System.Address;
       pragma Import (C, dlopen, "dlopen");

    begin
       handle:= dlopen ("../Plugin/lib/libplugin.so" & ASCII.NUL, RTLD_LAZY);
       if handle = System.Null_Address then
          Ada.Text_IO.Put_Line("unable to load plugin");
       end if;
    end Main;


    Main executes without any output. My understanding is the following:

     - When plugin loading with dlopen fails, I get an error message.
     - Otherwise, the controlled variable lc in plugin.adb comes to life and
       I get an output from the Initialize procedure.

    Where is my misconception?

    Probably, you do not have automatic initialization of the Ada run-time.

    for Library_Auto_Init use "False";

    Which is good, because under Windows would deadlock.

    What you should do is:

    1. Add an entry point to the library. Call it in order to return the
    expected minimum version of Main. It would add resilience. The
    implementation must be simple and not to require initialization. E.g.

    function get_required_version return Interfaces.C.unsigned;
    pragma Convention (C, get_required_version);

    Use dlsym to get the address:

    type get_required_version_ptr is
    function return Interfaces.C.unsigned;
    pragma Convention (C, get_required_version_ptr);
    function dlsym
    ( handle : System.Address;
    symbol : char_array := "get_required_version" & NUL
    ) return get_required_version_ptr;
    pragma Import (C, dlsym);

    2. Add another entry point like My_DLL_Init to call after version check.
    From there first call to Ada run-time initialization. I believe it is named

    <library-name>init

    After that you could do plug-in bookkeeping, calling registering
    subprograms etc.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)