c++ - 使用 c++ 和 Fortran/Call c++ code from Fortran/Unresolved external symbol 创建 .lib 文件

标签 c++ fortran object-files psse

我正在尝试创建一个 .lib 库文件,其中包含调用 C++ 函数的 Fortran 函数,但我收到了可怕的“错误 LNK2019:未解析的外部符号...”。该代码最终将与一堆其他库一起编译为 DLL,并在单独的程序 (PSSE) 中使用。当 PSSE 尝试使用我的库创建 DLL 时,出现编译错误。这是我尝试使用的代码,然后是编译代码。代码应该只是将两个数字相加并输出答案。

堡垒代码.f

  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_code.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++ 函数名称之前或之后的不同用法。我怎么知道要使用哪个:_CPPFUNCTIONCPPFUNCTIONCPPFUNCTION_。我是否需要使用 __declspec( dllexport ) 在 c++ 中导出函数?我是否需要在 Fortran 代码中创建 ALIAS:'_CPPFUNCTION'

我正在使用以下编译器: ifort:IVF IA-32 v12.1.0.233 cl: v16.00.30319.01 x86

我是否缺少将 C++ 代码正确链接到 Fortran 函数的内容?

最佳答案

问题在于有很多选项。无,前后一或两个下划线,变量后或列表末尾的字符串长度,按值调用或按引用调用。大写、小写或原始命名。仅使用这些选项,正确的概率已经低于 100 分之一 (1/3*1/3*1/2*1/2*1/3)。

您可以通过使用 dumpbin 内省(introspection) .lib 文件来稍微减少它。实用程序并手动检查 intel fortran 默认设置和项目文件中的设置。

最优雅的方法,就像一些人建议的那样,是结合使用 bind(C)iso_c_binding模块。 bind(C) 语句避免了必须知道名称的混淆。 iso_c_bindings 提供了 c stringsinteger(c_int) 而不是 integer*4 以确保您的类型与 C 的兼容性。您必须知道默认情况下通过引用进行 fortran 调用,您可以使用 , value 按值调用。这应该会将您的成功率一直提高到 1。

下面是一个简单的例子,说明如何调用下面用 C++ 定义的 add1 函数:

test.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

add1.cpp

extern "C" {
  int add1(int x);
}

int add1(int x) {
  return(x+1);
}

编辑一个只有子程序的例子。包含在您的共享对象/dll/dylib 中。

subroutineonly.f90

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

关于c++ - 使用 c++ 和 Fortran/Call c++ code from Fortran/Unresolved external symbol 创建 .lib 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14590235/

相关文章:

compiler-errors - gfortran在编译文件上不输出ident工具

c++ - C++目标文件的大小取决于什么?

c++ - 如何打印字符串 C++ mfc

c++ - hash_map 和 map 哪个更快?少于 10000 件

c++ - 正则表达式 : C++ extract text within double quotes

algorithm - 如何旋转粒子系统(大小为 =num_particles*3 的二维矩阵),以便某些条目变为零

c++ - 为什么异常不适用于 OSX 上的 gcc7 和 -static-libgcc?

fortran - 使用 SOURCE= 一次分配多个变量

compiler-errors - NASM 'org'指令和 '-fobj'

c++ - 从 .o 目标文件中提取函数的原始机器代码?