This is a bit of a complicated question to explain, and it technically involves a lot of code, so I'm going to do my best to explain it. If it turns out I need to post code, I'll post what parts people ask for, as they ask for it, so as to avoid cluttering this up too much.
I'm also fairly sure I know what the general problem is, I'm just not sure how to fix it or figure out how to fix it. Most of this deals with stuff I know very little about, and I've only gotten to where I am thanks to other SO questions and countless Google searches and the like, and lots of trial and error of cobbling it all together.
I'll start off by stating that I believe the problem is that part of what I'm doing is being compiled 32-bit, and part of it 64-bit. Hopefully that's accurate, and it'll help you to read this with your focus in the right places.
Basically I've got a C++ code base which is built and compiled on Windows with CMake and Visual Studio 12 2013, and a FORTRAN code base which is built and compiled on Linux with gfortran. The end goal is to make the FORTRAN into some sort of library which can be used by the C++ code, and have it all work nicely via CMake such that current developers of the C++ code don't have to do anything extra or annoying in order to use it.
So far, I've got a small example code base which I'm experimenting with, and once I get it to work with that, I'll use the same concepts to make the actual code work.
The point I'm up to is that it all works nicely, but when I actually run the resulting program, I get the following error:
The application was unable to start correctly (0xc000007b). Click OK to close the application.
Any ideas about what is going wrong (Google results seem to imply that the executable and the library are 32- and 64-bit, respectively, or vis versa), and how to fix it?
Note that this is all being built on Windows, it's just that the FORTRAN is being built with gfortran in the Makefile, which is being called from CMake. I don't actually know exactly how CMake is calling make
. I do have MSYS2 installed, and I got it working with that before getting to this stage, but I don't know exactly how CMake is making that call. If you know how I could find that out, please let me know!
Here I will post the horribly written CMakeLists.txt and Makefile I'm using to compile everything. If you would like to see other specifics, please let me know! Also, since there are so many moving parts, I'm not sure which things it's really relevant to mention in terms of versions of software. Please let me know if there's anything you'd like to know.
Again, I apologize for all of my noobishness-- this stuff is not my forte.
Makefile: (My editor changed tabs to spaces)
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
You are trying to combine a DLL library created using gfortran
on Windows under MSYS with a Visual Studio project using C++.
Creating correct DLL files in Windows can be tricky for many reasons such as calling conventions, compiler flags, and function visibility. Getting everything right while going through gfortran
is probably technically possible but is not recommended.
There are two main approaches.
1) First is to translate the Fortran code into C or C++, then either integrate that code directly into your main C++ project (easiest) or compile it into a DLL using normal methods (preferably using Visual Studio to keep a single toolchain). You mentioned that you have Fortran 90 code, so you should investigate the Fable tool.
2) The second approach is to write a DLL using your MSYS gcc
toolchain using C source code. Once you have a working DLL that is callable from your Visual Studio code, link in object files compiled using gfortran
. The idea is to split the problem into two parts which are independently solvable: making a DLL using the gcc
toolchain, and mixing C and Fortran code. If you have hundreds of Fortran functions this method might not be feasible since you need to write some shim code for each function.
Thanks to everyone's help, but especially to @IanH helping me on another related SO question, I've got the whole thing figured out finally!
The short answer is that the DLL was being compiled 64-bit. So I just downloaded and installed the 32-bit version of MSYS2 with all of the appropriate tools (make
, gcc
, etc), and now everything works!
User contributions licensed under CC BY-SA 3.0