Jump to page: 1 2
Thread overview
Fortran DLL and D
Mar 13, 2012
Michael
Mar 13, 2012
Tobias Brandt
Mar 13, 2012
Michael
Mar 13, 2012
Tobias Brandt
Mar 13, 2012
Michael
Mar 13, 2012
Andrej Mitrovic
Mar 13, 2012
Michael
Mar 14, 2012
Ellery Newcomer
Mar 21, 2012
Michael
Mar 21, 2012
bearophile
Mar 21, 2012
Michael
March 13, 2012
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
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
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
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
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
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
Thanks, but i still get the same.


March 14, 2012
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
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
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