【问题标题】:Why won't my C++ program properly load my FORTRAN library?为什么我的 C++ 程序不能正确加载我的 FORTRAN 库?
【发布时间】:2017-02-20 07:10:43
【问题描述】:

这是一个解释起来有点复杂的问题,而且它在技术上涉及很多代码,所以我会尽力解释它。如果事实证明我需要发布代码,我会发布人们要求的部分,因为他们要求它,以避免过于混乱。

我也很确定我知道一般问题是什么,只是不知道如何解决它或弄清楚如何解决它。其中大部分涉及我知之甚少的东西,而且由于其他 SO 问题和无数的 Google 搜索等,以及将它们拼凑在一起的大量试验和错误,我才走到了现在的位置。

我将首先声明我认为问题在于我正在做的部分工作是编译为 32 位的,而一部分是 64 位的。希望这是准确的,它将帮助您在正确的地方集中注意力阅读本文。

基本上,我有一个使用 CMake 和 Visual Studio 12 2013 在 Windows 上构建和编译的 C++ 代码库,以及一个使用 gfortran 在 Linux 上构建和编译的 FORTRAN 代码库。最终目标是使 FORTRAN 成为某种可以被 C++ 代码使用的库,并通过 CMake 让所有这些都很好地工作,这样当前的 C++ 代码开发人员就不必做任何额外或烦人的事情了使用它。

到目前为止,我已经有了一个正在试验的小型示例代码库,一旦我得到它,我将使用相同的概念来使实际代码工作。

我的意思是一切都很好,但是当我实际运行生成的程序时,我收到以下错误:

The application was unable to start correctly (0xc000007b). Click OK to close the application.

关于出了什么问题的任何想法(Google 结果似乎暗示可执行文件和库分别是 32 位和 64 位,反之亦然),以及如何解决它?

请注意,这一切都是在 Windows 上构建的,只是 FORTRAN 是在 Makefile 中使用 gfortran 构建的,它是从 CMake 调用的。我实际上并不确切知道 CMake 是如何调用make 的。我确实安装了 MSYS2,在进入这个阶段之前我已经使用它了,但我不知道 CMake 是如何进行调用的。如果你知道我是怎么知道的,请告诉我!

在这里,我将发布我用来编译所有内容的写得很糟糕的 CMakeLists.txt 和 Makefile。如果您想查看其他详细信息,请告诉我!此外,由于有这么多活动部件,我不确定在软件版本方面提到哪些东西真正相关。如果您有什么想知道的,请告诉我。

再次,我为我所有的笨拙道歉——这不是我的强项。

Makefile: (我的编辑器将制表符更改为空格)

FC=gfortran -g
CC=g++ -g

DLL_SRC_DIR=.
BUILD_DIR=build

all:
    $(FC) -c $(DLL_SRC_DIR)/fdll.f90 -o $(BUILD_DIR)/fdll.o

    $(CC) -c -DBUILDING_C_DLL $(DLL_SRC_DIR)/cdll.cpp -o $(BUILD_DIR)/cdll.o
    $(CC) -shared -o $(BUILD_DIR)/libcdll.dll $(BUILD_DIR)/cdll.o $(BUILD_DIR)/fdll.o -Wl,--out-implib,$(BUILD_DIR)/libcdll.a,--output-def,$(BUILD_DIR)/libcdll.def -lgfortran
    /c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio\ 12.0/VC/BIN/lib /MACHINE:x86 /DEF:$(BUILD_DIR)\\libcdll.def /OUT:$(BUILD_DIR)\\libcdll.lib

clean:
    rm -f $(BUILD_DIR)/*

CMakeLists.txt

project(cmake_test)
add_executable(cprog cprog.cpp)

find_path(FORTRAN_DIR NAMES cdll.cpp fdll.f90 Makefile PATHS ../source)

execute_process(COMMAND make
                WORKING_DIRECTORY ${FORTRAN_DIR})

set(FORTRAN_LIB ${FORTRAN_DIR}/build/libcdll.lib)

include_directories(${FORTRAN_DIR})
set(MY_LIBRARIES ${MY_LIBRARIES} ${FORTRAN_LIB})

target_link_libraries(cprog ${MY_LIBRARIES})

# See: http://stackoverflow.com/questions/10671916/how-to-copy-dll-files-into-the-same-folder-as-the-executable-using-cmake
add_custom_command(TARGET cprog POST_BUILD         # Adds a post-build event to cprog
    COMMAND ${CMAKE_COMMAND} -E copy_if_different  # which executes "cmake -E copy_if_different..."
    "${FORTRAN_DIR}/build/libcdll.dll"             # <--this is the file to copy
    $<TARGET_FILE_DIR:cprog>)                      # <--this is where to copy it

【问题讨论】:

  • 这并不完全清楚(也许我没有彻底阅读这个问题)——你不是在尝试将 Windows 可执行文件链接到 Linux 库吗?
  • 好吧,您可能想澄清您的问题,看来我并不是唯一一个最初感到困惑的人。至于您评论的其余部分,如果您有材料要添加到您的问题中添加它,请不要在 cmets 中提出补充问题,它们太难阅读了。
  • Lahey 曾经支持 gfortran 和 Visual Studio 之间的接口。一些商业 Fortran 产品可与 Visual Studio 一起使用。否则,建议坚持使用 g++/gfortran 的单一组合发行版(可能是 MinGW,如果您已经选择了它,或者您不能接受 cygwin 许可条款)。无论哪种情况,单个 .exe 都必须完全是 32 位或 64 位模式。
  • 顺便说一句,这是 Fortran。它已经正式使用了超过四分之一个世纪。请参阅 en.wikipedia.org/wiki/Fortran 下的 Fortran 90 条目
  • 您的 makefile 为 DLL 的导入库指定 /machine:x86,即 32 位。你是用 gfortran 编译成 32 位还是 64 位?您的操作系统是 64 位的,并且 gfortran 命令行中没有 -m 32,这让我怀疑您正在为 64 位编译 DLL。您是在构建 32 位还是 64 位 EXE?您可以使用dumpbin /headers filename.xxx 来确定EXE 或DLL 的位数。您要构建什么位数的 EXE/DLL?你是如何调用cmake的?无法从您发布的信息中确定这些内容。

标签: c++ visual-studio dll cmake fortran


【解决方案1】:

您正在尝试将在 MSYS 下在 Windows 上使用 gfortran 创建的 DLL 库与使用 C++ 的 Visual Studio 项目相结合。

在 Windows 中创建正确的 DLL 文件可能很棘手,原因有很多,例如调用约定、编译器标志和函数可见性。在通过gfortran 的过程中正确处理一切可能在技术上是可行的,但不建议这样做。

主要有两种方法。

1) 首先是将 Fortran 代码转换为 C 或 C++,然后将该代码直接集成到您的主 C++ 项目中(最简单)或使用常规方法将其编译为 DLL(最好使用 Visual Studio 来保留单个工具链)。你提到你有 Fortran 90 代码,所以你应该调查Fable tool

2) 第二种方法是使用您的 MSYS gcc 工具链使用 C 源代码编写一个 DLL。一旦有了可从 Visual Studio 代码调用的工作 DLL,链接到使用 gfortran 编译的目标文件。这个想法是将问题分成两个可独立解决的部分:使用gcc 工具链制作一个DLL,以及混合C 和Fortran 代码。如果您有数百个 Fortran 函数,则此方法可能不可行,因为您需要为每个函数编写一些 shim 代码。

【讨论】:

  • 这不是困难。许多参加 Fortran 标签的人经常混合 Fortran 和 C 或 C++。一般不需要翻译。我自己使用 gfortran 编译的 DLL 作为 MSVC++ 编译的 Windows 游戏的插件,唯一需要的是导出具有正确名称的符号并调用正确的 C 符号。
  • 你可能是对的,我在 Windows 上的经验已经过时了。我只记得从 MingGW 获取可靠的工作 Fortran DLL 时遇到问题。
  • 如果你坚持混合不同的环境,比如 MSVC++ 和 gfortran,那么 dll 路由似乎最有可能成功,但这似乎并不是你最初的想法。您仍然无法以这种方式混合 32 位和 64 位模式,而且您也不能免除协调装饰约定的责任。
  • @tim18 可能应该针对提问者/问题下方?
  • 很棒的信息,谢谢大家!不幸的是,我没有将 Fortran 转换为 C 的选项。Nathan 的第二个想法是一个不错的想法,但我认为这基本上是我想要做的。也许我遗漏了一些元素,但问题的拆分一直是我一直在努力的方向。此外,从其他 cmets 来看,可能还没有必要做所有这些额外的事情......@tim18 你能解释一下吗?这对我来说听起来不错,但是“dll 路由”到底是什么意思?另外,弗拉基米尔,感谢您的所有投入!
【解决方案2】:

感谢大家的帮助,尤其是@IanH 在another related SO question 上帮助我,我终于弄明白了!

简短的回答是 DLL 被编译为 64 位。所以我刚刚下载并安装了 32 位版本的 MSYS2 以及所有适当的工具(makegcc 等),现在一切正常!

【讨论】:

    猜你喜欢
    • 2021-12-29
    • 2013-11-19
    • 2020-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多