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

LNK2019: unresolved external symbol

Keith_Stewart
Beginner
3,363 Views
I am having problems with LNK2019 errors - I have a small Fortran sub that calls external functions in a third-party C obj file - the obj is 'COFF format for Microsoft compilers' (according to the documentation).

I am migrating from LF95 to IVF 12.0, and in LF95 I declared the C function as 'ML_External JM_Check' (JM_Check is the function), JM_Check as an integer, and compiled with -msvc - all worked fine.

What I have done so far is to include:

!DEC$ ATTRIBUTES C, EXTERN :: JM_Check
integer :: JM_Check

The sub compiles OK, but when I link I get:

error LNK2019: unresolved external symbol __jm_check referenced in function _GET_CHECKRESULT

where Get_CheckResult is my sub.

I am new to IVF and VS2010 (only just installed) and am using WiDE (Winteracter Development Environment) as this is what I have been using fro the past 15 yrs.

Any pointers on declarations, compiling and linking would be appreciated.
0 Kudos
1 Solution
JVanB
Valued Contributor II
3,363 Views
[fortran]! *********************************************************************
!
      SUBROUTINE Get_CheckResult3
!
      interface
        function JM_CHECK (FIn)
!DEC$ ATTRIBUTES STDCALL,DECORATE,ALIAS:"JM_Check" :: JM_CHECK
          integer :: JM_CHECK
          integer, value :: FIn
        end function JM_CHECK
      end interface
!
      integer :: iR
!
      iR = JM_Check(0)
!
      END SUBROUTINE Get_CheckResult3
!
! *********************************************************************
[/fortran]

View solution in original post

0 Kudos
10 Replies
Steven_L_Intel1
Employee
3,363 Views
There are a couple of ways to go for this.  One is to use the Fortran standard C interoperability features with an interface block.  So you'd replace the lines you quoted with:

interface
function JM_CHECK (arguments-go-here) bind (C,NAME="JM_Check")
USE, INTRINSIC :: ISO_C_BINDING
integer(C_INT) :: JM_CHECK
declarations of arguments go here
end function JM_CHECK
end interface

You would put in the names and types of the arguments as appropriate.  This is the approach I would recommend - it is standard-conforming and allows Fortran to verify that you are calling the function correctly.  I assume that  in the C code it is named JM_Check, with exactly that capitalization.  If not, change the NAME= value accordingly.

Another way is simpler but trading one extension for another.  Replace the ATTRIBUTES line with:

!DEC$ ATTRIBUTES DECORATE,ALIAS:"JM_Check" :: JM_CHECK

You don't need C as that is the default, though if you explicitly say C here then arguments are passed by value by default.  If you use the interface method, you can add the Fortran standard VALUE attribute to each argument declaration.
0 Kudos
Keith_Stewart
Beginner
3,363 Views
Steve,

Thank you for your response.

I included your first approach and the sub compiled and linked without error, but when I then uncommented the calls to my sub ('Get_CheckResult(1)', where 1 is the function argument) I get the LNK2019 errors again, as follows:

error LNK2019: unresolved external symbol _GET_CHECKRESULT referenced in function _MAIN__

... which I have not found before.

Do I need to make some reference elsewhere to 'decorate' the sub 'Get_CheckResult' or something similar?

Thanks,

Keith
0 Kudos
mecej4
Honored Contributor III
3,363 Views
You cite error messages but knowing the declarations of the symbols in the error messages is often essential in understanding the underlying causes.

You have not explicitly stated whether Get_CheckResult is a routine name in C or Fortran sources, but one may guess that the C name is "Get_CheckResult". To suppress the changing of this symbol to upper case by the Fortran compiler when it compiles the call from Fortran to this routine, you may provide an interface declaration, just as you did for the other symbol, "jm_check":

!DEC$ ATTRIBUTES DECORATE,ALIAS:"Get_CheckResult" :: GET_CHECKRESULT

0 Kudos
Keith_Stewart
Beginner
3,363 Views
Thank you for your post.  I have since found a small glitch where I had turned off linking of Get_CheckResult while working on another part of the prog, and forgot to turn it back on when I initially tried Steve's solution.

Get_CheckResult is a Fortran sub called from the main Fortran program, and when correctly linked the subsequent (Get_CheckResult) error was resolved - sorry if I wasted any of your time.

I have gone back to Steve's solution and created 2 small subs (Get_CheckResult1 (in file: Test1.f90) & Get_CheckResult2 (in file: Test2.f90)), with contents as follows:

! *********************************************************************
!
      SUBROUTINE Get_CheckResult1
!
!DEC$ ATTRIBUTES DECORATE,ALIAS:"JM_Check" :: JM_CHECK
!
      integer :: iR
!
      iR = JM_Check(0)
!
      END SUBROUTINE Get_CheckResult1
!
! *********************************************************************

When compiled the above (Test1.f90) I get the following error:

\test1.f90(14): error #7794: Only a function or subroutine subprogram may have the !DEC$ ATTRIBUTES directive DECORATE specifier.   [JM_CHECK]
!DEC$ ATTRIBUTES DECORATE,ALIAS:"JM_Check" :: JM_CHECK
--------------------------------------------------------------^
compilation aborted for \test1.f90 (code 1)



! *********************************************************************
!
      SUBROUTINE Get_CheckResult2
!
      interface
        function JM_CHECK (FIn) bind (C,NAME="JM_Check")
          USE, INTRINSIC :: ISO_C_BINDING
          integer(C_INT) :: JM_CHECK
          integer :: FIn
        end function JM_CHECK
      end interface
!
      integer :: iR
!
      iR = JM_Check(0)
!
      END SUBROUTINE Get_CheckResult2
!
! *********************************************************************

The above (Test2.f90) compiles without error, but when linked I get:

test2.obj : error LNK2019: unresolved external symbol _JM_Check referenced in function _GET_CHECKRESULT2
\SL.exe : fatal error LNK1120: 1 unresolved externals

Neither of the above subs are called from anywhere as yet, and are complied and linked separately to avoid conflict.

The object module I am linking is included and is described as 'COFF format for Microsoft compilers', and is the same file I have used (successfully) for some time with LF95.  I presume IVF can link external obj modules??

The supplier of the obj describes the function as JM_Check with the calling syntax as:
int _stdcall JM_Check( int iOptions ); (which I take as being in C - I have referenced it as in the above 2 examples, and it has worked for some years in LF95).

I have not applied any specific switches to the compile or link commands with IVF (I did not believe them to be necessary).

Any further comments or suggestions would be appreciated as a I really do not fully understand the differences in doing such calls in IVF and LF95 as yet (being an IVF novice).

Thank you.

0 Kudos
JVanB
Valued Contributor II
3,364 Views
[fortran]! *********************************************************************
!
      SUBROUTINE Get_CheckResult3
!
      interface
        function JM_CHECK (FIn)
!DEC$ ATTRIBUTES STDCALL,DECORATE,ALIAS:"JM_Check" :: JM_CHECK
          integer :: JM_CHECK
          integer, value :: FIn
        end function JM_CHECK
      end interface
!
      integer :: iR
!
      iR = JM_Check(0)
!
      END SUBROUTINE Get_CheckResult3
!
! *********************************************************************
[/fortran]
0 Kudos
Keith_Stewart
Beginner
3,363 Views
Thank you, very much... it all worked as per your example, and I can now edit my routines to work as intended.

I have other functions (within the same obj module) that I wish to use, and presume I should simply use the same sequence of 'function... declarations... end function' (within the interface declaration) to declare those functions - please advise if that is not the case, otherwise I will proceed with my newly-acquired knowledge.

Your assistance is very much appreciated, and has saved me from more pouring over the user guide and head-scratching.

Keith.
0 Kudos
Steven_L_Intel1
Employee
3,363 Views
I don't see any evidence here that STDCALL is appropriate in the interface block. If it is there but the routine you are calling is not a STDCALL routine, it will link ok but you'll corrupt the stack on each call.
0 Kudos
Keith_Stewart
Beginner
3,363 Views
Steve,

Thank you for your response.  I don't know if the routine is a STDCALL routine or not... all I have at the moment is:

The supplier of the obj describes the function as JM_Check with the calling syntax as:
int _stdcall JM_Check( int iOptions );

Does the reference to '_stdcall' mean that it is?  Or should I just be trying with and without, and how would I be able to check the stack for corruption?

Any assistance is appreciated, thank you.

Keith
0 Kudos
JVanB
Valued Contributor II
3,363 Views
I think Steve just missed the "_stdcall" in your reply #4. Coming from LF95 which was simply pitiable as far as interfacing to functions written in other languages, I think you will find ifort to be a big improvement. Look at the !DEC$ ATTRIBUTES documentation some more, as well as the mixed language programming stuff. ifort supplies copious examples of interfacing with STDCALL functions. In the INCLUDE path that the compiler sets up, there are modules that enable you to interface with Win32 API functions, along with the source code. You can look up the corresponding C prototypes in MSDN, you have thousands of examples to go with the available documentation. Probably you will want to write a module with interface blocks for the functions in the .obj file and then USE the module in the Fortran procedures that need it. Start with interface specifications for the functions you need right now; you can add to them later. Test them and make sure they work, there are a few more gotchas you will encounter but between documentation and questions in this forum you should get over them fairly readily.
0 Kudos
Keith_Stewart
Beginner
3,363 Views
Many thanks for the response and additional pointers - I will proceed with caution (as you have suggested) and aim to relate what you have provided to the user's guide.

I think I stayed with LF95 too long, given the improvements in IVF that are slowly becoming apparent to me.

Many thanks again.

Keith
0 Kudos
Reply