2016-06-02 23 views
1

Ich versuche, eine Fortran-Unterroutine mit C++ zu verknüpfen, kann aber nicht ganz herausfinden, was genau hier falsch ist: Das Fortran-Unterprogramm ruft einige Funktionen auf. d1mach oder xermsg, die nicht im Fortran-Unterprogramm definiert, sondern extern aufgerufen werden. Beim Kompilieren ist der Fehler "undefinierter Verweis auf d1mach _" (oder xermsg). Ich habe versucht, eine Bibliothek zu verbinden, von der ich glaube, dass sie die genannten Funktionen enthält (Es scheint eine Datei mit dem Namen d1mach.o und xermsg.o in der Bibliothek zu geben), aber derselbe Fehler bleibt bestehen. Was könnte ich falsch machen?undefined Verweis auf 'd1mach_'

extern"C" { 
void drc3jm_(double *L1,double *L2,double *L3,double *M1,double *M2MIN, 
    double *M2MAX,double *THRCOF,int *NDIM,int *IER); 
} 

Dies ist die Funktion, die ich verwenden, um die Unterroutine aufzurufen, und haben keine neuen Header neben Iostream

*DECK DRC3JM 
     SUBROUTINE DRC3JM (L1, L2, L3, M1, M2MIN, M2MAX, THRCOF, NDIM, 
    + IER) 
CALL XERMSG('SLATEC','DRC3JM','L1-ABS(M1) less than zero or '// 
    +  'L1+ABS(M1) not integer.',IER,1) 

Dies ist die Erklärung des Fortran-Unterprogramm nicht verwendet, die die nicht angemeldete Funktion xermsg nennt.

Ich verknüpfe die Bibliothek mit dem -L/Pfad/lib Anweisung, aber ohne Erfolg. Das Unterprogramm soll eine mathematische Funktion berechnen und ist Teil der Schiefer-Codes.

Bitte lassen Sie mich wissen, welche anderen Informationen Sie benötigen könnten.

+0

Sie müssen mit der Fortran-Laufzeitbibliothek verlinken. Versuchen Sie -lgfortran zu Ihrem Link-Befehl hinzuzufügen – antlersoft

+0

@antlersoft Ich habe das schon gemacht, ich habe .o-Dateien für beide Dateien, dann kompiliert sie mit den Anweisungen -lgfortran und -L. Dies führt zu diesem Fehler mit oder ohne den Befehl -L. – pyroscepter

+0

Können Sie die vollständigen Befehlszeilen freigeben, die Sie zum Kompilieren und Verknüpfen verwenden? – Smeeheey

Antwort

2

Der Grund, warum das Problem weiterhin besteht, könnte einfach darin liegen, dass Ihre lib3j6j9j.a keine notwendigen Dateien (wie d1mach) enthält. Eigentlich können wir benötigte Dateien kompilieren und nicht direkt, also werde ich das Verfahren unten zusammenfassen:

1) Download drc3jm.f (die 3J-Symbole) und Abhängigkeiten von der Netlib/Slatec Seite (here oder here) berechnet. Entpacken Sie die Archivdatei, um Fortran-Dateien (* .f) zu erhalten.

tar xvf netlibfiles.tgz 

2) entfernen d1mach.f, i1mach.f und r1mach.f (falls vorhanden). Stattdessen herunterladen, um ihre alternativen Versionen von Netlib/blas (*):

rm -f i1mach.f r1mach.f d1mach.f 
wget http://www.netlib.org/blas/i1mach.f 
wget http://www.netlib.org/blas/r1mach.f 
wget http://www.netlib.org/blas/d1mach.f 

3) Kompilieren aller * .f Dateien

gfortran testf.f90 *.f 

zusammen mit einem Hauptprogramm testf.f90 (im freien Format) B.

program main 
implicit none 
integer, parameter :: N = 1000 
double precision coef(N), M2min, M2max, M2 
integer ier 
ier = 0 ; coef(:) = 0.0d0 

call DRC3JM(15.0d0, 30.0d0, 40.d0, 2.0d0, M2min, M2max, coef, N, ier) 
print *, "M2min, M2max, ier = ", M2min, M2max, ier 

M2 = 2.0d0 
print "(a, f20.15)", "coef = ", coef(nint(M2 - M2min+1)) !! -0.019081579799192 
end 

Dann führt das Ausführen der ausführbaren Datei das gewünschte Ergebnis.


3-a) Wir können auch dieses * .f als Bibliothek und einen Link mit C++ Codes machen, beispielsweise wie folgt:

gfortran -c *.f 
ar rv mylib.a *.o 
g++ testc.cpp mylib.a -lgfortran 

mit einem Hauptprogramm (testc.cpp)

sehen
#include <cstdio> 
extern "C" 
double drc3jm_ (double*, double*, double*, 
       double*, double*, double*, double*, int*, int*); 

int main() 
{ 
    double* coef; 
    double L1, L2, L3, M1, M2min, M2max, M2; 
    int ier, k, N = 1000; 

    coef = new double [ N ]; 
    L1 = 15.0; L2 = 30.0; L3 = 40.0; M1 = 2.0; 

    drc3jm_ (&L1, &L2, &L3, 
       &M1, &M2min, &M2max, coef, &N, &ier); 
    printf("M2min, M2max, ierr = %10.5f%10.5f%d\n", M2min, M2max, ier); 

    M2 = 2.0; 
    k = (int)(M2 - M2min + 1.0e-3); 
    printf("coef = %20.15f\n", coef[ k ]); // -0.019081579799192 
    return 0; 
} 

Wir, dass die beiden Programme den gleichen Koeffizienten geben (-,019081579799192) für

j1=15, j2=30, j3=40, m1=2, m2=2, m3=-4 

Sie können dasselbe Ergebnis auch mit einem Online-Tool erhalten, z. B. here.


Aber je nach Fällen kann es einfacher sein, andere Bibliotheken zu verwenden. Ein Ansatz ist es, die entsprechenden GSL-Routinen zu verwenden (here) als

#include <cstdio> 
extern "C" 
double gsl_sf_coupling_3j (int two_ja, int two_jb, int two_jc, 
          int two_ma, int two_mb, int two_mc); 
int main() 
{ 
    double coef; 
    coef = gsl_sf_coupling_3j(30, 60, 80, 4, 4, -8); // -0.019081579799205 
    // NOTE: all j's and m's need to be doubled. 

    printf("coef = %20.15f\n", coef); 
    return 0; 
} 

Hier müssen Sie die notwendigen GSL-Bibliotheken (zum Beispiel g++ test.cpp -lgsl oder g++ test.cpp /usr/lib64/libgsl.so.0 /usr/lib64/libgslcblas.so.0 usw.) verknüpfen.


Ein weiterer Ansatz ist es, ein aktuelles Programm WIGXJPF (das zugehörige Papier ist here) zu verwenden. Ich habe es ein wenig versucht und es scheint extrem einfach zu installieren (nur ein make) und zu verwenden. Geben Sie beispielsweise das Verzeichnis example/ ein und versuchen Sie gcc -I../inc csimple.c ../lib/libwigxjpf.a. Gemäß dem oben genannten Papier kann dieses Programm einige Genauigkeit und Leistungsvorteile bieten.


(*) Für weitere Informationen wenden Sie sich bitte the Netlib/FAQ page (dank @VladimirF im Kommentar) sehen. Wir könnten das ursprüngliche d1mach.f usw. in Slatec verwenden, aber wir müssen sie modifizieren, um korrekte maschinenabhängige Konstanten zu erhalten. Die obigen BLAS-Versionen von d1mach.f usw. behandeln dies automatisch, so dass sie bequemer sind.

+0

Wow das war unglaublich detailliert! Ich hatte die Hoffnung fast aufgegeben. Vielen Dank @roygvib! Ich habe den 2. Schritt noch nicht erreicht, aber es scheint, als wäre es eine Lösung für die - Nan Werte, die ich bekomme. Wird am Morgen bezüglich des Fortschritts aktualisiert. – pyroscepter

+0

Das funktioniert perfekt! Der zweite Ansatz ist genau das, was ich wollte (Der mit C++ linking. Ohne die alternativen Versionen des d1mach usw. herunterzuladen, war das Problem, dass es mir -nan als Ergebnis gab. Das Herunterladen der alternativen Versionen scheint das behoben zu haben.) . Vielen Dank für die Bereitstellung einer sehr aufwendigen und idiotensicheren Antwort! – pyroscepter

+0

Eigentlich war dies das erste Mal, dass ich die BLAS-Version von d1mach.f usw. benutzte, was sich als sehr nützlich erwies. (Weil ich es nicht wusste, musste ich sie manuell ändern, um etwas AMOS-Code auszuführen, siehe [http://stackoverflow.com/questions/34082554/how-to-call-fortran-routines- from -c/34094408 # 34094408) ... so aktualisiert es.) Wie für NaN, ich denke, es ist, weil die alte Version von d1mach.f gibt 0.0 als "großen" Wert (es sei denn, wir kommentieren unnötige Zeilen). Gut zu wissen, dass es eine einfache Lösung gibt :) Prost – roygvib