DllMain/DllMainCRTStartup 不在 DLL 中执行
DllMain/DllMainCRTStartup does not execute in DLL
使用 gnat 构建的 DLL 中的初始化代码在导入时不会自动 运行ning。我做了一个 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:\GNAT15\lib\gcc\i686-pc-mingw32.9.3\adalib",
"-LC:\GNAT15\lib\gcc\i686-pc-mingw32.9.3\adalib\libgnat");
end Proj_Name;
我正在使用 ctypes 测试来自 python 的 dll。我用 ctypes.CDLL 导入它,我可以使用 MyDivision。然而,初始化代码在导入dll时不会运行,因为text_io没有被执行。
另一方面,如果我将 AdaInit 过程添加到代码中,我在编译时会得到类似这样的结果:
undefined reference to `adainit'
非常感谢!
我不确定你是怎么知道初始化代码不是 运行?
我在 macOS 上 运行ning,但 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;
有了这个更简单的 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";
end Proj_Name;
并使用此 C 代码进行测试:
#include <stdio.h>
extern int MyDivision(int, int);
int main()
{
printf("42 / 2 => %d\n", MyDivision(42, 2));
return 0;
}
结果是
$ ./caller
hello world!
42 / 2 => 21
很明显,对我来说,库的阐述 是 调用的,我什么都不用做。
原因是您在项目文件中指定了 Library_Interface
,这意味着您正在构建一个 stand-alone library,
is a library that contains the necessary code to elaborate the Ada units that are included in the library. A stand-alone library is a convenient way to add an Ada subsystem to a more global system whose main is not in Ada since it makes the elaboration of the Ada part mostly transparent.
您可以指定一个不自动初始化的独立动态库,使用
for Library_Auto_Init use "false";
这种情况需要自己调用库的初始化过程;它叫做 {library-name}init
(在你的例子中,mathinit
)。但是你需要从你的主程序中调用它;它需要在 C
中声明
extern void mathinit();
使用 gnat 构建的 DLL 中的初始化代码在导入时不会自动 运行ning。我做了一个 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:\GNAT15\lib\gcc\i686-pc-mingw32.9.3\adalib",
"-LC:\GNAT15\lib\gcc\i686-pc-mingw32.9.3\adalib\libgnat");
end Proj_Name;
我正在使用 ctypes 测试来自 python 的 dll。我用 ctypes.CDLL 导入它,我可以使用 MyDivision。然而,初始化代码在导入dll时不会运行,因为text_io没有被执行。
另一方面,如果我将 AdaInit 过程添加到代码中,我在编译时会得到类似这样的结果:
undefined reference to `adainit'
非常感谢!
我不确定你是怎么知道初始化代码不是 运行?
我在 macOS 上 运行ning,但 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;
有了这个更简单的 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";
end Proj_Name;
并使用此 C 代码进行测试:
#include <stdio.h>
extern int MyDivision(int, int);
int main()
{
printf("42 / 2 => %d\n", MyDivision(42, 2));
return 0;
}
结果是
$ ./caller
hello world!
42 / 2 => 21
很明显,对我来说,库的阐述 是 调用的,我什么都不用做。
原因是您在项目文件中指定了 Library_Interface
,这意味着您正在构建一个 stand-alone library,
is a library that contains the necessary code to elaborate the Ada units that are included in the library. A stand-alone library is a convenient way to add an Ada subsystem to a more global system whose main is not in Ada since it makes the elaboration of the Ada part mostly transparent.
您可以指定一个不自动初始化的独立动态库,使用
for Library_Auto_Init use "false";
这种情况需要自己调用库的初始化过程;它叫做 {library-name}init
(在你的例子中,mathinit
)。但是你需要从你的主程序中调用它;它需要在 C
extern void mathinit();