Unresolved externals: mixed Fortran/C++

Unresolved externals: mixed Fortran/C++

Stuart M.'s picture
Hi folks
I'm hoping somebody can shed some light on a bit of trouble I'm having. I have a solution comprising two projects, one Fortran and one C++. The C++ project builds as a DLL and is called by a Fortran executable. If I place the C++ project and associated files anywhere but in Visual Studio/Projects/MyProject I get the following error during the build: StuRSE.obj : error LNK2019: unresolved external symbol __imp__Initialize referenced in function _RUNRSE
StuRSE.obj : error LNK2019: unresolved external symbol __imp__PreSolve referenced in function _RUNRSE
StuRSE.obj : error LNK2019: unresolved external symbol __imp__RKSolve referenced in function _RUNRSE
StuRSE.obj : error LNK2019: unresolved external symbol __imp__PostSolve referenced in function _RUNRSE
Debug\FTLOADDS.exe : fatal error LNK1120: 4 unresolved externals
Initialize, PreSolve, RKSolve and PostSolve are all C++ subroutines that are called by Fortran using the following interface: Interface to Subroutine Initialize ( input_xml, output_xml, rsname ) !DEC$ Attributes C, DLLIMPORT, alias: "_Initialize" :: Initialize
INTEGER*1, Dimension (50):: input_xml, output_xml, rsname !new input files as arrays of chars instead of strings
!DEC$ Attributes REFERENCE :: input_xml
!DEC$ Attributes REFERENCE :: output_xml
!DEC$ Attributes REFERENCE :: rsname
END

Interface to Subroutine PreSolve ( num_var, vars )
!DEC$ Attributes C, DLLIMPORT, alias: "_PreSolve" :: PreSolve
Integer(kind=4) :: num_var
Real(kind=8), Dimension(num_var) :: vars
End

Interface to Subroutine PostSolve ( num_var, vars )
!DEC$ Attributes C, DLLIMPORT, alias: "_PostSolve" :: PostSolve
Integer(kind=4) :: num_var
Real(kind=8), Dimension(num_var) :: vars
End

Interface to Subroutine RKSolve ( time_step, rk_order, num_var, vars )
!DEC$ Attributes C, DLLIMPORT, alias: "_RKSolve" :: RKSolve
Integer(kind=4) :: num_var
Integer(kind=4) :: rk_order
Real(kind=8) :: time_step
Real(kind=8), Dimension(num_var) :: vars
End While I can resolve the external symbols by simply moving the files into Visual Studio/Projects/MyProjects I really don't want them in that particular directory. What I can't figure out is what to do resolve the external symbols once I've changed the relative position of the files... Is it likely to be hard-coded somewhere in the C++ code, or is it something I can control with project settings somehow? I'm still pretty green when it comes to this stuff so I just don't know how to tell. When the C++ code is in the "right" place everything works great, but as soon as I move it I'm stuck with the above errors. None of the additional libraries set in Linker refer to directories containing the code associated with errors. Maybe something in Additional Dependencies? Something to do with where the DLL is? Thanks very much!

7 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.
anthonyrichards's picture
It would appear that since you can resolve the symbols when you compile and link your Fortran project, the .LIB file containing the symbols exported from your DLL and which iscreated alongside your DLL is included into your Fortran project, thus telling it what symbols are available,and the Fortran compiler must be correctly generating the matching symbols. However, in order to run your Fortran executable, it must be told where to find the DLL. When running the executable from a directory, the DLL must either be located alongside the executable, OR the PATH environment variable must contain somewhere within it the path to the directory where the DLL is stored, OR in a Windows system directory where DLLs are normally to be found.

Starting with Windows server 2003 and Windows XP sp1, the default search path for DLLs is now
1) System locations (such as /windows/system32/)
2) The current directory
3) user-defined paths

Steve Lionel (Intel)'s picture

Anthony, the DLL does not enter into the linking behavior.

My guess is that the path to the DLL export library is not in a place where the project knows to look for it. I don't know how the project is identifying the library - if it's done by adding the .LIB as a source file to the Fortran project, it will use that specific location. Usually one makes the DLL project a "dependent" of the executable and Visual Studio will link in the export library from wherever it is created. Otherwise you can use the Linker property pages to specify the paths for additional library folders and name the library under 'Additional dependencies".

I would also ask that you convert the old, non-standard Microsoft Fortran PowerStation "interface to" syntax to standard Fortran 90 interface blocks.

Steve
Stuart M.'s picture

Gents,


I discovered that my Solution Properties->Project Dependencies had been wiped clean somehow; by restoring the dependency of my Fortran project on the C++ project the unresolved externals issue seems to have been dealt with. To respond to some of your comments, my Fortran project Linker specifies an Additional Library Directory, the Debug folder to which the C++ build outputs are sent. I also have a Post-Build Event that copies the DLL from this Debug directory to the Fortran project Debug directory, where the Executable for the overall build is output to. I've since tried deleting this copy command and the solution builds and executes just fine, presumably because of the Additional Library Directory setting in Linker. This is all starting to make more sense to me, so thank you both for the comments. Steve, could you please confirm for me that the following is the correct F90 syntax for the interface:

INTERFACE

SUBROUTINE PreSolve ( num_var, vars )

!DEC$ Attributes C, DLLIMPORT, alias: "_PreSolve" :: PreSolve

Integer(kind=4) :: num_var

Real(kind=8), Dimension(num_var) :: vars

END SUBROUTINEPreSolve

END INTERFACE


Thanks again guys!

Steve Lionel (Intel)'s picture

I suggest the following:

INTERFACE
SUBROUTINE PreSolve ( num_var, vars ) BIND(C,NAME="PreSolve")
!DEC$ Attributes DLLIMPORT :: PreSolve
Integer(kind=4), Value :: num_var
Real(kind=8), Dimension(num_var) :: vars
END SUBROUTINE PreSolve
END INTERFACE

Steve
Stuart M.'s picture
Quoting - Steve Lionel (Intel)
I suggest the following:

INTERFACE
SUBROUTINE PreSolve ( num_var, vars ) BIND(C,NAME="PreSolve")
!DEC$ Attributes DLLIMPORT :: PreSolve
Integer(kind=4), Value :: num_var
Real(kind=8), Dimension(num_var) :: vars
END SUBROUTINE PreSolve
END INTERFACE

Thanks Steve. Is there a particular reason why you prefer to use BIND(C,NAME="PreSolve")?
Steve Lionel (Intel)'s picture

If there's a standard way to say something, I prefer it. On the ALIAS - you include the leading underscore, which is correct on IA-32 but not on x64. You could fix that with a DECORATE attribute added, but I find the F2003 syntax preferable. Note that unlike ATTRIBUTES C, BIND(C) does not imply pass-by-value for scalars.

Steve

Login to leave a comment.