View mode: basic / threaded / horizontal-split · Log in · Help
March 13, 2012
Fortran DLL and D
Hi everyone)

dmd 2.058
os: win 7 64 bit
fortran compilers: gfortran, ftn95

I have a fortran code that compiled into dll:

SUBROUTINE fsu (i)
    real :: x
    integer :: i
    x = 0.025
    print *, 'The answer is x = ', x , i
END SUBROUTINE fsu

and simple D code

import std.stdio;
import core.runtime;
import std.c.windows.windows;
import core.memory;

alias void function(int) MyHandler;

void main()
{
    GC.disable;
    FARPROC fp;
    HMODULE lib = cast(HMODULE)Runtime.loadLibrary("testf.dll");
    MyHandler mh;

    if (lib is null)
    {
        writeln("Lib!");
        return;
    }

    fp = GetProcAddress(lib, "FSU");

    if (fp is null)
    {
            writeln("Proc!");
            writeln(GetLastError());
            return;
    }
    mh = cast(MyHandler) fp;
    (*mh)(1);
    Runtime.unloadLibrary(lib);
}

and its output

The answer is x =     2.500000E-02  1407551829

It's should be an 1 value instead 1407551829.

I think, trouble in param passing.
How it can be fixed? Or where to look?

Thanks)
March 13, 2012
Re: Fortran DLL and D
Fortran uses pass-by-ref by default. You could try

   integer, value :: i

in the Fortran function declaration, OR

   *int

in the MyHandler declaration.
March 13, 2012
Re: Fortran DLL and D
I don't think this can work:
alias void function(int) MyHandler;

maybe:
alias extern(C) void function(int) MyHandler;

And there's no need to call it like this: '(*mh)(1)', call it mh(1).
March 13, 2012
Re: Fortran DLL and D
On Tuesday, 13 March 2012 at 22:30:02 UTC, Tobias Brandt wrote:
> Fortran uses pass-by-ref by default. You could try
>
>     integer, value :: i
>
> in the Fortran function declaration, OR
>
>     *int
>
> in the MyHandler declaration.
in case integer, value :: i or integer, intent(in) :: i

same results


in case int*

int * i;
*i=5;
(*mh)(i);

object.Error: Access Violation
----------------
409960
4097D7
402BA8
402BE7
4027F7
413635
----------------
March 13, 2012
Re: Fortran DLL and D
On 13 March 2012 23:53, Michael <pr@m1xa.com> wrote:
> On Tuesday, 13 March 2012 at 22:30:02 UTC, Tobias Brandt wrote:
>>
>> Fortran uses pass-by-ref by default. You could try
>>
>>    integer, value :: i
>>
>> in the Fortran function declaration, OR
>>
>>    *int
>>
>> in the MyHandler declaration.
>
> in case integer, value :: i or integer, intent(in) :: i
>
> same results
>
>
> in case int*
>
> int * i;
> *i=5;
> (*mh)(i);
>
> object.Error: Access Violation
> ----------------
> 409960
> 4097D7
> 402BA8
> 402BE7
> 4027F7
> 413635
> ----------------
>
>


You could use the C binding syntax:

SUBROUTINE fsu (i) bind(C, name = "FSU")
  real :: x
  integer, value :: i
  x = 0.025
  print *, 'The answer is x = ', x , i
END SUBROUTINE fsu

and then use extern(C) in D. That should work, but you
need a newish Fortran compiler.
March 13, 2012
Re: Fortran DLL and D
On Tuesday, 13 March 2012 at 22:42:38 UTC, Andrej Mitrovic wrote:
> I don't think this can work:
> alias void function(int) MyHandler;
>
> maybe:
> alias extern(C) void function(int) MyHandler;
>
> And there's no need to call it like this: '(*mh)(1)', call it 
> mh(1).

I know, it's short version.

Anyway,

object.Error: Access Violation
----------------
409960
4097D7
402BA8
402BE7
4027F7
413635
----------------
March 13, 2012
Re: Fortran DLL and D
Thanks, but i still get the same.
March 14, 2012
Re: Fortran DLL and D
On 03/13/2012 05:15 PM, Michael wrote:
> Hi everyone)
>
> dmd 2.058
> os: win 7 64 bit
> fortran compilers: gfortran, ftn95
>

Here's apples to oranges, since I'm on linux 64 bit, but with your code 
and this:

pragma(lib, "flib");

extern(C) void fsu_(int*i);

void main(){
    int i = 1;
    fsu_(&i);
}

when compiled on my box gives

 The answer is x =   2.50000004E-02           1

If something similar doesn't work for you, can you post disassembly 
dumps of your dll function and calling function?
March 21, 2012
Re: Fortran DLL and D
Guys, thanks for advices.
After all I have proper code.

simple.d

import core.runtime;
import std.stdio;
import std.string;
import std.conv;

version(Windows)
{
    import core.sys.windows.windows;
    alias GetProcAddress GetProc;
}
else
    version(Linux) // not tested
    {
        import core.sys.linux.linux;
        alias dlsym GetProc;
    }

alias extern(C) void function (double *, int) func_One;
alias extern(C) void function (double *, int, ref int) func_Two;

void main(string[] args)
{
    if (args.count != 2)
        return;

    size_t size = parse!int(args[1]);

    writeln("Accept: ", size);

    double[] arr = new double[size];

    auto dllfile = "simple.dll";

    void * lib = Runtime.loadLibrary(dllfile);

    if (!lib)
    {
        writeln("Lib!");
        return;
    }

    func_One f_One = cast(func_One) GetProc(lib, 
"fOne".toStringz);
    if (f_One is null)
    {
        writeln("f_One!");
        return;
    }

    func_Two f_Two = cast(func_Two) GetProc(lib, 
"fTwo".toStringz);
    if (f_Two is null)
    {
        writeln("f_Two!");
        return;
    }

    f_One(arr.ptr, arr.length);

    writeln("array size: ", arr.length);

    for(int k = 0; k < arr.length; k++)
    {
        writeln(k + 1, '\t', arr[k]);
    }

    int ans = 0;
    f_Two(arr.ptr, arr.length, ans);

    writeln("fTwo = ", ans);

    Runtime.unloadLibrary(lib);
}

simple.f95 compiled with gfortran -shared -O3 -o simple.dll 
simple.f95

subroutine fOne(a, i) bind(C, name = "fOne")
    integer*4, value, intent(in) :: i
    real*8, dimension(i), intent(out) :: a
    print *, 'entry fortran dll'
    print *, 'size', i
    do j = 1, i
        a(j) = j * j;
        print *, j
    end do
    print *, 'exit fortran dll'
end

subroutine fTwo(a, i, ans) bind(C, name = "fTwo")
    integer*4, value, intent(in) :: i
    real*8, dimension(i), intent(in) :: a
    integer*4, intent(out) :: ans
    print *, 'entry fortran dll'
    print *, 'size', i
    if (a(1) .lt. 100) then
        print *, 'inside if'
        ans = 1
        print *, 'end if'
        return
    end if
    ans = 0
    print *, 'exit fortran dll'
end
March 21, 2012
Re: Fortran DLL and D
Michael wrote:

> Guys, thanks for advices.
> After all I have proper code.

Why don't you write how to do it in the D wiki?

Bye,
bearophile
« First   ‹ Prev
1 2
Top | Discussion index | About this forum | D home