0

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
B. Eckles
  • 1,626
  • 2
  • 15
  • 27
  • 2
    It's not entirely clear (maybe I haven't read the question thoroughly enough) -- you're not trying to link a Windows executable to a Linux library are you ? – High Performance Mark Oct 11 '16 at 16:47
  • I don't think so... They're both being built on Windows, just the FORTRAN is being built with gfortran in the Makefile, which is being called from CMake. I don't know, come to think of it, exactly how it's calling `make`. I do have MSYS2 installed, and I got it working with that before getting to this stage, but I don't know what CMake is using to make that call. How would I find out? – B. Eckles Oct 11 '16 at 16:50
  • 2
    Well, you might want to clarify your question, it seems I'm not the only person who was initially confused. As for the rest of your comment, if you have material to add to your question add it, don't ask supplementary questions in comments, they're just too difficult to read. – High Performance Mark Oct 11 '16 at 16:51
  • 1
    Lahey used to support an interface between gfortran and Visual Studio. Several commercial Fortran products work with Visual Studio. Otherwise, it would appear advisable to stick with a single combined distribution of g++/gfortran (probably MinGW, if you already chose that, or you can't accept cygwin license terms). In either case, a single .exe must be entirely 32- or 64-bit mode. – tim18 Oct 11 '16 at 17:20
  • Unfortunately, I don't have the option of changing out either compiler. The C++ project already uses Visual Studio, and I can't require all developers who use the code to purchase commercial licenses for FORTRAN products. If I could, then yes, this would be a much simpler problem! Also, I know that the entire executable muse be 32- or 64-bit. I'm trying to figure out where that's going wrong, if it is indeed going wrong. – B. Eckles Oct 11 '16 at 17:23
  • 1
    BTW It's Fortran. It has been officially for over quarter of a century. See the Fortran 90 entry under https://en.wikipedia.org/wiki/Fortran – Ian Bush Oct 11 '16 at 19:21
  • Hahaha! I had to read the entry to be able to read your sentence properly! Good call... though most of the code I deal with is still FORTRAN 77, so I'm used to that spelling. ;) But yes, this project is mostly Fortran 90 or newer, so you're right. – B. Eckles Oct 11 '16 at 19:24
  • And wouldn't you like to change that spelling? Normally I just edit that whenever I see it but if you actually want it that way... – Vladimir F Героям слава Oct 11 '16 at 22:47
  • 2
    Your makefile specifies /machine:x86, i.e. 32 bit, for the DLL's import library. Are you compiling to 32 bit or 64 bit with gfortran? Your operating system is 64 bit, and there's no `-m 32` in your gfortran command line, which makes me suspect you are compiling the DLL for 64 bits. Are you building a 32 bit or 64 bit EXE? You can use `dumpbin /headers filename.xxx` to determine the bitness of an EXE or DLL. What bitness EXE/DLL do you want to build? How are you invoking cmake? There's no way of determining this stuff from the information that you have posted. – IanH Oct 11 '16 at 23:12
  • @VladimirF lol you're welcome to change it if it bothers you. It doesn't bother me much. ;) – B. Eckles Oct 13 '16 at 16:02
  • @IanH Good points. I've now tried adding a `-m32` flag but I'm having issues with it. New question about that here: http://stackoverflow.com/questions/40025754/why-wont-my-32-bit-fortran-c-dll-compile-in-msys2 `dumpbin` confirmed the EXE is x86. I believe that eventually I'll want to build both bitnesses, but I'm starting with 32-bit. I'm invoking cmake via the cmake-gui. – B. Eckles Oct 13 '16 at 16:05
  • 1
    I used the `bind(C)` feature, but if you make your C calling the Fortran mangled symbols it should also work. I just compiled by the `gfortran` from MinGW, that was all. Everything was 32-bit at that time. I don't remember any particular details, because everything was smooth and straightforward. I didn't have to solve any big problems. – Vladimir F Героям слава Oct 13 '16 at 16:18
  • I don't suppose this code is available online somewhere? :D – B. Eckles Oct 13 '16 at 16:19
  • @VladimirF I'm guessing you're not able to post your code base. ;) Can you at least tell me which version of MinGW you used? (ie. I'm assuming it wasn't mingw-w64 or msys2. Was it just standard MinGW from https://sourceforge.net/projects/mingw/files/Installer/, for example?) – B. Eckles Oct 13 '16 at 19:50
  • It's a long time age, but I opened it again and I have there gfortran 4.7 from the page you link, thread model win32, target i586-pc-mingw32. There is nothing special about the code. – Vladimir F Героям слава Oct 13 '16 at 21:08

2 Answers2

0

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.

Nathan Whitehead
  • 1,942
  • 2
  • 16
  • 19
  • 5
    It's not *that* difficult. Many people attending the Fortran tag are mixing Fortran and C or C++ routinely. Translation is normally not needed. I have myself used DLL compiled by gfortran as a plugin to Windows game compiled by MSVC++ and the only required thing was to export the symbol with the right name and call the right C symbols. – Vladimir F Героям слава Oct 11 '16 at 22:25
  • You're probably right, my experience in Windows is way out of date. I just remember having problems getting reliable working Fortran DLLs from MingGW. – Nathan Whitehead Oct 11 '16 at 22:57
  • 1
    If you insist on mixing disparate environments such as MSVC++ and gfortran, the dll route seems most likely to be successful, but this didn't appear to be what you had in mind originally. You still couldn't mix 32- and 64-bit modes this way, and you would not be relieved of the responsibility for reconciling decoration conventions. – tim18 Oct 11 '16 at 23:25
  • 1
    @tim18 Probably should be targetted to the asker/below the question? – Vladimir F Героям слава Oct 11 '16 at 23:32
  • Great info, thanks guys! Unfortunately I don't have the option to translate the Fortran to C. Nathan's second idea is a good one, but is basically what I'm trying to do, I think. Maybe I'm missing a few elements, but that splitting of the problem has been what I've been working on for a while. Also, judging from the other comments, it might not be necessary to do all of those extra things just yet... @tim18 Can you explain a bit more? It sounds good to me, but what do you mean exactly by "the dll route"? Also, Vladimir, thanks for all of your inputs man! – B. Eckles Oct 13 '16 at 16:11
  • Also, @VladimirF can you tell me more about that game you mentioned and how that worked? (Not the game part-- the "used DLL compiled by gfortran as a plugin to Windows ... compiled by MSVC++" part!) It sounds very similar to what I want to do! It's very possible I'm going down the wrong road to get there. – B. Eckles Oct 13 '16 at 16:14
0

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!

Community
  • 1
  • 1
B. Eckles
  • 1,626
  • 2
  • 15
  • 27