我想调用一个函数,该函数既在 C++ 父类“inval”中,又在 Fortran 77 的 C++ 派生类“SMval”中。我要调用的函数包含在我想要接口的更大代码中到我的 Fortran。我写了以下代码(3个文件)
在library_wrapper.h中:
#include "classes.h"
#include "SMval.h"
#ifdef __cplusplus
//Forward declarations of classes
class inval;
class SMval;
extern "C" {
#endif
void* createinval_();
void destroyinval_(void* instance);
void* createSMval_();
void destroySMval_(void* instance);
void invalsetWrapper_(const int idx, const double val);
void SMvalsetWrapper_(const int idx, const double val); // Declaration of the wrapper function
#ifdef __cplusplus }
#endif
在库wrapper.cpp中:
#include "library_wrapper.h"
#include "classes.h"
#include "SMval.h"
#include "Cplx.h"
#include <iostream>
#include <string.h>
extern "C" {
void* createinval_() {
return new inval();
}
void* createSMval_() {
return new SMval();
}
void destroyinval_(void* instance) {
delete static_cast<inval*>(instance);
}
void destroySMval_(void* instance) {
delete static_cast<SMval*>(instance);
}
void invalsetWrapper_(const int idx, const double val) {
inval obj;
return obj.set(idx, val);
}
void SMvalsetWrapper_(const int idx, const double val) {
SMval obj;
return obj.set(idx, val);
}
}
最后是主要的 Fortran 77:
PROGRAM main
implicit none
CALL CREATEINVAL()
CALL CREATESMVAL()
CALL INVALSETWRAPPER(12, 1/137.03599976)
CALL SMVALSETWRAPPER(1, 91.1876)
END
我正在 MAC Sonoma 上编译:
clang++ -g -std=c++11 -c library_wrapper.cpp
ld -r allothersobjectfiles.o library_wrapper.o -o combined_library.o
clang++ -shared -o liblibrary.a combined_library.o
gfortran -ffixed-line-length-none fortran.f -o main -L. -llibrary
但是我明白了
ld: Undefined symbols:
_createinval_, referenced from:
_MAIN__ in ccPLQP9I.o
_createsmval_, referenced from:
_MAIN__ in ccPLQP9I.o
_invalsetwrapper_, referenced from:
_MAIN__ in ccPLQP9I.o
_smvalsetwrapper_, referenced from:
_MAIN__ in ccPLQP9I.o
collect2: error: ld returned 1 exit status
我尝试创建一个静态库并链接它,但它仍然不起作用
要尽可能正确地做到这一点,您应该使用 Fortran 的 C/Fortran 互操作性功能,基于 iso_c_binding Fortran 模块
例如,要调用
invalsetWrapper_
函数,您的 Fortran 代码应如下所示:
program main
use iso_c_binding
implicit none
interface
subroutine inval_set_wrapper(idx,val) bind(C,name="invalsetWrapper_")
integer(kind=c_int), value :: idx
real(kind=c_double), value :: val
end subroutine
end interface
...
call inval_set_wrapper(12, 1/137.03599976d0)
end
请注意,互操作性假设使用成对的编译器(即,您应该将
gcc
与 gfortran
一起使用),即使它在缺少编译器时通常可以工作。