From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on ip-172-31-74-118.ec2.internal X-Spam-Level: X-Spam-Status: No, score=-1.9 required=3.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.6 Path: eternal-september.org!reader02.eternal-september.org!aioe.org!qYcU9JfyUhY8OJVCu5UZdA.user.46.165.242.91.POSTED!not-for-mail From: "Dmitry A. Kazakov" Newsgroups: comp.lang.ada Subject: Re: Plugin with controlled variable for initialization. Date: Wed, 2 Feb 2022 19:05:19 +0100 Organization: Aioe.org NNTP Server Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit Injection-Info: gioia.aioe.org; logging-data="51942"; posting-host="qYcU9JfyUhY8OJVCu5UZdA.user.gioia.aioe.org"; mail-complaints-to="abuse@aioe.org"; User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Thunderbird/91.5.1 X-Notice: Filtered by postfilter v. 0.9.2 Content-Language: en-US Xref: reader02.eternal-september.org comp.lang.ada:63443 List-Id: 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 init After that you could do plug-in bookkeeping, calling registering subprograms etc. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de