undefined reference to 'd1mach_'

荒凉一梦 提交于 2020-01-11 11:38:48

问题


I'm trying to link a fortran subroutine with c++, but can't quite figure out what exactly is wrong here: The fortran subroutine calls some functions eg. d1mach or xermsg, which aren't defined in the fortran subroutine but called externally. When compiling, the error is "undefined reference to d1mach_"(or xermsg). I tried linking a library I think might contain the said functions (There seems to be a file called d1mach.o and xermsg.o inside the library) but the same error still persists. What might I be doing wrong?

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

This is the function I use to call the subroutine, and haven't used any new headers beside 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)

This is the declaration of the fortran subroutine which calls the undeclared function xermsg.

I link the library using the -L/path/lib instruction but to no avail. The subroutine is to calculate a mathematical function and is part of the slatec codes.

Please let me know what other information you might need.


回答1:


The reason why the problem persists might be simply because your lib3j6j9j.a does not include necessary files (such as d1mach). Actually, we can compile necessary files rather directly, so I will summarize the procedure below:

1) Download drc3jm.f (which calculates 3j-symbols) and dependencies from the Netlib/Slatec page (here or here). Unpack the archive file to get Fortran files (*.f).

tar xvf netlibfiles.tgz

2) Remove d1mach.f, i1mach.f, and r1mach.f (if any). Instead, download their alternative versions from 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) Compile all *.f files

gfortran testf.f90 *.f

together with a main program testf.f90 (in free-format), e.g.,

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

Then running the executable gives the desired result.


3-a) We can also make these *.f as a library and link with C++ codes, e.g., as follows:

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

with a main program (testc.cpp)

#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;
}

We can see that the two programs give the same coefficient (-0.019081579799192) for

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

You can also get the same result with an online tool, e.g., here.


But depending on cases, it may be simpler to use other libraries. One approach is to use the corresponding GSL routines (here) as

#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;
}

Here you need to link necessary GSL libraries (e.g., g++ test.cpp -lgsl or g++ test.cpp /usr/lib64/libgsl.so.0 /usr/lib64/libgslcblas.so.0 etc).


Yet another approach is to use a latest program WIGXJPF (the related paper is here). I tried this a bit and it seems extremely easy to install (only one make) and use. For example, enter the example/ directory and try gcc -I../inc csimple.c ../lib/libwigxjpf.a. According to the above paper, this program may offer some accuracy and performance advantage.


(*) For more details, please see the Netlib/FAQ page (thanks to @VladimirF in the comment). We could utilize the original d1mach.f etc in Slatec, but we need to modify them so as to obtain correct machine-dependent constants. The above BLAS versions of d1mach.f etc handle this automatically, so they are more convenient.



来源:https://stackoverflow.com/questions/37601714/undefined-reference-to-d1mach

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!