为什么我的C++程序无法正确加载我的 FORTRAN 库?

Why won't my C++ program properly load my FORTRAN library?

本文关键字:我的 加载 FORTRAN C++ 程序 为什么      更新时间:2023-10-16

要解释这个问题有点复杂,从技术上讲,它涉及大量代码,所以我将尽力解释它。如果事实证明我需要张贴代码,我会张贴人们要求的部分,因为他们要求它,以避免把它弄得太乱。

我也相当确定我知道一般的问题是什么,我只是不确定如何解决它或找出如何解决它。其中大部分都是我所知甚少的东西,多亏了其他SO问题和无数的谷歌搜索之类的,以及大量的试验和错误,我才有了今天的成就。

我将首先声明我认为问题是我正在做的部分被编译为32位,部分被编译为64位。希望这是准确的,它会帮助你在阅读这篇文章时把注意力集中在正确的地方。

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

到目前为止,我已经有了一个小的示例代码库,我正在进行试验,一旦我让它工作,我将使用相同的概念使实际的代码工作。 我想说的是,这一切都工作得很好,但是当我实际运行结果程序时,我得到以下错误:

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

有什么想法是错误的(谷歌的结果似乎暗示可执行文件和库分别是32位和64位,或者相反),以及如何修复它?

请注意,这都是在Windows上构建的,只是FORTRAN是用gfortran在Makefile中构建的,它是从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

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

在Windows中创建正确的DLL文件可能会有很多棘手的原因,比如调用约定、编译器标志和函数可见性。在完成gfortran的过程中,让一切都正确在技术上是可能的,但不推荐。

有两种主要的方法。

1)首先是将Fortran代码翻译成C或c++,然后将该代码直接集成到您的主要c++项目中(最简单),或者使用常规方法将其编译成DLL(最好使用Visual Studio保持单个工具链)。您提到您有Fortran 90代码,因此您应该研究一下Fable工具。

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

感谢大家的帮助,特别是@IanH在另一个相关的SO问题上帮助我,我终于弄清楚了整个事情!

简短的回答是DLL被编译为64位。所以我只是下载并安装了32位版本的MSYS2和所有适当的工具(make, gcc等),现在一切都工作了!