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

问题描述 投票:1回答:1

我编写了一些代码来加载在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!\n";
}
else
{
    std::cout << "Fail!\n";
}

FreeLibrary(handle);

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

完整的可编译示例

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

fortran_value.dll

fortran_value_test.exe

c++ visual-studio dll fortran intel-fortran
1个回答
2
投票

在阅读了对我的问题的回答后,我花了更多的时间来调试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
© www.soinside.com 2019 - 2024. All rights reserved.