Неопределенная ссылка на 'd1mach_'

Я пытаюсь связать подпрограмму фортрана с C++, но не могу понять, что именно здесь не так: подпрограмма фортрана вызывает некоторые функции, например. d1mach или xermsg, которые не определены в подпрограмме fortran, но вызываются извне. При компиляции ошибка "неопределенная ссылка на d1mach_"(или xermsg). Я попытался связать библиотеку, которая, как мне кажется, может содержать указанные функции (кажется, в библиотеке есть файлы с именами d1mach.o и xermsg.o), но та же ошибка все еще сохраняется. Что я могу делать не так?

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

Это функция, которую я использую для вызова подпрограммы, и я не использовал никаких новых заголовков, кроме 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)

Это объявление подпрограммы fortran, которая вызывает необъявленную функцию xermsg.

Я связываю библиотеку, используя инструкцию -L /path/ lib, но безрезультатно. Подпрограмма предназначена для вычисления математической функции и является частью slatec-кодов.

Пожалуйста, дайте мне знать, какая другая информация вам может понадобиться.

1 ответ

Решение

Причина, по которой проблема сохраняется, может быть просто потому, что ваша lib3j6j9j.a не включает необходимые файлы (например, d1mach). На самом деле, мы можем скомпилировать необходимые файлы довольно напрямую, поэтому я подведу итоги процедуры ниже:

1) Скачать drc3jm.f (который вычисляет 3j-символы) и зависимости со страницы Netlib/Slatec ( здесь или здесь). Распакуйте архив, чтобы получить файлы Фортрана (*.f).

tar xvf netlibfiles.tgz

2) Удалить d1mach.f, i1mach.f, а также r1mach.f (если есть). Вместо этого загрузите их альтернативные версии из 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) Скомпилируйте все *.f файлы

gfortran testf.f90 *.f

вместе с основной программой testf.f90 (в свободном формате), например,

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

Затем запуск исполняемого файла дает желаемый результат.


3-а) Мы также можем сделать их *.f в виде библиотеки и связать их с кодами C++, например, следующим образом:

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

с основной программой (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;
}

Мы можем видеть, что две программы дают одинаковый коэффициент (-0.019081579799192) для

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

Вы также можете получить тот же результат с онлайн-инструментом, например, здесь.


Но в зависимости от случаев может быть проще использовать другие библиотеки. Один из подходов заключается в использовании соответствующих подпрограмм GSL ( здесь) в качестве

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

Здесь вам нужно связать необходимые библиотеки GSL (например, g++ test.cpp -lgsl или же g++ test.cpp /usr/lib64/libgsl.so.0 /usr/lib64/libgslcblas.so.0 так далее).


Еще один подход заключается в использовании новейшей программы WIGXJPF (соответствующий документ здесь). Я попробовал это немного, и это кажется чрезвычайно простым в установке (только один make) и использовать. Например, введите example/ каталог и попробуйте gcc -I../inc csimple.c ../lib/libwigxjpf.a, Согласно приведенному выше документу, эта программа может предложить некоторые преимущества точности и производительности.


(*) Для получения более подробной информации, пожалуйста, посетите страницу Netlib / FAQ (спасибо @VladimirF в комментарии). Мы могли бы использовать исходный файл d1mach.f и т. Д. В Slatec, но нам нужно изменить их, чтобы получить правильные машинно-зависимые константы. Вышеуказанные версии d1mach.f BLAS и т. Д. Обрабатывают это автоматически, что делает их более удобными.

Другие вопросы по тегам