Silverfrost Forums

Welcome to our forums

How to load a Fortran function from C++ (instructions)

20 Jun 2017 10:28 (Edited: 20 Jun 2017 10:37) #19780

In the 32bit world it was possible for the linker to create a dll AND a lib file (via the archive command). This was particular useful as it allowed a Qt or VC++ program to call a Fortran function directly using

extern 'C' void FortranFunction(...)

Now however it is necessary to use LoadLibraryA if using VC++, as follows:

#include 'stdafx.h'
#include 'windows.h'
//extern 'C' void VERYSIMPLE(int* input);    //old way, with .lib file present



extern 'C' {
	typedef void(*VERYSIMPLE_ptr)(int* input);
}

void VERYSIMPLE(int* input)
{
	auto hdl = LoadLibraryA('fortran.dll');
	if (hdl)
	{
		auto the_func = reinterpret_cast< VERYSIMPLE_ptr >(GetProcAddress(hdl, 'VERYSIMPLE'));
		if (the_func)
			the_func(input);	
		else
			printf('no function\n');

		FreeLibrary(hdl);
	}
	else
		printf('no library\n');

}



int _tmain(int argc, _TCHAR* argv[])
{

	int input1 = 12;
        VERYSIMPLE(&input1);
	system('pause');
	return 0;
}
20 Jun 2017 10:31 #19781

If using Qt with MSVC, then it is possible to use LoadLibraryA as above, or use Qt's QLibrary.

#include <QLibrary>

void QW_GET_VALC(int* IWIN, int* IFLD, char* CH)
{
    typedef void (*MyPrototype)(int* IWIN, int* IFLD, char* C);
    MyPrototype myFunction = (MyPrototype) QLibrary::resolve('llib1', 'QW_GET_VALC');
    if (!myFunction)
    {
        qWarning()<<'\nError with function QW_GET_VALC';
    }

    if (myFunction)
        myFunction( IWIN,  IFLD,  CH);
}
20 Jun 2017 10:35 #19782

If passing a string from C++ to Fortran, be aware that you need to add in C++ the string size (strlen) as an extra int parameter at the end (as per Silverfrost's documentation).

In VC++ this works fine, but NOT in Qt. Not sure where the bug is (if it is Qt or Silverfrost), but a temporary solution is to create a VC++ DLL that calls the Fortran DLL, and Qt will call the VC++ DLL.

20 Jun 2017 11:48 #19783

StamK

It isn't necessary to use LoadLibrary when calling a C++ function from 64 bit FTN95.

The standard approach is to use extern 'C' and export the functions from the DLL. Then load the DLL via SLINK64.

In the Fortran code you should declare the DLL functions using C_EXTERNAL and, when passing strings, use STRING, INSTRING or OUTSTRING.

20 Jun 2017 12:13 #19784

Hi Paul, thanks for the useful input - but this is for Fortran calling a C++ DLL, while I have described a C++ executable loading a Fortran DLL.

20 Jun 2017 2:34 #19785

OK. I missed that.

Microsoft have a lib.exe app that creates mylib.lib from mylib.dll and mylib.def.

21 Jun 2017 3:59 #19789

I had tried that lib.exe command and it didn't work at first, but I found out that Qt was failing for another reason.

I can confirm that Qt can access the DLL with the LIB file created that way.

The script below removes the extra lines, cleans the rows and adds EXPORTS at the beginning of the DEF file, which is then used to create the LIB file. Assuming that the script is called libcreate.bat and the DLL file is called LIBRARIES.DLL, then it can be called as

libcreate.bat LIBRARIES

Code:

@echo off
if '%1'=='' goto blank
call del %1.def
for /f 'usebackq tokens=4,* delims=_ ' %%i in (`dumpbin /exports '%1.dll'`) do  echo %%i_%%j >> %1.def
call more +9 '%1.def' > '%1.def.new'
move /y '%1.def.new' '%1.def' >nul
copy %1.def temp.def
echo.EXPORTS>%1.def
type temp.def>>%1.def
del temp.def
lib /def:'%1.def' /out:'%1.lib'  /MACHINE:X64
goto DONE
:BLANK
echo No DLL file name present
:DONE
30 Jun 2017 2:43 #19816

If the Fortran subroutine/function is inside a module, then it will be necessary to use the LoadLibraryA method as Silverfrost exports it as MODULENAME!FORTRAN_SUBROUTINE and cannot be found via extern 'C' (or at least I am not able to put a name with an exclamation mark). Unless there is a way to tell Silverfrost to export in a different name?

Thanks

30 Jun 2017 8:14 #19818

SLINK64 has an 'alias' option that is described in the help file at FTN95->x64 platform->Using the 64 bit linker. It might be useful in this context. The 'map' option may also be useful in that it may show the internal representation of the module function.

Please login to reply.