Je veux appeler un sous-programme Fortran à partir de C # en utilisant des commandes entrées dans la console. J'essaie depuis deux jours maintenant, en lisant de nombreuses pages Web et en suivant de nombreux conseils, mais sans succès.
Voici un exemple typique de mes nombreuses tentatives infructueuses.
Utilisation d'un éditeur de texte ( Bloc-notes) Je crée ce fichier appelé "fdll.f90"
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); }
Sur la console MS-DOS (CMD.EXE), je tape la commande suivante et appuie sur "Entrée":
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
Deux nouveaux fichiers apparaissent, nommés "fdll.dll" et "fdll.mod".
En utilisant l'éditeur de texte Monodevelop C #, je crée le suivant le fichier source C # appelé "DLLImport.cs"
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)
Sur la console, j'entre la commande suivante:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /t:exe /out:go.exe DLLImport.cs
Un nouveau fichier apparaît appelé "go.exe". Je tape "go".
Le résultat est une fenêtre contextuelle m'indiquant que "go.exe a cessé de fonctionner". Cela me donne la possibilité de fermer le programme. Sur la console MS-DOS, le message suivant est apparu:
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); }
Qu'ai-je fait de mal? Comment puis-je faire fonctionner cela?
J'utilise un ordinateur portable SONY 64 bits sous Windows 8.1. J'utilise la dernière version de gfortran (i686-w64-mingw32).
MISE À JOUR: J'ai modifié le code source de Fortran pour permettre ISO_C_BINDING (suite à la suggestion de Pierre). La nouvelle version est:
C:\Compilers\fortran\mingw32\bin\gfortran.exe -shared -o fdll.dll fdll.f90
J'ai également modifié le code source C # pour lui faire envoyer la chaîne de caractères dans Fortran sous forme de tableau (comme expliqué ici: http://www.luckingtechnotes.com/calling-fortran-dll-from-csharp/ a >). Le nouveau code C # est:
module fdll implicit none contains subroutine testFDLL(char) character(12) :: char write(6,*)" Hello FORTRAN : let us do something ...",char return end end module
Je n'ai apporté aucune modification aux arguments de ligne de commande exécutant les compilateurs; ni compile, ni gfortan ni csc, ne se sont plaints de l'un de ces changements.
RÉSULTAT: lorsque j'exécute le programme (entrez "go"), le même message d'erreur apparaît.
Quelqu'un peut expliquez ce qui ne va pas ou ce qui manque avec ce que j'ai fait. Est-ce vraiment difficile de faire en sorte que C # envoie une chaîne de caractères dans un sous-programme Fortran?
3 Réponses :
J'essaie juste de montrer comment interfacer ce code FORTRAN avec C, cela ne répond pas complètement à votre question, mais si vous savez comment interfacer C (prétendre le FORTRAN comme C) avec C #, cela devrait aider.
Hello FORTRAN : let us do something ...Hello from C, again, using dynamic dlopen()
Et le code C appelant le sous-programme FORTRAN.
gfortran -o libxf90.so -shared -fPIC x.f90 gcc -o yout y.c ./libxf90.so gcc -o zout z.c -ldl
Vous pouvez faire semblant que votre sous-programme FORTRAN est une fonction C et appeler depuis C # comme d'habitude. Le code de test C donne:
//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; }
Vous pouvez également établir un lien implicite avec la bibliothèque dynamique comme suit (notez, ignorez tout contrôle d'erreur et fermez les ressources pour un exemple plus court).
Hello FORTRAN : let us do something ...Hello from C
La commande pour les compiler (sous Linux) est
//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; }
La sortie du 2ème programme est comme: p>
!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
Merci. J'ai changé mon code FORTRAN pour qu'il soit identique au vôtre, mais le message d'erreur demeure. Votre code C est intéressant. Je ne vois pas comment modifier mon code C # pour le refléter. Des idées?
Vous devez identifier le problème FORTRAN, le problème C #, le problème d'interface ou le problème d'environnement d'exécution. Je suppose que vous savez comment appeler la bibliothèque de dll C à partir de C #, car je ne connais pas C #. Vous pouvez essayer d'utiliser C comme intermédiaire, appelez d'abord C dll à partir de C # pour éliminer les problèmes possibles qui ne sont pas liés à FORTRAN. Mon exemple est juste la partie liée à FORTRAN. Essayez d'abord d'isoler les problèmes.
Comment avez-vous compilé votre code FORTRAN? Pouvez-vous me donner la syntaxe exacte de la ligne de commande de votre console.
Je viens de le compiler comme gfortran -c x.f90 pour tester le code. Cela peut ne pas être utile car vous souhaitez le compiler dans une bibliothèque de liens dynamiques. Comme je l'ai dit, l'exemple montre simplement l'interopérabilité FORTRAIN et C, votre problème exact peut être sur une autre partie de la chaîne.
La définition C # est incorrecte. Cela devrait être
public static extern void __MOD_fdll_testFDLL(byte[] Plea);
voir comment appeler une fonction Fortran90 incluse dans un module en code c ++?
Vous pouvez utiliser nm, si vous l'avez, ou le le navigateur de dépendances pour savoir quels sont les symboles exportés.
Notez que C # char est de 2 octets, Fortran char est de 1 octet et la façon dont les tableaux sont stockés est différente à la fois en Fortran et C #.
S'il ne s'agit que d'un test d'interopérabilité, essayez d'abord de travailler uniquement avec des entiers et assurez-vous que cela fonctionne. Passez ensuite à un seul caractère (octet), puis aux tableaux. Ne passez pas aux tableaux lors de votre première tentative.
i686-w64-mingw32 signifie que vous devez compiler C # avec x86 (pas AnyCPU)
Avez-vous lu les fonctionnalités
iso_c_binding
de Fortran?Merci. Si vous pouvez me montrer où cela entre dans mon code source ou dans mes commandes, je l'apprécierais.
iso_c_binding
est un ensemble de fonctionnalités, y compris des spécificateurs qui organisent une convention d'appel de style C (ABI) entre Fortran et C (pas C #, vous devez considérer le code comme C). C'est un sujet bien connu, il est donc de votre devoir au moins de l'essayer et de publier votre code adapté ici avant que quiconque ne fournisse une aide supplémentaire.Sûr. Je vais essayer. Dans toutes mes recherches sur ce sujet (interopérabilité de C # et FORTRAN) il n'y a pas eu de mention de "iso_c_binding". Mais je vais l'examiner.
Fortran n'a pas de capacité directe "C #". Vous devez le considérer comme une interface C.
Je ne sais pas si cela aidera en essayant d'ajouter un -fPIC à la ligne de compilation gfortran