Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28477 Discussions

Problem linking FORTRAN and C++ .LIB that calls a managed function

Murali1
Beginner
320 Views


I have a large FORTRAN program that calls C++ functions linked as a static library using Microsoft Visual Studio 9. I supply the .LIB created by the C++ project to the FORTRAN linker. Previously I only used unmanged code. Now I want to extend the C++ function to use managed code.

So I added a new C++ function that is called from one of the existing C++ functions that itself is called from FORTRAN. The new C++ function is compiled using the /CLR option on the C++ side. The reason I did this is to be able to use .NET on the C++ side. How do I link this new .LIB file using FORTRAN linker? Now I receive a bunch of unresolved symbol and token messages. Just to make things clear I have drawn a diagram. (I hope the diagramis more clear than my description :) )

Program A (FORTRAN) ---> calls ---->C++ function B---> which in turn calls C++ function C compiled using /CLR

The first of several messages I receive from the FORTRAN linker is the following:

CPP.lib(CTest.obj) : error LNK2028: unresolved token (0A000006) "extern "C" void __clrcall ___CxxCallUnwindDtor(void (__clrcall*)(void *),void *)" (?___CxxCallUnwindDtor@@$$J0YMXP6MXPAX@Z0@Z) referenced in function "public: virtual __thiscall std::logic_error::~logic_error(void)" (??1logic_error@std@@$$FUAE@XZ)

Thanks in advance.

Murali

0 Kudos
3 Replies
jirina
New Contributor I
320 Views
I use lib and dll written in C++ in my Fortran program too. It is quite complicated (for historical reasons) and it goes like this:

1. I have a dll with one function
[cpp]__declspec(dllexport) void WriteLogEntryNET
(char* appName, char* logName, char* message, int typeID, int eventID, int catID )[/cpp]
The function is supposed to write into the event log. This project is compiled in Visual Studio 2008 using following options:
[cpp]/O2 /Ob1 /Oy /D "WIN32" /D "_WINDOWS" /D "NDEBUG" /D "_USRDLL" /D "_AFXDLL" /D "_VC80_UPGRADE=0x0700" /D "_WINDLL" /D "_MBCS" /GF /FD /EHa /MD /Gy /Yu"stdafx.h" /Fp"ReleaseCppEventLog.pch" /Fo"Release" /Fd"Releasevc90.pdb" /W3 /nologo /c /Zi /clr /TP /errorReport:prompt[/cpp]
2. In another C++ project, I am creating a lib to be used by my Fortran program. Functions which are supposed to be called from Fortran are declared like this:
[cpp]extern "C" {
__declspec(dllexport) void __stdcall WriteLogEntry
(char* appName, int appNameLen,
char* logName, int logNameLen,
char* message, int messageLen,
int typeID, int eventID, int catID );
__declspec(dllexport) void __stdcall WorkingDirectory
(char* workDir, int workDirLen);
__declspec(dllexport) int __stdcall InitSignalProcessing
(void);
__declspec(dllexport) BOOL __stdcall CtrlHandler
(DWORD fdwCtrlType);
}[/cpp]
I'm using dll from step 1. to call the function WriteLogEntryNET.

Compiler options are:
[cpp]/O2 /Ob1 /Oy /D "WIN32" /D "_WINDOWS" /D "NDEBUG" /D "_USRDLL" /D "_VC80_UPGRADE=0x0700" /D "_WINDLL" /D "_MBCS" /GF /FD /EHsc /MT /Gy /Yu"stdafx.h" /Fp"ReleaseEventLog.pch" /Fo"Release" /Fd"Releasevc90.pdb" /W3 /nologo /c /Zi /TP /errorReport:prompt[/cpp]
dll from Step 1. is listed in Linker -> Input -> Delay Loaded DLLs.

3. Finally, Fortran code for one of the functions from Step 2. reads:
[cpp]      interface
        subroutine WriteLogEntry( appName, appNamelen, logName, logNameLen, msg, msgLen, typeID, eventID, catID )
        !dec$ attributes stdcall, dllimport, decorate, alias: "WriteLogEntry" :: WriteLogEntry
        ! Event log entry parameters
        character*30 appName
        character*20 logName
        character*1024 msg
        integer*4 appNameLen, logNameLen, msgLen
        integer*4 typeID, eventID, catID
        !dec$ attributes reference :: appName, logName, msg
        end subroutine WriteLogEntry
      end interface[/cpp]
Calling this function works well.

I have EventLog.lib from Step 2. included in my project and important linker options (for my program) are:
[cpp]/DELAYLOAD:"EventLog.dll" (dll from Step 2.) /IMPLIB:"D:...myApp.lib" delayimp.lib libguide.lib[/cpp]
I am not sure if anything from above will help you, but you might find something useful.
0 Kudos
Murali1
Beginner
320 Views
Thanks for the quick reply. I want to make sure I understand exactly what you are doing.

The WriteLogEntryNet is called from WriteLogEntry (which is a C function) which in turn is being called from FORTRAN. the C functions called from FORTRAN are supplied through the static library. The C Static Library in turn is using the DLL. Am I right?

And you appear to have created a DLL to isolate managed code since WriteLogEntryNet uses the /clr compiler option. The other thing I don't understand is this. In step 2 I assume WriteLogEntry which is part of a static library project calls WriteLogEntryNet. How is it declared in the second .LIB project?

How is the first DLL supplied to step 2?

Thanks again.

0 Kudos
jirina
New Contributor I
320 Views
You are right that the DLL from Step 1. (CppEventLog.dll) was created to isolate the managed code.

You are also right that the C function WriteLogEntry from Step 2. calls WriteLogEntryNET from CppEventLog.dll. The C library created in Step 2. is static.

Fortran code --> WriteLogEntry (static C library) --> WriteLogEntry (CppEventLog.dll)

CppEventLog from Step 1. is supplied to Step 2. by adding CppEventLog.lib to the project files. I also added CppEventLog.dll to Linker - Input - Delay Loaded DLLs.

To be able to call WriteLogEntryNET, I have following in the source code from Step 2.:
[cpp]typedef void (CALLBACK* WRITELOGENTRYNET)(char*,char*,char*,int,int,int);[/cpp]
I hope I did not forget anything.
0 Kudos
Reply