Вызов подпрограммы FORTRAN из C # на консоли - PullRequest
0 голосов
/ 14 февраля 2019

Я хочу вызвать подпрограмму FORTRAN из C #, используя команды, введенные на консоли.Я пытался в течение двух дней, читал много веб-страниц и следовал многим советам, но безуспешно.

Вот типичный пример моих многочисленных неудачных попыток.

Используя текстовый редактор (Блокнот), я создаю этот файл с именем "fdll.f90"

 module fdll
implicit none
 contains

 subroutine testFDLL(char)
 character(12) :: char
    write(6,*)" Hello FORTRAN : let us do something ...",char
 return
 end
 end module

На консоли MS-DOS (CMD.EXE) я набираю следующую команду инажмите «Enter»:

 C:\Compilers\fortran\mingw32\bin\gfortran.exe -shared -o fdll.dll fdll.f90 

Появятся два новых файла с именами «fdll.dll» и «fdll.mod».

Используя текстовый редактор Monodevelop C #, я создаю следующий C #Исходный файл с именем «DLLImport.cs»

 using System;
 using System.Runtime.InteropServices;

public static class DLLImport
{       
    public static void Main(string[] args)
    {
        RunFortranDLL ();
    }

public static void RunFortranDLL()
    {
        FortranLib.testFDLL("Please work!");
    }
}

public static class FortranLib
{
    private const string dllName = "fdll.dll";
    [DllImport(dllName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]

    public static extern void testFDLL(string Plea);
}

В консоли я ввожу следующую команду:

 C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /t:exe /out:go.exe DLLImport.cs 

Появляется новый файл с именем «go.exe».Я набираю «идти».

В результате появляется всплывающее окно с сообщением «go.exe перестал работать».Это дает мне возможность закрыть программу.На консоли MS-DOS появилось следующее сообщение:

 Unhandled Exception: System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
 at Fortran.Lib.testFDLL(String Plea)
 at DLLImport.Main(String[] args)

Что я сделал не так?Как я могу заставить это работать?

Я использую 64-битный ноутбук SONY под управлением Windows 8.1.Я использую последнюю версию gfortran (i686-w64-mingw32).

ОБНОВЛЕНИЕ: я изменил исходный код FORTRAN для разрешения ISO_C_BINDING (следуя совету Пьера).Новая версия:

 module fdll
 contains
 subroutine testFDLL(char) bind(C)
     USE ISO_C_BINDING
     character (C_CHAR) :: char(20)
    write(6,*)" Hello FORTRAN : let us do something ..."
 return
 end subroutine
 end module

Я также изменил исходный код C #, чтобы он отправлял символьную строку в FORTRAN в виде массива (как описано здесь: http://www.luckingtechnotes.com/calling-fortran-dll-from-csharp/). Новый код C #:

 using System;
 using System.Runtime.InteropServices;

 public static class DLLImport
 {       
public static void Main(string[] args)
{
    RunFortranDLL ();
}

public static void RunFortranDLL()
{
    FortranLib.testFDLL(ToCharacterArrayFortran("Please work!",20));
}

public static char[] ToCharacterArrayFortran(this string source, int length)
{
    var chars = new char[length];
    int sourceLength = source.Length;
    for (int i = 0; i < length; i++)
    {
        if (i < sourceLength)
            chars[i] = source[i];
        else
            chars[i] = ' '; // Important that these are blank for Fortran compatibility.
    }

    return chars;
   }
 }

 public static class FortranLib
 {
     private const string dllName = "fdll.dll";
     [DllImport(dllName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]

public static extern void testFDLL(char[] Plea);
 }

Я не вносил изменений в аргументы командной строки, запускающие компиляторы, ни компиляция, ни gfortan, ни csc не жаловались на какие-либо из этих изменений.введите «go»), появляется то же сообщение об ошибке.

Может кто-нибудь объяснить, что не так, или нет, с тем, что я сделал. Неужели так сложно заставить C # отправить строку символов в подпрограмму FORTRAN?

Ответы [ 2 ]

0 голосов
/ 19 февраля 2019

Определение C # неверно.Это должно быть

public static extern void __MOD_fdll_testFDLL(byte[] Plea);

см. как вызвать функцию Fortran90, включенную в модуль в коде c ++?

Вы можете использовать nm, если он у вас есть, илисредство обхода зависимостей для определения экспортируемых символов.

Обратите внимание, что символ C # равен 2 байта, символ Fortran равен 1 байту и способ хранения массивов различен как в Fortran, так и в C #.

Если это всего лишь тест на совместимость, попробуйте сначала поработать только с целыми числами и убедитесь, что он работает.Затем перейдите к одному символу (байту) и затем к массивам.Не переходите к массивам с первой попытки.

0 голосов
/ 15 февраля 2019

Я просто пытаюсь показать, как связать этот код FORTRAN с C, это не полностью отвечает на ваш вопрос, но если вы знаете, как взаимодействовать с C (притвориться FORTRAN как C) с C #, это должно помочь.

!fortran code, named as x.f90
module fdll
    implicit none
contains

subroutine testFDLL(str, n) bind(c, name='testFDLL_as_C')
    use ISO_C_BINDING
    integer(c_int), value :: n
    character(kind=c_char), intent(in) :: str(n)
    write(6,*)" Hello FORTRAN : let us do something ...",str
    return
end
end module

И код C, вызывающий подпрограмму FORTRAN.

//c code explicitly link. named as y.c
#include <stdio.h>
#include <string.h>

int main()
{
    void testFDLL_as_C(char *str, int n);
    char str[] = "Hello from C";
    testFDLL_as_C(str, strlen(str));
    return 0;
}

Вы можете представить свою подпрограмму FORTRAN как функцию C и вызывать из C #, как обычно.Код теста C дает:

  Hello FORTRAN : let us do something ...Hello from C

Вы также можете неявно связываться с динамической библиотекой следующим образом (обратите внимание, игнорируйте все проверки ошибок и закрытие ресурсов для более короткого примера).

//implicit link. named as z.c
#include <stdio.h>
#include <string.h>
#include <dlfcn.h>

int main()
{
    void (*func_from_so_f90)(char *str, int n);
    char str[] = "Hello from C, again, using dynamic dlopen()";
    void *handle = dlopen("./libxf90.so", RTLD_LAZY);
    func_from_so_f90 = dlsym(handle, "testFDLL_as_C");
    func_from_so_f90(str, strlen(str));
    return 0;
}

Команда для их компиляции (в linux):

gfortran -o libxf90.so -shared -fPIC x.f90
gcc -o yout y.c ./libxf90.so
gcc -o zout z.c -ldl

Вывод 2-й программы выглядит так:

  Hello FORTRAN : let us do something ...Hello from C, again, using dynamic dlopen()
...