从动态库加载Fortran函数:Debug vs Release

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从动态库加载Fortran函数:Debug vs Release相关的知识,希望对你有一定的参考价值。

我编写了一些代码来加载在Fortran中编译的动态库。 Fortran库中导出的函数包括导出的setter和getter。我正在尝试使用Windows API加载这些setter和getter。虽然这适用于我在调试中构建的代码。它不适用于我在发布中构建的代码。在发布时,当我尝试将1.0f传递给set()时,当我进入fortran代码时,我在调试器中看到0.0f

编辑:我忘了提到另一个观察。如果我只加载setValue()函数。我的问题完全消失了。只有当我从库中加载其他功能时,我才开始遇到我遇到的问题。

编译器

  • 英特尔Fortran 2017 Update 5
  • Visual Studio 2017 v15.5.2

调试

我已经确定当我的C ++代码在发布时编译时,我加载的set()函数会将0.0f传递给fortran函数。这是通过加载fortran库的调试版本并通过Visual Studio的调试器运行它来发现的。使用我的代码的调试版本执行相同的操作会产生正确的值传递给fortran函数。

为了弄清楚发生了什么,我尝试了以下方法:

  • 试图在我的加载器的Debug和Release版本中加载已编译的Fortran的Debug和Release二进制文件。仅适用于我的装载器的Debug构建。
  • 重建Fortran代码验证编译器标志,例如用于调试的Mutithreaded Debug DLL和用于Release的多线程DLL。
  • 执行fortran二进制文件的dumpbin以验证函数地址​​是否正确加载;他们是。

FORTRAN

    REAL FUNCTION getValue()
!DEC$ ATTRIBUTES DLLEXPORT, c:: getValue
    IMPLICIT NONE
    INCLUDE 'VALUE.CMN'

    getValue = VAL
    RETURN
      END FUNCTION getValue

    SUBROUTINE setValue(x)
!DEC$ ATTRIBUTES DLLEXPORT, c:: setValue
    IMPLICIT NONE 
    INCLUDE 'VALUE.CMN'

    REAL, INTENT(IN) :: x

    VAL = x 

      END SUBROUTINE setValue

C ++

const auto handle = reinterpret_cast<HMODULE>(LoadLibrary("fortran_value.dll"));

typedef void(*Set)(float&);
typedef float(*Get)(void);

const auto set = reinterpret_cast<Set>(GetProcAddress(handle, "setvalue"));
const auto get = reinterpret_cast<Get>(GetProcAddress(handle, "getvalue"));

auto value = 1.0f;

// 0.0f gets set to the internal fotran variable when this code is compile in release.
set(value);

// Only succeeds when this code is compiled in Debug.
// get() returns 0.0f when this code is compiled in Release.
if(value == get()) 
{
    std::cout << "Success!
";
}
else
{
    std::cout << "Fail!
";
}

FreeLibrary(handle);

我不知所措。关于这里可能发生什么的任何想法或建议?

完整的可编译示例

以下是我正在解决的问题的完整可编辑示例的链接。有更多的时间与它一起度过。看来我的问题源于我尝试使用上面的代码制作包装器。

fortran_value.dll

fortran_value_test.exe

答案

在阅读了对我的问题的回答后,我花了更多的时间来调试fortran代码并做更多的研究。正如我对问题的回答中所讨论的,呼叫惯例存在不匹配。通过在我的fortran代码中使用bind(c),我的问题得到了解决。

自Fortran 2003(ISO / IEC 1539-1:2004(E))以来,有一种标准化的方法来生成与C(ISO / IEC 9899:1999)可互操作的过程和派生类型声明和全局变量。添加了bind(C)属性以通知编译器符号应与C互操作;此外,还增加了一些限制。但请注意,并非所有C功能都具有Fortran等效功能,反之亦然。例如,C的无符号整数和具有可变数量参数的C函数在Fortran中都不具有等价

    REAL FUNCTION getValue() bind(c)
!DEC$ ATTRIBUTES DLLEXPORT :: getValue
    IMPLICIT NONE
    INCLUDE 'VALUE.CMN'

    getValue = VAL
    RETURN
      END FUNCTION getValue

    SUBROUTINE setValue(x) bind(c)
!DEC$ ATTRIBUTES DLLEXPORT :: setValue
    IMPLICIT NONE 
    INCLUDE 'VALUE.CMN'

    REAL, INTENT(IN) :: x

    VAL = x 

      END SUBROUTINE setValue

以上是关于从动态库加载Fortran函数:Debug vs Release的主要内容,如果未能解决你的问题,请参考以下文章

在vs 2012中运行fortran语言时出现提示Debug win 32需要win 32平台支持编译,是啥情况?

如何编译C/Fortran动态/静态链接库

HDF5:构建 Fortran 库 (Windows)

VS中Debug和Realease及静态库和动态库的区别整理(转)

CMAKE怎么编译LAPACK

VS2010创建动态链接库(DLL)的方法