C++ 使用c+创建.lib文件+;和Fortran/callc++;来自Fortran的代码/未解析的外部符号
我试图创建一个包含C++函数的fortran函数的.LB库文件,但是我得到了可怕的“错误LNK2019:未解析的外部符号……”。该代码最终将与其他库一起编译为DLL,并在单独的程序(PSSE)中使用。当PSSE试图使用我的库创建DLL时,我遇到编译错误。下面是我试图使用的代码,后面是编译代码。代码只需将两个数字相加并输出答案 福特代码C++ 使用c+创建.lib文件+;和Fortran/callc++;来自Fortran的代码/未解析的外部符号,c++,fortran,object-files,psse,C++,Fortran,Object Files,Psse,我试图创建一个包含C++函数的fortran函数的.LB库文件,但是我得到了可怕的“错误LNK2019:未解析的外部符号……”。该代码最终将与其他库一起编译为DLL,并在单独的程序(PSSE)中使用。当PSSE试图使用我的库创建DLL时,我遇到编译错误。下面是我试图使用的代码,后面是编译代码。代码只需将两个数字相加并输出答案 福特代码 SUBROUTINE TESTCPP ( II, JJ, KK, LL ) INCLUDE 'COMON4.INS' integer*4, exte
SUBROUTINE TESTCPP ( II, JJ, KK, LL )
INCLUDE 'COMON4.INS'
integer*4, external :: CPPFUNCTION
INTEGER a, b, c, test
IF (.NOT. IFLAG) RETURN
a = ICON(II)
b = ICON(II + 1)
test = CPPFUNCTION( a , b, c )
WRITE ( ITERM, * ) 'C = ', c
RETURN
END
cpp_代码.cpp
extern "C" {
void _CPPFUNCTION(int a, int b, int *c);
}
void _CPPFUNCTION(int a, int b, int *c) {
*c = a + b;
}
编译.bat
cl /nologo /MD /c /W3 /O2 /FD /EHsc /errorReport:prompt /D"MSWINDOWS" /D"WIN32" ^
/D"_WINDOWS" /D"NDEBUG" "cpp_code.cpp"
IFORT /nologo /Od /Oy- /assume:buffered_io /traceback /libs:dll /threads /c /Qip ^
/extend_source:132 /noaltparam /fpscomp:logicals /warn:nodeclarations ^
/warn:unused /warn:truncated_source /Qauto /Op /iface:cvf /define:DLLI ^
/include:"C:\Program Files (x86)\PTI\PSSE32\PSSLIB" ^
/object:"fort_code.OBJ" ^
"fort_code.f"
lib /out:fort_cpp.lib fort_code.obj cpp_code.obj
当PSSE程序尝试创建DLL时,我得到的输出是:
ifort /nologo /assume:buffered_io /traceback /libs:dll /threads /c /Qip /extend_source:132 /noaltparam /fpscomp:logicals /Qprec /warn:declarations /warn:unused /warn:truncated_source /Qauto /fp:source /iface:cvf /define:DLLI /include:"C:\Program Files (x86)\PTI\PSSE32\PSSLIB" /object:"C:\temp\INIT_620289\11hw2ap_conec.obj" /module:"C:\temp\INIT_620289" "11hw2ap_conec.f"
ifort /nologo /assume:buffered_io /traceback /libs:dll /threads /c /Qip /extend_source:132 /noaltparam /fpscomp:logicals /Qprec /warn:declarations /warn:unused /warn:truncated_source /Qauto /fp:source /iface:cvf /define:DLLI /include:"C:\Program Files (x86)\PTI\PSSE32\PSSLIB" /object:"C:\temp\INIT_620289\11hw2ap_conet.obj" /module:"C:\temp\INIT_620289" "11hw2ap_conet.f"
link /INCREMENTAL:NO /NOLOGO /DLL /SUBSYSTEM:WINDOWS /MACHINE:X86 /ERRORREPORT:PROMPT @"C:\temp\INIT_620289\linkfilestod9p1.txt" /OUT:"C:\temp\INIT_620289\11hw2ap_dsusr.dll" /map:"C:\temp\INIT_620289\11hw2ap_dsusr.map"
fort_cpp.lib(fort_code.obj) : error LNK2019: unresolved external symbol _CPPFUNCTION@12 referenced in function _TESTCPP
C:\temp\INIT_620289\11hw2ap_dsusr.dll : fatal error LNK1120: 1 unresolved externals
ERROR during link(1)... Aborted
conec/conet只是对外部库函数的Fortran调用:
SUBROUTINE CONEC
C
INCLUDE 'COMON4.INS'
C
CALL TESTCPP ( 55791, 0, 0, 0)
C
RETURN
END
SUBROUTINE CONET
C
INCLUDE 'COMON4.INS'
C
IF (.NOT. IFLAG) GO TO 9000
C
C NETWORK MONITORING MODELS
C
C
9000 CONTINUE
C
RETURN
END
我见过几个不同的例子,从Fortran调用C++函数,但它们看起来稍微不同。在C++函数名称之前或之后,我注意到了<<代码> <代码>的不同用法。我如何知道使用哪一个:
\cppufunction
、cppufunction
或cppufunction
。我需要用C++来使用C++代码吗?我是否需要在Fortran代码中创建一个别名:“\cppu function”
我正在使用以下编译器:
ifort:IVF IA-32 v12.1.0.233
cl:v16.00.30319.01 x86
<> P>是否有什么东西可以将C++代码正确地链接到FORTRAN函数?< P>问题是有很多选择。无、前后有一个或两个下划线、变量后或列表末尾的字符串长度、按值调用或按引用调用。大写、小写或原始命名。只有这些选项,正确的概率已经低于百分之一(1/3*1/3*1/2*1/2*1/3) 通过使用该实用程序内省.lib文件,并手动检查“英特尔fortran默认设置”和项目文件中的设置,可以稍微减少该值 正如一些人建议的那样,最优雅的方法是使用
bind(C)
和module的组合。bind(C)
语句避免了知道名称mangling。iso_c_绑定
提供和integer(c_int)
而不是integer*4
,以确保您的类型与c的兼容性。您必须知道fortran在默认情况下按引用调用,您可以使用,value
按值调用。这会将你的成功率一直提高到1
这里是一个简单的例子,如何调用C++中定义的ADD1函数:
测试.f90 program example
use iso_c_binding
implicit none
interface
integer(c_int) function add1(x) bind(C,name="add1")
!DEC$ ATTRIBUTES DLLEXPORT :: add1
use iso_c_binding
integer(c_int), value :: x
end function add1
end interface
call callingadd1()
contains
subroutine callingadd1()
write(*,*) '1+1=', add1(1)
end subroutine callingadd1
end program example
subroutine callingadd1() bind(C, name="callingadd1")
!DEC$ ATTRIBUTES DLLEXPORT :: callingadd1
use iso_c_binding
implicit none
interface
integer(c_int) function add1(x) bind(C,name="add1")
!DEC$ ATTRIBUTES DLLEXPORT :: add1
use iso_c_binding
integer(c_int), value :: x
end function add1
end interface
write(*,*) '1+1=', add1(1)
end subroutine callingadd1
add1.cpp
extern "C" {
int add1(int x);
}
int add1(int x) {
return(x+1);
}
仅使用子例程编辑示例。用于包含在共享对象/dll/dylib中
子程序.f90
program example
use iso_c_binding
implicit none
interface
integer(c_int) function add1(x) bind(C,name="add1")
!DEC$ ATTRIBUTES DLLEXPORT :: add1
use iso_c_binding
integer(c_int), value :: x
end function add1
end interface
call callingadd1()
contains
subroutine callingadd1()
write(*,*) '1+1=', add1(1)
end subroutine callingadd1
end program example
subroutine callingadd1() bind(C, name="callingadd1")
!DEC$ ATTRIBUTES DLLEXPORT :: callingadd1
use iso_c_binding
implicit none
interface
integer(c_int) function add1(x) bind(C,name="add1")
!DEC$ ATTRIBUTES DLLEXPORT :: add1
use iso_c_binding
integer(c_int), value :: x
end function add1
end interface
write(*,*) '1+1=', add1(1)
end subroutine callingadd1
似乎您应该指定调用约定。cdecl或stdcall,我不知道,我只为Unix编程。最好的方法是使用Fortran 2003与C(和
iso_C_绑定模块
)的互操作性。我知道主程序是如何做到这一点的,但我很难将其与子例程一起使用。最近我用Fortran为一个Win32游戏做了一些dll,它“刚刚工作”很完美,当我使用Fortran 2003和iso_c_binding时,您的里程可能会有所不同。关于手动指定约定,我不能说任何事情。iso_c_绑定
是否可以从子例程
中完成,而不是像您建议的那样将其放入程序
中?我更新了示例以使用子例程。您也可以将接口和子例程放在一个模块中,也可以将接口放在子例程中。这个网站上Fortran答案中常见的一个术语诡辩——内部模块ISO_C_绑定是C互操作性的一部分,但与OP的问题无关。这是他需要的BIND属性——如果你从你的例子中去掉USE语句,编译器仍然会得到正确的名称。使用“iso_c_binding”作为c互操作性的同义词是不准确的,可能会让新手感到困惑。我想我的问题是,是否可以单独在子例程模块中使用它。这将最终成为一个我无法控制的程序所使用的库。所以我想知道的是,是否需要在程序级定义使用iso_c_绑定
和隐式无
,或者是否可以在子例程中进行布局。请参阅额外示例。如果将其编译到dll中,该函数应该是可调用的。