快乐案例
我已经成功地在Ada中编译了一个最小的hello world窗口DLL,并通过FFI接口使用了它:
package MY_FFI is
procedure Hello_World
with
Export => True,
Convention => C,
External_Name => "hello_world";
end MY_FFI;
package body MY_FFI is
procedure Hello_World is
begin
Ada.Text_IO.Put_Line("Hello world!");
end Send_Request;
end MY_FFI;#[link(name = "my_ffi")]
extern "C" {
#[link_name = "hello_world"]
fn ada_hello_world();
fn my_ffiinit(); // same as adainit just renamed by gprbuild
fn my_ffifinal(); // same as adafinal just renamed by gprbuild
}
pub fn initialize_my_ffi() {
unsafe {
println!("step 1");
my_ffiinit();
println!("step 2");
ada_hello_world();
println!("step 3");
}
}其结果是:
step 1
step 2
Hello world!
step 3真实问题
当我的Ada库变得更复杂并且需要以下额外的系统DLL时:
libgnarl-7.dlllibgnat-7.dlllibgcc_s_seh-1.dll (明明POSIX)libwinpthreadthread-1.dll (明明POSIX)我无法准确地挑出需要这些额外DLL的代码,但是一旦代码变得足够复杂到需要这些DLL,它就会在my_ffiinit函数的生锈处停下来,只输出:
step 1同样的代码在x64 Linux上也能工作。另外,对其他Linux平台(powerpc、arm64)也进行交叉编译。
当我使用Library_Auto_Init="true"时,wine64输出:
0009:err:module:LdrInitializeThunk "libmy_ffi.dll" failed to initialize, aborting
0009:err:module:LdrInitializeThunk Initializing dlls for L"Z:\\test.exe" failed, status 20474343主要项目探地雷达:
with "/opt/libA/a_lib.gpr";
with "/opt/libB/b_lib.gpr";
library project MY_FFI is
for Languages use ("Ada");
for Library_Name use "my_ffi";
for Library_Kind use "dynamic";
for Library_Standalone use "encapsulated";
for Source_Dirs use ("src/**");
for Library_Interface use (
"my_ffi",
);
type Target_Type is ("windows64", "windows32", "linux64", "armhf", "powerpc", "arm64");
Target : Target_Type := external ("target", "linux64");
for Library_Dir use "lib/" & external ("target", "linux64");
for Object_Dir use "obj/" & external ("target", "linux64");
end MY_FFI;预编译共享库A的探地雷达
library project a_lib is
for Languages use ("Ada");
for Library_Name use "a";
for Library_Kind use "dynamic";
for Source_Dirs use ("src/**");
type Target_Type is ("windows64", "windows32", "linux64", "armhf", "powerpc", "arm64");
Target : Target_Type := external ("target", "linux64");
for Library_Dir use "lib/" & external ("target", "linux64");
for Object_Dir use "obj/" & external ("target", "linux64");
package Naming is
for Spec_Suffix ("ada") use ".ads";
for Body_Suffix ("ada") use ".adb";
for Separate_Suffix use ".adb";
for Casing use "MixedCase";
for Dot_Replacement use "-";
end Naming;
package Compiler is
for Default_Switches ("ada") use ("-fPIC");
end Compiler;
for Externally_Built use "true";
end a_lib;从资料来源汇编的B库探地雷达:
library project b_lib is
for Source_Dirs use ("src");
for Library_Name use "b";
for Library_Dir use "lib";
for Object_Dir use "obj";
for Languages use ("Ada");
package Compiler is
for Switches ("ada") use ("-O2", "-ffunction-sections", "-gnatQ", "-fdata-sections", "-fPIC", "-gnatf", "-gnatwa");
end Compiler;
package Builder is
for Switches ("ada") use ("-j0", "-k", "-s");
end Builder;
type Target_Type is ("windows64", "windows32", "linux64", "armhf", "powerpc", "arm64");
Target : Target_Type := external ("target", "linux64");
for Library_Dir use "lib/" & external ("target", "linux64");
for Object_Dir use "obj/" & external ("target", "linux64");
end b_lib;发布于 2020-11-21 15:05:28
问题是在主项目配置文件中使用for Library_Standalone use "encapsulated";,当将其替换为默认值standard项目编译失败时,会出现以下错误:
shared library project "my_ffi" cannot import static library project "b"一旦将行for Library_Kind use "relocatable";添加到库B项目配置中,编译错误就会消失,libmy_ffi.dll就会成功编译。更重要的是,当它从Rust调用时,产生的DLL可以正常工作。
仍未回答的怪癖:
gprbuild不强制执行或警告唯一的静态策略发布于 2020-11-21 04:50:45
对Ada不太了解,但它不是有自己的ABI吗?这个文档建议您需要用Convention => C标记一个函数,以便从C调用它,类似于在Rust中使用extern "C"的方式。
发布于 2021-01-04 14:19:54
会不会是在DLL:s中在库级别上创建任务?这是行不通的,因为动态库中的init代码在Windows上是严格单线程的。
https://stackoverflow.com/questions/64931869
复制相似问题