0

我正在尝试将一个非常简单的 C++ 函数链接到一个非常简单的 Intel Visual Fortran 程序。

Fortran 程序在一个名为 VFTestBed.f90 的文件中如下所示):

 program VFTestBed

 integer pInteger

 pInteger = 11

 call SimpleTest1( pInteger )

 end program

Fortran 接口块如下所示(在名为 interfaces.f90 的文件中):

MODULE INTERFACES

interface

subroutine SimpleTest1( pInteger) 

!DEC$ATTRIBUTES DECORATE, ALIAS: "SimpleTest1"

integer pInteger

end subroutine SimpleTest1

end interface

END MODULE

C++ 函数如下所示(在名为 cppresponder.cpp 的文件中):

#include <windows.h>
#include <sstream>

void SimpleTest1(int pInteger);

void SimpleTest1(  int pInteger)

{

      std::string pString = "";
      std::string pTitle = "";

      std::string pName = "SimpleTest1\0";

   pString = "Integer was entered.";
   pTitle = "In Routine: " + pName;

   MessageBoxA(NULL, pString.c_str(), pTitle.c_str(), MB_OK |    MB_ICONINFORMATION);

}        

我在谷歌上研究了这个问题,并尝试了各种设置、声明、装饰等的几十种排列和组合,但都无济于事。事实上,许多帖子都很长而且相当复杂,而且往往似乎没有得出一个成功的结论。

除其他外,我尝试过:

  1. 使 C++ 代码成为 .LIB
  2. 使 C++ 代码成为 .DLL
  3. 使用各种形式的 !DEC$ATTRIBUTES DECORATE, ALIAS: "SimpleTest1"
  4. 使用 BIND(C, ...)
  5. 使用普通别名
  6. 使用修饰别名
  7. 使用 DUMPBIN 查看 .DLL 中的符号
  8. 使用前导外部“C”
  9. 编译为 C 代码(禁用所有 C++ 结构)

还有很多其他的东西。我已经尝试了所有应该对其他海报有用的东西,但绝对没有运气。

无论我做什么,我都会收到一条链接器错误消息 LNK2019,关于函数 _MAIN__ 中引用的未解析的外部符号 _SIMPLETEST1

根据英特尔网站,我在 CppResponder.DLL 中添加了,就像在源文件中添加一样。

如果重要的话,我正在使用适用于 Windows 的 Visual Studio Enterprise 2017 和 Intel Parallel Studio XE 2016 Update 4 composer Edition,它们都在 64 位 Windows 8.1 机器上运行。

假设 Intel Fortran 确实可以调用 C++ 函数(我假设它可以),那么我一定是在某处缺少开关或设置。我已经使用 Visual Studio 提供的默认值设置了 Fortran 和 C++ 项目。两个项目都设置为 Release | x86。

当然,这真的不是那么难的事情。我在这上面花了大约 12 个小时,但没有什么可展示的。我在 Fortran 方面拥有数十年的经验,但对 C++ 还是很陌生。

有没有人这样做过,并愿意带我了解你是如何做到的?

提前致谢,

鲍勃·基泽

4

2 回答 2

0

cppresponder.cpp

#include <iostream>

extern "C" void simpletest_(int* i){
    std::cout << "cpp " << *i << '\n';
}

VFTestBed.cpp

 program VFTestBed

 integer pInteger

 pInteger = 11

 call simpletest(pInteger)

 end program

汇编:

g++ -c cppresponder.cpp; gfortran -c VFTestBed.f90; gfortran -o test.o cppresponder.o VFTestBed.o -l stdc++

执行:

./test.o

输出

>cpp 11

您可能还需要这些编译器开关

 g++ -c -Wpadded -Wpacked -malign-double -mpreferred-stack-boundary=8 cppresponder.cpp; gfortran -c -malign-double VFTestBed.f90
于 2017-08-02T04:12:33.293 回答
0

我感谢上面的响应者。我尝试了他们的建议,但没有得到任何结果。

但是在经历了更多的悲伤之后,我确实找到了一些有用的东西。

Fortran:

program VFTestBed

use INTERFACES

integer pInteger

pInteger = 11

call SimpleTest1( pInteger )

end program



MODULE INTERFACES

interface

subroutine SimpleTest1( pInteger)

!DEC$ ATTRIBUTES  ALIAS:'?SimpleTest1@@YGXPAH@Z' :: SimpleTest1

integer pInteger

end subroutine SimpleTest1

end interface

END MODULE

在 C++ 方面:

#define WIN32_DEFAULT_LIBS
#include <windows.h>
#include <iostream>
#include <sstream>


__declspec(dllexport) void SimpleTest1(int* pInteger);

void SimpleTest1(int* pInteger)

{

    std::string pString = "";
    std::string pTitle = "";

    std::string pName = "SimpleTest1\0";

    pString = "Integer entered = " + std::to_string(*pInteger);
    pTitle = "In Routine: " + pName;

    MessageBoxA(NULL, pString.c_str(), pTitle.c_str(), MB_OK |    MB_ICONINFORMATION);


}

显着变化:

  1. 添加了 __declspec(dllexport)
  2. 将 int 更改为 int*
  3. 添加了#define WIN32_DEFAULT_LIBS
  4. 从 .DLL 更改为 .LIB
  5. 使用 DUMPBIN 找出 C++ 名称装饰
  6. 在主程序中添加了 USE INTERFACES
  7. 在界面中添加:!DEC$ ATTRIBUTES ALIAS:'?SimpleTest1@@YGXPAH@Z'::SimpleTest1

因此,所有这一切只需要不到 30 行代码即可编译、链接和运行!嘘!

我生命中的 15 个多小时,我永远不会回来。

无论如何,它已经解决了,我希望我已经从我所经历的所有悲伤中拯救了一些未来的读者。我希望某个地方的某个人觉得这很有用。

于 2017-08-04T02:58:32.890 回答