- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
in front i´m complete new with Fortran.
So my Problem is: We have an realy old Software Project. It was generatet with Compaq Visual Fortran 6.1 and includes Source Files in *.cpp and *.for.
From my point of view, it was extremly confortable to compile and Debug this Project in one step by pressing F5.
My question is: Is there a way to do the same with VisualStudio and IntelParallelstudio XE 2016?
In best case i would like to convert my Compaq c++ DSW to VisualStudio.
Until now i only found examples where a Fortran dll was use by a c++ Programm. IBut i would like to create a dll from c++ and Fortran sourcefiles.
Best
Daniel
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Visual Studio doesn't allow source files for different programming languages in one project. So you should split the set of source files into two or more separate projects. However, by setting the dependencies correctly, all you need to do is build the topmost project and all dependencies are automatically taken care of.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Suppose I build the C++ as a dll within the project and attempt to connect to it via Fortran. I have had luck doing this with: 1) C++, and 2) C#. The Fortran poses unique problems.
In order to remove the name mangling of the C++, I declared its exports with EXTERN_C. But there are limitations to this approach which I do not fully comprehend. The attempt was to create a C++ class with a static function to export. I cannot seem to get the syntax quite right because everything compiles but the linkage fails with several complaints about missing external symbols. With compilation being Win32 Debug in both projects, the first complaint is
Error 2 error LNK2001: unresolved external symbol @_RTC_CheckStackVars@8
with similar complaints following. I know this has been pursued elsewhere, but I have USED code from former forum posts to build the example without luck.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This could be a matter of differing calling conventions - CDECL versus STDCALL. Typically for STDCALL: the number of arguments (or rather the total size in bytes) is encoded in the name - the @8 bit in your case.
Could you show us a code example that exhibits this problem? (Say, a Fortran program that calls the single C++ routine in the DLL)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
That reference is to a MSVC library routine, though the leading @ seems wrong. Can you show us a small but complete example that demonstrates the problem?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Most of the error messages are because you changed the Fortran project's linker property "Ignore all default libraries" to Yes. Set that to No.
What you're left with is the reference to _GetLastErrorMessage which you have defined in the C++ project as a class member. This won't work. To call C++ code from Fortran the C++ routine has to be declared with 'extern "C"' and not part of a class. Remember, it's C interoperability, not C++ interoperability.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you for the heads up on the "No" for "Ignore All Default Libraries". I built the exported dll function as not static and EXTERN_C.
The complaint is still
Error 1 error LNK2019: unresolved external symbol _GetLastErrorMessage referenced in function _MAIN__
What linkage step have I left out? "Additional Dependencies"? I am noting the C++ dll is created within the Debug output directory.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You didn't do the 'extern "C"' thing. You also never DLLEXPORTed the C++ routine, nor did you tell the Fortran project to link in the C++ project's export library.
Here's what you need to do:
- Right click on the Fortran project, select Build Dependencies > Project Dependencies. Check the box for the C++ project and click OK
- In your C++ code, change the function header to: extern "C" __declspec(dllexport) char* GetLastErrorMessage()
- Right click on the Fortran project, select Properties. Go to Linker > Input. Change the Configuration dropdown to All Configurations. In the Additional Dependencies property, put in: $(OutDir)\PassingStuffToFromCpp.lib
Normally this last step would not be needed, but there's a bug in MSVC where it won't make a C++ DLL project visible to Fortran as a link dependency.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I followed those steps completely. Per usual, I have no proof because it continues not to link. I am attaching my latest version of the code. It bonks with
Error 2 fatal error LNK1107: invalid or corrupt file: cannot read at 0x2F0 Debug\PassingStuffToFromCpp.dll
I know you said to use PassingStuffToFromCpp.lib as the Additional Dependencies, but that lib file is not created in the build of my C++ project.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
One doesn't link to a DLL directly. Always the .LIB.
You didn't do step 2.
By the way, you don't need the DllMain routine if you're not going to do anything in it.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
But I did do step 2, didn't I? My header file code reads
namespace PassingToFro { EXTERN_C __declspec(dllexport) char* GetLastErrorMessage(); }
Is this not what was mentioned in step 2?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Not in the ZIP you attached.
// PassingStuffToFromCpp.cpp : Defines the exported functions for the DLL application. // #include "stdafx.h" namespace PassingToFro { char HelloWorld[12]; char* GetLastErrorMessage() { strcpy_s(HelloWorld, 12, "Hello World"); return HelloWorld; } }
Your not adding __declspec(dllexport) prevents the .lib from being created.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Now I'm confused. Where does the __declspec(dllexport) phrase lie? And where does the extern "C" phrase lie? I put both in the header file. Should I have put them in the source and not in the header file?
Then the real question to be asked is, if I am using somebody else's library who has used appropriate export statements and entry points, how do I access their library? At present all I have is a dll file with "appropriate" entry points, but I have been completely unable to make anything link.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Okay, now I have discovered the inherent foolishness of my approach. All it would have taken is to add the line
#include "PassingStuffToFromCpp.h"
to the file PassingStuffToFromCpp.cpp. Then your method would have worked without trouble.
Forgive my mistake.
The question remains, how does one connect Fortran source to a dll? I am connecting to the lib file without error. Do I need the lib files for third party software to make this work?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Nothing is looking at the header file. You put these in the function itself. If you are using a header file you could also put them there, but that's not going to fix your problem on its own.
If all they give you is a DLL, you cannot link to it. I have seen tools that will construct an export library from a DLL, or you can use LoadLibrary and GetProcAddress - see the DLL\DynamicLoad example we provide.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you for the help. I am now pursuing the "DLL\DynamicLoad" sample. I have one question: would a Fortran program be capable of catching an exception thrown by an external dll?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
A DLL is just a collection of procedures. There's no difference in behavior of calling a routine in a DLL or one in a static library (or even in its own objects.)
I will note though that Fortran has no exception handling capability.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The calling of a routine in a DLL is posing some challenges. I first conquered the calling of routine
extern "C" { __declspec(dllexport) double Add(double a, double b); }
using the Fortran abstract interface
FUNCTION ADD_double(a, b) USE iso_c_binding, ONLY : c_double REAL (KIND = c_double) :: ADD_double REAL (KIND = c_double), INTENT(IN) :: a, b END FUNCTION ADD_double
and the declarations
PROCEDURE (ADD_double), POINTER :: ADD REAL (KIND = c_double) a, b, ret
and the CALL sequence
ret = ADD(%VAL(a), %VAL(b))
I guess this one demonstrated the call-by-reference/call-by-value distinction in the two languages. However, the calling of routine
extern "C" { __declspec(dllexport) char * Subtract(double a, double b); }
using the Fortran abstract interface
FUNCTION SUBTRACT_double(a, b) USE iso_c_binding, ONLY : C_PTR, c_double TYPE (C_PTR) :: SUBTRACT_double REAL (KIND = c_double), INTENT(IN) :: a, b END FUNCTION SUBTRACT_double
and the declarations
PROCEDURE (SUBTRACT_double), POINTER :: SUBTRACT TYPE (C_PTR) ret_sub
and the CALL sequence
ret_sub = SUBTRACT(%VAL(a), %VAL(b))
did not work. Debugging this one saw that the input values attained in the C++ Subtract function were not equal to the values sent by the Fortran. What have I omitted in the calling of the second routine (Subtract)? This example is based summarily on the C++ example posed in
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
First of all, don't use %VAL. Instead, add the VALUE attribute to the dummy arguments a and b in the interface.
I can't tell what went wrong because you have not shown a complete program - you haven't even shown the contents of the C Subtract function (there is no such function on the MSDN page you linked to.) How are a and b declared in the caller?
It would be best if you'd attach a ZIP of the complete solution (do a Build > Clean first) so we can see the whole picture.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Attached is the entire project: C++ dll, C++ driver for dll, C# driver for dll and Fortran driver for dll. The Fortran driver is a reproduction of the sample DLL\DynamicLoad. I tried applying the "VALUE" attribute rather than INTENT(IN) in the ABSTRACT INTERFACE without any luck. The code comment reflects this.
As for the code not following the Microsoft sample, I guess this is Microsoft's newest sample and I had used an older one. Sorry.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page