首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么Ada在从Rust接口调用时会卡在adainit上?

为什么Ada在从Rust接口调用时会卡在adainit上?
EN

Stack Overflow用户
提问于 2020-11-20 15:07:14
回答 3查看 500关注 0票数 6

快乐案例

我已经成功地在Ada中编译了一个最小的hello world窗口DLL,并通过FFI接口使用了它:

代码语言:javascript
复制
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;
代码语言:javascript
复制
#[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");
    }
}

其结果是:

代码语言:javascript
复制
step 1
step 2
Hello world!
step 3

真实问题

当我的Ada库变得更复杂并且需要以下额外的系统DLL时:

  • libgnarl-7.dll
  • libgnat-7.dll
  • libgcc_s_seh-1.dll (明明POSIX)
  • libwinpthreadthread-1.dll (明明POSIX)

我无法准确地挑出需要这些额外DLL的代码,但是一旦代码变得足够复杂到需要这些DLL,它就会在my_ffiinit函数的生锈处停下来,只输出:

代码语言:javascript
复制
step 1

同样的代码在x64 Linux上也能工作。另外,对其他Linux平台(powerpc、arm64)也进行交叉编译。

当我使用Library_Auto_Init="true"时,wine64输出:

代码语言:javascript
复制
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

主要项目探地雷达:

代码语言:javascript
复制
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的探地雷达

代码语言:javascript
复制
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库探地雷达:

代码语言:javascript
复制
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;
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-11-21 15:05:28

问题是在主项目配置文件中使用for Library_Standalone use "encapsulated";,当将其替换为默认值standard项目编译失败时,会出现以下错误:

代码语言:javascript
复制
shared library project "my_ffi" cannot import static library project "b"

一旦将行for Library_Kind use "relocatable";添加到库B项目配置中,编译错误就会消失,libmy_ffi.dll就会成功编译。更重要的是,当它从Rust调用时,产生的DLL可以正常工作。

仍未回答的怪癖:

  • 为什么这对Linux平台来说不成问题呢?
  • 为什么在编译项目时gprbuild不强制执行或警告唯一的静态策略
票数 5
EN

Stack Overflow用户

发布于 2020-11-21 04:50:45

对Ada不太了解,但它不是有自己的ABI吗?这个文档建议您需要用Convention => C标记一个函数,以便从C调用它,类似于在Rust中使用extern "C"的方式。

票数 1
EN

Stack Overflow用户

发布于 2021-01-04 14:19:54

会不会是在DLL:s中在库级别上创建任务?这是行不通的,因为动态库中的init代码在Windows上是严格单线程的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64931869

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档