Using Mingw I have successfully compiled a minimal hello world windows DLL in Ada and used it over the FFI interface:
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");
}
}
Which results in:
step 1
step 2
Hello world!
step 3
When my Ada library gets more complicated and requires following extra system DLLs:
libgnarl-7.dll
libgnat-7.dll
libgcc_s_seh-1.dll
(mingw posix)
libwinpthreadthread-1.dll
(mingw posix)
I am not able to exactly single out the code, which requires those extra DLLs, but once the code gets complicated enough to require these DLLs, it just stalls in the rust at the my_ffiinit
function, outputting only:
step 1
Same code on x64 Linux just works. Also cross-compilation for other Linux platforms (powerpc, arm64) works.
When I use Library_Auto_Init="true"
, wine64 outputs:
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
Main project gpr:
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;
gpr for Precompiled shared library 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;
gpr for library B compiled from the source:
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;
Problem is the use of for Library_Standalone use "encapsulated";
in the main project configuration file, when this is replaced with the default value standard
project compilation fails with the following error:
shared library project "my_ffi" cannot import static library project "b"
Once line for Library_Kind use "relocatable";
is added to library B project configuration, compilation error goes away and libmy_ffi.dll
is compiled successfully. What is more, resulting DLL works as expected when its called from Rust.
gprbuild
not enforce or warn about the only static policy when the project is compiledDon't know much about Ada, but doesn't it have its own ABI? This document suggests that you need to tag a function with Convention => C
in order to call it from C, similarly to how you'd use extern "C"
in Rust.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With