2016-06-02 5 views
1

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

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) 

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

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

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

+0

Вам необходимо установить связь с библиотекой времени исполнения Fortran. Попробуйте добавить -lgfortran к вашей команде связи – antlersoft

+0

@antlersoft. Я уже сделал это, я сделал файлы .o для обоих файлов, а затем скомпилировал их с помощью команд -lgfortran и -L. Это приводит к этой ошибке, с инструкцией -L или без нее. – pyroscepter

+0

Можете ли вы поделиться всеми командами, которые вы используете, для компиляции и ссылки? – Smeeheey

ответ

2

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

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

tar xvf netlibfiles.tgz 

2) Удалить d1mach.f, i1mach.f и r1mach.f (если таковые имеются). Вместо этого, загрузить свои альтернативные версии от Netlib/Блас (*):

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 

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


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

#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 (соответствующая бумага here). Я попробовал это немного, и кажется чрезвычайно простым в установке (только один make) и использовать. Например, введите каталог example/ и попробуйте gcc -I../inc csimple.c ../lib/libwigxjpf.a. В соответствии с вышеприведенным документом эта программа может предложить некоторую точность и производительность.


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

+0

Ничего себе это было удивительно подробно! Я почти потерял надежду. Большое спасибо @roygvib! Я еще не достиг 2-го шага, но похоже, что это решение для значений, которые я получаю. Утром будет обновляться относительно прогресса. – pyroscepter

+0

Это работает отлично! Второй подход - именно то, что я хотел (тот, у кого есть ссылка на C++). Не загружая альтернативные версии d1mach и т. Д., Проблема заключалась в том, что он дал мне -nan в качестве результата. Возможно, исправлено сравнение альтернативных версий.) , Спасибо, что предоставили очень продуманный и идиотский доказательство! – pyroscepter

+0

На самом деле, это был первый раз, когда я использовал версию BLA d1mach.f и т. Д., Которая оказалась очень полезной. (Поскольку я этого не знал, мне нужно было вручную изменить их, чтобы запустить некоторый код AMOS, см. Эту страницу [http://stackoverflow.com/questions/34082554/how-to-call-fortran-routines-from -c/34094408 # 34094408) ... так обновил его.) Что касается NaN, я думаю, это потому, что старая версия d1mach.f дает 0.0 как «огромное» значение (если мы не раскомментируем необходимые строки). В любом случае, хорошо знать, что есть простое решение :) Cheers – roygvib