DllMain / DllMainCRTStartup не выполняется в DLL

Код инициализации в сборке DLL с gnat не запускается автоматически при импорте. Я сделал MCVE, который состоит из:

Division.ads

with System;
with Interfaces.C;

package Division is
   --Neither of these work
   procedure DllMainCRTStartup ;
   pragma Export (StdCall, DllMainCRTStartup , "DllMainCRTStartup"); --Edited as noticed by Brian
   -- procedure DllMain
   -- pragma Export (StdCall, DllMain , "DllMain ");

   function Div (A : in INTEGER; B : in INTEGER) return INTEGER;
   pragma Export (C, Div, "MyDivision");

   -- --If I put this, it does not compile... maybe a wrong linkage option set?
   -- procedure AdaInit; 
   -- pragma Import (C, AdaInit, "adainit");
end Division;

Division.adb

with text_io;

package body Division is
   procedure DllMainCRTStartup  is begin --DllMain or DllMainCRTStartup
      text_io.put("INIT CODE YEAH!!!*************!"); --This does not execute :(
      --AdaInit;
   end DllMainCRTStartup ;

   function Div(A : in INTEGER; B : in INTEGER) return INTEGER is
      X : INTEGER := A/B;
   begin
      return X;
   end Div;
end Division;

и gpr:

library project Proj_Name is
  for Library_Name use "math";
  for Object_Dir use "obj";
  for Source_Dirs use ("src");
  for Library_Dir use "lib";
  for Library_Interface use ("Division");
  for Library_Kind use "dynamic";
  for Library_Options use ("-LC:\GNAT\2015\lib\gcc\i686-pc-mingw32\4.9.3\adalib",
                           "-LC:\GNAT\2015\lib\gcc\i686-pc-mingw32\4.9.3\adalib\libgnat");
end Proj_Name;

Я тестирую dll из python с помощью ctypes. Я импортирую его с помощью ctypes.CDLL и могу использовать MyDivision. Однако код инициализации не запускается при импорте dll, так как text_io не выполняется.

С другой стороны, если я добавлю в код процедуру AdaInit, при компиляции я получу что-то вроде этого:

undefined reference to `adainit'

Большое спасибо!


person gccinac    schedule 23.11.2016    source источник
comment
adainit - это не то, что вы пишете или поставляете. Это то, что фреймворк обычно запускает для инициализации Ada RTS перед запуском любого кода Ada, например crt0.c (обычно незаметно) до того, как main () когда-либо будет вызван в программе C. Однако это не объясняет, почему не вызывается запуск вашей DLL. Одна странность: почему в экспортируемом имени есть пробел?   -  person user_1818839    schedule 23.11.2016
comment
Упс ... опечатка. Однако я его изменил, но это не сработало :(   -  person gccinac    schedule 23.11.2016


Ответы (1)


Не знаю, откуда вы знаете, что код инициализации не запускается?

Я работаю на macOS, но аспекты Ada должны быть похожи. Я написал этот пакет spec / body как более простую версию вашего:

package Division is

   function Div (A : in INTEGER; B : in INTEGER) return INTEGER;
   pragma Export (C, Div, "MyDivision");

end Division;

with Ada.Text_IO;
package body Division is

   function Div(A : in INTEGER; B : in INTEGER) return INTEGER is
      X : INTEGER := A/B;
   begin
      return X;
   end Div;

   procedure Test_For_Elaboration is
   begin
      Ada.Text_IO.Put_Line ("hello world!");
   end Test_For_Elaboration;

begin
   Test_For_Elaboration;
end Division;

с этим более простым георадаром

library project Proj_Name is
  for Library_Name use "math";
  for Object_Dir use "obj";
  for Source_Dirs use ("src");
  for Library_Dir use "lib";
  for Library_Interface use ("Division");
  for Library_Kind use "dynamic";
end Proj_Name;

и протестирован с помощью этого кода C:

#include <stdio.h>

extern int MyDivision(int, int);

int main()
{
  printf("42 / 2 => %d\n", MyDivision(42, 2));
  return 0;
}

and the result was

$ ./caller 
hello world!
42 / 2 => 21

так ясно, что для меня разработка библиотеки была вызвана без каких-либо действий.

Причина в том, что вы указали Library_Interface в файле проекта, что означает, что вы создаете автономная библиотека, которая

- это библиотека, содержащая необходимый код для разработки модулей Ada, включенных в библиотеку. Автономная библиотека - это удобный способ добавить подсистему Ada в более глобальную систему, основная часть которой находится не в Ada, поскольку она делает разработку части Ada большей частью прозрачной.

Вы можете указать автономную динамическую библиотеку, которая не инициализируется автоматически, используя

for Library_Auto_Init use "false";

в этом случае вам нужно вызвать процедуру инициализации библиотеки самостоятельно; он называется {library-name}init (в вашем случае mathinit). Но тогда вам нужно вызвать его из вашей основной программы; его нужно объявить на C

extern void mathinit();
person Simon Wright    schedule 23.11.2016
comment
Ах, у тебя есть решение! Спасибо! Я думал, что достаточно экспортировать функцию для запуска при импорте с именем DllMain. Похоже, что это не лучший вариант, поскольку в вашем решении вы используете begin Test_For_Elaboration; конец деления; - person gccinac; 28.11.2016
comment
Ооо! Я должен был заметить, что не было кода инициализации пакета ... - person user_1818839; 28.11.2016