Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.
29298 Discussions

error LNK2019: unresolved external symbol....

bonnied
Beginner
3,470 Views
I am attempting to call a MS C++ function from an Intel FORTRAN program and am getting the following error:
error LNK2019: unresolved external symbol _InitComPort referenced in function _MAIN_
The abreviatedFORTRAN code is:
PROGRAMTestComPort
USE KERNEL32
INTEGER(HANDLE) hPort
INTEGER*2 status
INTERFACE
INTEGER FUNCTION InitComPort (intHandle)
!DEC$ ATTRIBUTES C, ALIAS:'_InitComPort' :: InitComPort
INTEGER intHandle
END FUNCTION InitComPort
END INTERFACE
status = InitComPort (hPort)
IF ( .NOT. status) THEN
PRINT *, 'Unable to initialize the comm port (status: ', status, ')'
GOTO 999
ELSE
PRINT *, 'The port identifier is: ', hPort
ENDIF
999 CONTINUE
END PROGRAMTestComPort
The abreviated C code is:
extern unsigned char InitComPort (HANDLE hPort)
{
string num_strg,port,settings;
unsigned char success=0;
SetComPort(NULL,NULL);
hPort = CreateFile("COM1:",(GENERIC_READ | GENERIC_WRITE), 0,
NULL,OPEN_EXISTING,0,NULL);
if (hPort == INVALID_HANDLE_VALUE)
success=1;
return (success);
}
What am I missing here?
Bonnie
0 Kudos
11 Replies
ipattielgc
Beginner
3,470 Views

Maybe C++ is mangling the function name, I usually include an "extern "C" " to eliminate mangling in the C++ code.

0 Kudos
bonnied
Beginner
3,470 Views

Either I don't understand your suggestion, or it's not the correct solution.

I inserted the extern "C" in front of the C++ declaration and I get the same error.

Bonnie
0 Kudos
Jugoslav_Dujic
Valued Contributor II
3,470 Views
That's the correct suggestion...
Open command prompt, then browse to .Debug or .Release folder of C++ project. In the command line, type
dumpbin /symbols CppFileName.obj > temp.txt
then open temp.txt and find the string "InitComPort". What's the decoration of it?
Jugoslav
0 Kudos
bonnied
Beginner
3,470 Views

Jugoslav

This is the line that from the dumpbin resultant file (temp.txt) which has the InitComPort definition in it.

1DD 00000048 SECT56 notype () External | ?InitComPort@@$$J14YGEPAX@Z (unsigned char __stdcall InitComPort(void *))

I confess I don't know a think about the .NET environment or programming in the Microsoft world. I'm and old VMS FORTRAN and MACRO programmer with some UNIX C/C++ experience. I'm assuming at this point that the InitComPort call needs to be referenced not as a C alias but as an _stdcall alias, but when I do that I don't get anything different. This baffles me.

So, then Iproceeded as follows:

1)Changed the project properties: I changed the properties in the C++ project, under C/C++ / Advanced / Calling Convention, to _cdecl (/Gd) and in the Fortran project, under Fortran / External Procedures / Calling Convention, to C, REFERENCE. This returned the following error:

error LNK2001: unresolved external symbol __CorExeMain@0

Ran thedumpbin command and found the following resultant InitComPort definition:

1DD 00000048 SECT56 notype () External | ?InitComPort@@$$J0YAEPAX@Z (unsigned char __cdecl InitComPort(void *))

2) Changed the project properties, again: I changed the properties in the C++ project, under Calling Convention, to__stdcall (/Gz)and in the Fortran project, under Calling Convention, to STDCALL, REFERENCE. This returned the following errors:

error LNK2019: unresolved external symbol _InitComPort referenced in function _main__

error LNK2019: unresolved external symbol _MAIN__ referenced in function _main

Ran thedumpbin command and found the following resultant InitComPort definition:

1DD 00000048 SECT56 notype () External | ?InitComPort@@$$J14YGEPAX@Z (unsigned char __stdcall InitComPort(void *))

3) Tried another change tothe project properties: Ileft the properties in the C++ project, under Calling Convention,as__stdcall (/Gz)and in the Fortran project, under Calling Convention, to STDCALL. This returned the same errors as 2):

error LNK2019: unresolved external symbol _InitComPort referenced in function _main__

error LNK2019: unresolved external symbol _MAIN__ referenced in function _main

Ran thedumpbin command and found the following resultant InitComPort definition:

1DD 00000048 SECT56 notype () External | ?InitComPort@@$$J14YGEPAX@Z (unsigned char __stdcall InitComPort(void *))

4) Not yet tired of being rejected, I tried another change tothe project properties: Ileft the properties in the C++ project, under Calling Convention,as__stdcall (/Gz)and in the Fortran project, under Calling Convention, to defauolt. This returned the following error:

error LNK2019: unresolved external symbol _InitComPort referenced in function _MAIN__

Ran thedumpbin command and found the following resu ltant InitComPort definition:

1DD 00000048 SECT56 notype () External | ?InitComPort@@$$J14YGEPAX@Z (unsigned char __stdcall InitComPort(void *))

I am completely baffled....

0 Kudos
Jugoslav_Dujic
Valued Contributor II
3,470 Views

No matter what you didwith calling conventions, you don't appear to have specified extern "C" correctly -- the InitComPort always has C++ name mangling (InitComPort@@$$J0YAEPAX@Z or like,variations coming from __stdcall vs. __cdecl).

Your initial setup was fine. Fortran compiler setting don't really affect anything if you have explicit INTERFACE with ALIAS and calling convention specified.

Just in case, specify extern "C" in both declaration(.h file if any) and definition(.cpp file) of InitComPort. (I'm not sure how exactly it works, but having it in both places is a safe bet).

(C vs C++) Name mangling and calling convention are not quite related; due to possibilities of function overloading and other language features, C++ has toencode all information about routine type, calling convention, and argument types in decorated name. This encoding is compiler-specific. You can specify any of (cdecl, stdcall, fastcall) calling convention in C++, but you have to match it in Fortran INTERFACE (fastcall not supported).

Quote from MSDN:


A decorated name for a C++ function contains the following information:
  • The function name.
  • The class that the function is a member of, if it is a member function. This may include the class that encloses the functions class, and so on.
  • The namespace the function belongs to (if it is part of a namespace).
  • The types of the functions parameters.
  • The calling convention.
  • The return type of the function.
  • The function and class names are encoded in the decorated name. The rest of the decorated name is a code that has internal meaning only for the compiler and the linker. The following are examples of undecorated and decorated C++ names.


    Jugoslav

    0 Kudos
    bonnied
    Beginner
    3,470 Views

    Jugoslav

    Thank you so much for all your information!

    I have finally resolved this issue, but it was a little more that just the C++ mangling of the name, which I did not understand verywell until your last email. (Now it actually makes some sense!)

    Apparently, my problem also had issue with programming in the .NET environment. Itagged onto a .NET programmer who just couldn't believe the code wasn't linking once I had placed the extern "C" command in the code. After playing around with several of the two projects' settings we finally corrected the linking problem.

    Let me summarize in case someone else ever sees the same thing and the extern "C" doesn't correct the situation:

    In the FORTRAN project properties (which is the calling project, in this case):

    • The Fortran / External Procedures / Calling Convention should be C, REFERENCE (although, this can be handled in the code with an INTERFACE command).
    • The Linker / General / Additional Library Directories MAY need to have the path for the library you're about to link to declared.

    In the C++ project properties (which is a library of called routines, in this case):

    • The C/C++ / Advanced / Calling Conventionshould be __stdcall (/Gz).

    In the C++source fileproperties (the only place you can find this one)

    • The C/C++ / General / Compile As Managed should be Not using managed extensions. (Compile As Managed controls the /clr parameter on the command line and you don't want the /clr) (This was the reason that Iwas getting the following error

      error LNK2001: unresolved external symbol __CorExeMain@0)

    This last item (/clr param) was the kicker. If I change it back to Compile As Managed or , the link does not work.

    Thanks again for all your help, it would have taken me much longer to resolve this without your support.

    Bonnie

    0 Kudos
    Steven_L_Intel1
    Employee
    3,470 Views
    /Gz and C,REFERENCE don't mix. It may appear to work, but you'll get stack corruption at run-time. I suggest dropping the /Gz, it looks as if you don't need it.
    0 Kudos
    bonnied
    Beginner
    3,470 Views
    Thanks, Steve
    I took your advice and then Ialso needed to change the !DEC$ ATTRIBUTES line to the following in order to link:

    !DEC$ ATTRIBUTES C, DECORATE, ALIAS:'InitComPort' :: InitComPort

    (had to exchange STDCALL for C)

    By the way, the stripped down code was running before the change, but the stack is very shallow in the stripped down version. The full blown program would have likely failed with the incompatibility.

    Thanks, again.

    Bonnie

    0 Kudos
    Steven_L_Intel1
    Employee
    3,470 Views
    Right - I did not see in your earlier reply that you were using ATTRIBUTES STDCALL - it looked to me as if you were using ATTRIBUTES C.
    0 Kudos
    bonnied
    Beginner
    3,470 Views
    Steve,
    My apologies. I see that I wasn't clear on that in my posting covering all the changes I had attempted. I had entered that more clearly inan original attempt to post, but had gotten called away and lost my connectionto the boardbefore sending the email. Forgot it the second time around....
    That also explains why that version, before your suggested change, was working...I had over-ridden the program properties in the INTERFACE declaration. (I'm learning.)
    Bonnie
    0 Kudos
    Jugoslav_Dujic
    Valued Contributor II
    3,470 Views

    FWIW, personally I prefer to leave compiler defaults as much as possible, and to spell out any specifics (via !DEC$ATTRIBUTES or __stdcall).

    There's no much real difference in performance of cdecl vs. stdcall. Cdecl is more widely accepted and it's universal on UNIXes, but stdcall has its merits as well, but the differences are slight. It's tougher to obtain fandango on stack with cdecl than with stdcall, but then, it means just that programmer's errors are hidden. Ideally, it shouldn't matter which one you use, as long as you pay attention to interactions (between different compilers).

    Jugoslav

    0 Kudos
    Reply