Unresolved external symbols

Unresolved external symbols

When I attempt to compile some legacy code I first get an error that the linker cannot find DFWIN.LIB (from CVF days). So I ignore that specific library. Then I get another file that's a problem too. So I walk down the line and ignore the libraries that it's looking for. Overall the following 5 libraries are ignored:

dfwin.lib, dfor.lib, libc.lib, dfconsol.lib, dfport.lib

I have the libraries the linker wants (from a computer that still has CVF 6.6c installed on it) and I added them into the project solution but this did not resolve the issue. It began to have duplicate definitions errors, between the CVF version of the file and IVF version of the file.

After ignoring all 5 libraries I get the following error below. To me it appears that the functions that PSWPTH is looking for are Fortran intrinsic functions and since this is legacy code these intrinsic functions must be from CVF.

Linking...
Creating temporary file "RSP1.rsp" with contents
[
 /OUT:"K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\EFPS6.exe" /INCREMENTAL:NO /NOLOGO /NODEFAULTLIB:"dfwin.lib" /NODEFAULTLIB:"dfor.lib" /NODEFAULTLIB:"libc.lib" /NODEFAULTLIB:"dfconsol.lib" /NODEFAULTLIB:"dfport.lib" /MANIFEST /MANIFESTFILE:"K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\EFPS6.exe.intermediate.manifest" /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"Debug/EFPS6.pdb" /SUBSYSTEM:CONSOLE kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /MACHINE:I386 "Debug/RSIDECNFG.obj" "Debug/PYGERA.obj" "Debug/fbxdrv.obj" "Debug/PyrolmLink.obj" "Debug/RSISPY.obj" "Debug/EFPSVersionInfo.res" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\GUIlink.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\slmpsw\\lsapiw32.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\PASSWD.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\GEN9306.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\TLEX.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\Flowsheet.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\SPYRO6.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\FIREBOX.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\LMFAC.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\CONVEC.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\NLSECURE.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\KIN9306.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\AUXILL.lib" "k:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Debug\\EFPS6_lib.lib"
]
Creating command line "Link @"K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Debug\\RSP1.rsp""

Link: executing 'link'
EFPS6_lib.lib(Pyrolm.obj) : warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/INCREMENTAL:NO' specification
LINK : warning LNK4098: defaultlib 'LIBCMT' conflicts with use of other libs; use /NODEFAULTLIB:library
NLSECURE.lib(PSWPTH.OBJ) : error LNK2019: unresolved external symbol _GETENVQQ@16 referenced in function _PSWPTH
NLSECURE.lib(PSWPTH.OBJ) : error LNK2019: unresolved external symbol _for_f90_index@20 referenced in function _PSWPTH
NLSECURE.lib(PSWPTH.OBJ) : error LNK2019: unresolved external symbol _for_len_trim@8 referenced in function _PSWPTH
NLSECURE.lib(PSWPTH.OBJ) : error LNK2001: unresolved external symbol _for_len_trim@8
NLSECURE.lib(PSWPTH.OBJ) : error LNK2001: unresolved external symbol _for_len_trim@8
NLSECURE.lib(PSWPTH.OBJ) : error LNK2019: unresolved external symbol __OtsMoveMinimum referenced in function _PSWPTH
NLSECURE.lib(PSWPTH.OBJ) : error LNK2019: unresolved external symbol __OtsFill referenced in function _PSWPTH
NLSECURE.lib(PSWPTH.OBJ) : error LNK2019: unresolved external symbol _SPLITPATHQQ@40 referenced in function _PSWPTH
K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\EFPS6.exe : fatal error LNK1120: 6 unresolved externals


EFPS6 - 9 error(s), 4 warning(s)

So I look into the static library containing PSWPTH.f and I see that it's using DFWIN and using DFLIB. I comment both of those out, recompile the *.lib file and reinsert it into the main project. I compile and get the following:

Linking...
Creating temporary file "RSP1.rsp" with contents
[
 /OUT:"K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\EFPS6.exe" /INCREMENTAL:NO /NOLOGO /NODEFAULTLIB:"dfwin.lib" /NODEFAULTLIB:"dfor.lib" /NODEFAULTLIB:"libc.lib" /NODEFAULTLIB:"dfconsol.lib" /NODEFAULTLIB:"dfport.lib" /MANIFEST /MANIFESTFILE:"K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\EFPS6.exe.intermediate.manifest" /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"Debug/EFPS6.pdb" /SUBSYSTEM:CONSOLE kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /MACHINE:I386 "Debug/RSIDECNFG.obj" "Debug/PYGERA.obj" "Debug/fbxdrv.obj" "Debug/PyrolmLink.obj" "Debug/RSISPY.obj" "Debug/EFPSVersionInfo.res" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\GUIlink.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\slmpsw\\lsapiw32.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\PASSWD.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\GEN9306.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\TLEX.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\Flowsheet.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\SPYRO6.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\FIREBOX.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\AUXILL\\Release\\AUXILL.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\LMFAC.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\CONVEC.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\NLSECURE.lib" "K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\KIN9306.lib" "k:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Debug\\EFPS6_lib.lib"
]
Creating command line "Link @"K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Debug\\RSP1.rsp""

Link: executing 'link'
EFPS6_lib.lib(Pyrolm.obj) : warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/INCREMENTAL:NO' specification
LINK : warning LNK4098: defaultlib 'LIBCMT' conflicts with use of other libs; use /NODEFAULTLIB:library
AUXILL.lib(PSWPTH.obj) : error LNK2019: unresolved external symbol _GETENVQQ@16 referenced in function _PSWPTH
AUXILL.lib(PSWPTH.obj) : error LNK2019: unresolved external symbol _GETMODULEFILENAME@16 referenced in function _PSWPTH
AUXILL.lib(PSWPTH.obj) : error LNK2019: unresolved external symbol _SPLITPATHQQ@40 referenced in function _PSWPTH
K:\\Pyrotec\\Software\\RSISimcon\\930680IVF\\RSIEFPSBASE\\Release\\EFPS6.exe : fatal error LNK1120: 3 unresolved externals


EFPS6 - 4 error(s), 4 warning(s)

I toggled DFLIB on and off. Now I get all 9 original errors regardless. Any help would be appreciated!

50 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

You must recompile all Fortran code - you are linking in objects or libraries built with CVF. That can't be mixed with Intel Fortran.

Steve - Intel Developer Support

OK, so I'm looking into this and it looks like those libraries I'm ignoring have the references for the calls that are missing.

For example: GETENVQQ is in DFPORT.lib which is now IFPORT.lib.

I tried adding USE IFPORT to PSWPTH.f, recompiling the library, then recompiling the project with the library in it.

No dice, still the same 9 errors =(

Steve, I've recompiled all the old CVF code in IVF then rebuilt all the libraries.

The AUXILL.lib (which contains PSWPTH.f) is built using IVF from the existing source code. Then AUXILL.lib is used in other project which has also been updated to IVF.

This solution was working in IVF before but now I'm having these particular issues. It's frustrating that something would work 2 weeks ago then not work now.

Thanks for your advice!

You are still linking in libraries compiled with CVF. Maybe you're not pulling in your rebuilt library.

Steve - Intel Developer Support

What I don't get is how can AUXILL.lib compile and build fine (with PSWPTH.f and those GETENVQQ and SPLITPATHQQ functions in it), yet when I add the *.lib into another IVF project solution I get the errors. So confusing!

I opened up an old CVF *.dsw project and converted all the source files over to IVF in a *.vfproj. Then in the *.vfproj environment I recompile and build AUXILL.lib.

Then I take that AUXILL.lib and add it into another *.vfproj. That's when I get these errors.

You must be right about the CVF/IVF mixing. I've just got to figure out where it's occurring. If AUXILL.lib is building properly then it must be something with the other *.vfproj....

I think I know what the problem is. It must be NLSECURE.lib that is causing the errors. I'll have to find the source code for that and recompile it in IVF.

Nope, this isn't it. Another project in IVF (same source code w/ exception of the two new files I've created) compiles and builds just fine with NLSECURE.lib.

See my reply to another user here - you have a similar problem. Do what I asked there and attach the build log (don't insert it inline, it will be big) You might even want to ZIP it first.

Steve - Intel Developer Support

You have references to CVF linkage of Fortran run-time functions. Those probably come from the libraries (you could check where those functions reside). This raises the possibility those libraries were made to require Compaq Fortran (which went off support over 10 years ago).
Besides switching to dynamic linkage, as Steve said, you will probably have to try building everything with /iface:cvf until you can get the libraries remade. That still would likely fail if the required run-time functions are actually from CVF.

There are other oddities, however. PSWPTH in NLSECURE.LIB seems to be the source of all of them and from looking at the symbols it references, this one souce was compiled with CVF (not just ifort with /iface:cvf.) You need to recompile it with Intel Fortran.

Steve - Intel Developer Support

Unfortunately I don't have the original source code for NLSECURE.lib so it appears I might be hosed.

The big problem is that I do not have the source for two static libraries that are CVF-era (NLSECURE.lib and another one).

Yes, that is a problem. You won't be able to solve that by juggling libraries. The best you can do is build a DLL from them, using a .DEF file to export the routine names you want. You'd have to do this with CVF to satisfy the external references (link to the static form of the CVF libraries). Then you could call the entries in the DLL as long as you weren't trying to share I/O units or pass deferred-shape arrays.

Steve - Intel Developer Support

It frosts me that in one case the compiler accepts a set of source code in one project, then in another project containing the same source code the compiler barfs and spits out these unresolved external symbol errors.

How can the compiler complain about unresolved external symbol _GETENVQQ@16 (PSWPTH.obj) in one instance and then not complain about it in another instance?

The compiler isn't barfing - those messages are coming from the linker.

(In #5 you say "What I don't get is how can AUXILL.lib compile and build fine...".

When you build a library the librarian utility normally just builds a simple archive of all the bits of object code that were generated from the source code in the project. The librarian utility (which on Windows is actually the linker moonlighting for some extra cash on the side) doesn't go through each piece of object code and make sure that it can satisfy all the various symbol references - in many cases that would defeat the purpose of building a library.

It is not until the final link stage (when the actual EXE or DLL is built) that the linker must resolve all the symbol references in the bits of object code that are being linked together.

So building a lib is not a sufficient test that all is well.

If you had two projects that were both generating EXE's (or DLL's), and one was failing while the other succeeded, then that's a different story, one that would explore differences between the projects.)

Here is an example of one problem I am having linking C++ files and Fortran files:

I have a GUILink_lib that contains a header file and two C++ files.

In the GUILinkC.c file (under the GUILink_lib project) there is a function called GUIDay with code as follows:

/*
* Function name: GUIDay
* Description : In a multi-day run, this is called with the number of the
* current simulation day, starting at day 1. In a single day
* simulation, it must also be called with argument 1.
* Arguments I: int DayNumber - the number of the day.
*/
void
GUIDay(int DayNumber)
{
GUICurrentDay = DayNumber;
}

Then in the Fortran *.lib project, X_lib, there is GUILinkF.f which defines a subroutine GUIDAY that relays to the C++ function above, with code as follows:

C
C Function name: GUIDAY
C Relays to : GUIDay(int DayNumber)
C Description : Assign the number of the day currently being processed.
C Arguments : INTEGER*4 DAY - the day number of the current run.
C
SUBROUTINE GUIDAY(DAY)

IMPLICIT NONE

INTEGER*4 DAY

INTERFACE
SUBROUTINE GUIDAYC(DAY)
!DEC$ ATTRIBUTES C, ALIAS:'_GUIDay' :: GUIDAYC
INTEGER*4 DAY
END SUBROUTINE GUIDAYC
END INTERFACE

CALL GUIDAYC(DAY)

END

The project is set up as follows:

MainProgram (Fortran *.exe)
X_lib (Fortran *.lib)
GUILink_lib (C++ *.lib)
SlmpswC_lib (C++ *.lib)

The two C++ projects are added to the overall project by choosing Add New Project -> Win32 -> Win32 Project. These two static libraries are compiled first, followed by X_lib then MainProgram.

After compilation the linker has unresolved external symbols from the Fortran GUILink.f file to the GUILink.c file.

Any thoughts? I understand that in this new environment C++ and Fortran files must be compiled separately in different projects but that a solution can contain multiple projects in a user-specified order. I think I have set this up properly.

Is there an issue with the declaration calling convention?

Are you actually using C or C++? If the latter, then you need extern "C" on the definition. I think though that Microsoft's C++ compiler sanely regards files ending in .c as C files by default.

Perhaps this is what you have done - but rather than setting compilation order you should be setting project dependencies (for example, perhaps the MainProgram exe depends on X_lib). An appropriate build order is an outcome of having the dependencies set correctly, manual ordering beyond that is simply for build convenience. The process for setting dependencies is similar to that for build order (it is simply a different tab on the same dialog) - right click on a project in the solution explorer and select "Project Dependencies".

If static libraries are part of a dependency chain then you can also decide whether you want to archive all the subordinate libraries into one big library as part of the build step. To do this, in the project properties set Librarian > Link Library Dependencies to Yes (a similar Link Library Dependencies setting exists for Fortran exe's and dll projects, but it is set to Yes by default). If you don't do this, then the top level exe or DLL needs to explicitly have all the subordinate libraries in its list of dependent projects.

If you are using VS2010 and have C++ project that depends on a Fortran library, then you may (will?) need to explicitly list the name of the Fortran library in the linker properties of the C++ project.

The Fortran 2003 standard introduced new features into the language to assist with "inter-operating" between Fortran and C. If you use these new features, the source code connection between Fortran and C will be portable and considerably more robust. I'd rewrite your interface block to be:

[fxfortran] INTERFACE
SUBROUTINE GUIDAYC(DAY) BIND(C, NAME='GUIDay')
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT
IMPLICIT NONE
INTEGER(C_INT), INTENT(IN), VALUE :: DAY
END SUBROUTINE GUIDAYC
END INTERFACE
[/fxfortran] If the subroutine in that interface was renamed to GUIDAY, popped into a module that was then used where appropriate you could eliminate the need for your Fortran wrapper subroutine. INTERFACE
SUBROUTINE GUIDAYC(DAY)
!DEC$ ATTRIBUTES C, ALIAS:'_GUIDay' :: GUIDAYC
INTEGER*4 DAY
END SUBROUTINE GUIDAYC
END INT

      INTERFACE

         SUBROUTINE GUIDAYC(DAY) BIND(C,NAME='GUIDay')

            USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT

            IMPLICIT NONE

            INTEGER(C_INT), INTENT(IN), VALUE :: DAY

         END SUBROUTINE GUIDAYC

      END INTERFACE

ERFACE

I assembled a self-contained example from the pieces that you provided. I added a trivial main program in C, and it works as expected (see below). Therefore, any problems that you still have are related to mismatched calling conventions, especially concerning libraries obtained from others and containing routines required to be called with stdcall protocol, and complications in your build procedure.

The Fortran part: exactly as you gave it.
The C function: Add to what you gave:

extern int GUICurrentDay;

The C main program:

#include 
int GUICurrentDay=123456789;

extern void GUIDay(int);
main(){

   printf("GUICurrentDay = %dn",GUICurrentDay);

   GUIDay(987654321);

   printf("GUICurrentDay = %dn",GUICurrentDay);

   }

Compile and link:

T:lang> ifort /MD /O2 guiday.f

T:lang> icl /O2 /MD uguiday.c guiday.obj guidayc.c
Results:

T:lang>uguiday

GUICurrentDay = 123456789

GUICurrentDay = 987654321

Hi Ian,

Oops, what I meant by compiling order really is Project Dependencies. I set up the solution such that the Fortran exe MainProgram is dependant on Fortran static library x_lib and x_lib is in turn dependant on two other C++ static libraries in the same project. I assume that the projects are compiled in order of dependency.

I'll check on the status of Link Library Dependencies and make sure it is set to Yes.

I am using VS2008 and fairly new to programming.

So what you are recommending are two options:
1)Modify the INTERFACE block as you suggest and see if that resolves the Fortran/C linking issue
2) I rename theFortran GUIDAYCsubroutine to GUIDay, and then instead of using an INTERFACE command, instead put the subroutine into a MODULE block, then use that MODULE as needed. What is the syntax for using a MODULE block?

Thanks for the help!

I agree with you - the problem is stemming from the calling conventions. This is old CVF 6.6c legacy code that I am trying to update to IVF and MS2008+ environment. Besides some basic editing and programming my skills in this area are limited. Especially when it comes to dealing with the nuances of compilers and IDEs. If I had a better understanding/grasp of exactly what the calling conventions are doing perhaps that might help me to resolve this particular issue. Thanks!

I'd strongly recommend (1).

(2) can perhaps be left for a rainy day, certainly one that comes after you getting a working build, though note that the general use of modules is something you should get up to speed with as soon as possible if you will be continuing to program in Fortran.

Compiler options (C and Fortran) can affect calling conventions; and the symbol names in error messages can give good hints as to where things are going wrong. Detailing both in your posts will help. Attaching the buildlog is even better as it gives that detail plus some insight into whether static libraries are being correctly included in the link step for a later project.

OK, as soon as I am able to get back to the programming swing of things I'll make the changes and see what happens. Thanks for your help!

Hi Ian, I'm reading up on Fortran interoperability with C thanks to your original suggestion. I have plenty of C to Fortran interfaces I need to update. Hopefully this starts to flesh out the errors in the build.

I have about 41 subroutines associated with the GUI that I have to apply modifications for C++/Fortran operability. This is gonna be fun!

Is the following code going to work? I'm mainly concerned with the declarations of integer, character and real variables and how they are passed/referenced between Fortran and C++. I'm looking at some online references and examples for interoperability code and I know that there are limitations. For example, for operability the length type parameter has to be omoitted or be specified by an initialization expression equal to one. So then is a variable defined as CHARACTER*120 x in a Fortran subroutine not passable to a C++ subroutine where the character variable is defined as char *x??

Here is what I have below...

In Fortran:

SUBROUTINE GUIINI(x, y)
IMPLICIT NONE
CHARACTER*120 x
CHARACTER*125 a
CHARACTER*4 y
INTEGER*4 b

INTERFACE
SUBROUTINE GUIINIC(x, y), BIND(C, NAME='GUIInit')
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT, C_CHAR
IMPLICIT NONE
INTEGER(C_INT) :: b
CHARACTER(C_CHAR) :: x
END SUBROUTINE GUIINIC
END INTERFACE

END SUBROUTINE

SUBROUTINE GUINAP(FEED, VALUES)
IMPLICIT NONE
INTEGER*4 FEED
REAL*4 VALUES(*)

INTERFACE
SUBROUTINE GUINAPC, BIND(C, NAME='GUINaphtha')
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT, C_FLOAT
IMPLICIT NONE
INTEGER(C_INT) :: FEED
REAL(C_FLOAT) :: VALUES
END SUBROUTINE
END INTERFACE

END SUBROUTINE

In C++:

void
GUIInit(char *x, int y)
{
char ghost[256];
FILE *OutFile;

memcpy(GUICase, x, (sizeof(char) * (strlen(x) + 1)));
...
}

void
GUINaphtha(int FeedNumber, float *Values)
{
...
}

The fortran interface for a char parameter on the C side must be length 1. If you are passing a string, rather than a single character, then you declare the fortran CHARACTER argument that corresponds to the char* parameter as an explicit shape or assumed size array.

(When declaring such an interface in Fortran be mindful that the default type parameter for CHARACTER variables is the LEN parameter, not the KIND parameter. So CHARACTER(C_CHAR) is equivalent to CHARACTER(LEN=C_CHAR), not the intended CHARACTER(KIND=C_CHAR). This is a mistake that I only make myself a couple of dozen times an hour.)

Normally the actual argument that corresponds to an array dummy argument must also be an array. But there are some exceptions - and importantly one of them is for KIND=C_CHAR CHARACTER arguments (the exception also applies to default kind character, but in ifort's case the default kind is also KIND=C_CHAR). In this case the sequence of characters in the string that is the actual argument get associated with the single character elements of the array dummy argument in a sane way.

(In summary - while the declaration of the interface needs to be length 1, you can still pass strings (or the storage for strings) from Fortran to C with length greater than one.)

When you are passing strings (or the storage for a string) from C to Fortran it is messier - the string comes in as an array. Before you can use the familiar Fortran string intrinsics you typically need to associate or copy the array to a CHARACTER scalar with length > 1.

From your example I infer that the character x argument in GUI is to receive data from the C side (??). At the moment there are multiple issues - you are passing a length one scalar (one byte...) and by the looks of it you are trying to poke a whole C string into it (many bytes?). Further, the number of bytes to copy is determined by referencing the length of a string that is yet to be defined. A typical pattern here is to pass the string (with the argument declared as an array as discussed above) along with the length of storage that's available for that string, with the called function then being careful to only copy data into that available length. Perhaps clarify your intent for further advice.

Be mindful that C's default is to pass by value. Your integer arguments on the fortran side are missing the VALUE attribute. Some of your argument names in their type declarations don't match those in the argument list. Your Fortran subroutines don't show any calls to the procedures defined by the interface blocks either.

(Style comments - (particularly for new code...) try and get out of the habit of using numeric type declarations with the typename*kind syntax (i.e INTEGER*4). That's not standard Fortran syntax (though it is a very common extension) - instead use typename(kind) (i.e. INTEGER(4)). You are already doing this in the interface blocks - might as well be consistent. For character variables the CHARACTER*len form is deprecated in recent standards - consider using CHARACTER(len), being mindful of the len/kind issue mentioned above. Good practice beyond use of the correct syntax is to then specify your kinds via a parameter rather hard coding the value 4.

Consider adding INTENT spec's to your argument declarations, including those in the interface blocks. It's a simple but effective method of in-source documentation (particularly for those not intimately familiar with your code, such as those reading snippets posted in a forum, or yourself in two weeks time...) and helps the compiler's ability to do error checking too.)

(Your C++ is also missing extern "C" (perhaps it's flagged for the encompassing scope)?)

After examining the code I believe the intent is to create a Fortran call to a C++ subroutine as the code is written in C++ instead of Fortran, perform operations in C++, then pass the results back into Fortran. So I need to be able to handle both directions for passing information.

One question: Does the call to the C++ code defined in the Fortran INTERFACE block have to occur after and outside the INTERFACE block? Or does it need to be called inside the SUBROUTINE block that's inside the INTERFACE block? Or outside that SUBROUTINE block but inside the INTERFACE block?

Additionally, if my understanding of what you said regarding the Fortran/C++ interface is correct, I'd like to summarize the following regarding passing character variables from Fortran to C++:

To pass a string from Fortran to C/C++ and then back into Fortran from a Fortran call, I would need to setup the following code:

In C++ (linkc.c):

CPlusProgramLink(char* stringc)
{...
stringc=stringc // "in life"
...}

In Fortran (linkf.f):

SUBROUTINE LINKPROGRAMF(STRING1) !STRING1 = "Tomorrow you will"
CHARACTER(120) STRING1
CHARACTER(30) STRING2
...
STRING2="find renewed vigor"
STRING1=STRING1 // STRING2
INTERFACE
SUBROUTINE LINKFPROGRAMC(STRINGC), BIND(C, NAME='CPlusProgramLink')
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_CHAR
IMPLICIT NONE
CHARACTER(KIND=C_CHAR, LEN=120) :: STRING2
END SUBROUTINE
END INTERFACE

CALL LINKFPROGRAMC(STRING1)

!At this point STRING1 = "Tomorrow you will find renewed vigor in life"

Is what I coded above right??

Also I am trying to understand the extern "C" comment you are making; bear with me, I'm not familiar with this as I have not programmed much.

There are four files associated with this GUI code:

- GUILink.h
- GUIComponents.c
- GUILinkC.c
- GUILinkF.f

At the beginning of GUILinkC.c there are standard system #include statements followed by a:

#include "GUILink.h"

GUILink.h file has following format:

#ifndef _GUILINK_H
#define _GUILINK_H
... (code containing #defines, extern const char declarations, etc.)
#endif _GUILINK_H

Is this reference correctly coded? GUILink.h is a C++ header file so do I even need an extern "C" construct in GUILinkC.c for this??

There are a bunch of mistakes in your code sample.It looks like you are interfacing with C, not C++ (*.c vs *.cpp).Neither C nor C++ has a concatenation operator, but there is a strcat() function in C and strstream.h in C++. These require ASCII NUL termination on input to work sensibly and the output also gets a NUL. In your Fortran code the input variable STRING1 has a fixed LEN of 120. Many think it better to get the LEN from the caller and test to make sure that it's long enough, as I do below. Also your interface block is out of place: it must be up among the specification statements of subroutine LINKPROGRAMF. Your interface body has the wrong name (STRING2 instead of STRINGC) for the declaration of the dummy argument and it has a non-unit LEN.I have fixed that up and made it an assumed-size array. Fortran does not trim strings on concatenation so the line
STRING1=STRING1//STRING2
actually does nothing. Also the C function will need ASCII NUL termination so I fixed that up. Finally Fortran will have to search for the NUL to know how long C thinks the string passed back actually is. Written as a Fortran main program and a C function I get:

#include 
CPlusProgramLink(char* stringc)

{

   strcat(stringc," in life");

}


      program test

         IMPLICIT NONE

         character(120) STRINGin

         STRINGin = 'Tomorrow you will'

         call LINKPROGRAMF(STRINGin)

      end program test
      SUBROUTINE LINKPROGRAMF(STRING1)      !STRING1 = "Tomorrow you will"

         IMPLICIT NONE

         CHARACTER(*) STRING1

         CHARACTER(30) STRING2

         integer, parameter :: string1len = 120

         INTERFACE

            SUBROUTINE LINKFPROGRAMC(STRINGC)                           &

     &         BIND(C, NAME='CPlusProgramLink')

               USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_CHAR

               IMPLICIT NONE

               CHARACTER(KIND=C_CHAR, LEN=1) :: STRINGC(*)

            END SUBROUTINE

         END INTERFACE
         if(len(STRING1) < string1len) then

            write(*,'(3(a,i0))') 'LEN(STRING1) = ',                     &

     &      len(STRING1),' < ',string1len,'.  Aborting'

         end if

         STRING2="find renewed vigor"

         STRING1=trim(STRING1) // ' ' // trim(STRING2) // achar(0)
         CALL LINKFPROGRAMC(STRING1)

         write(*,'(a)') STRING1(1:index(STRING1,achar(0))-1)
      end subroutine LINKPROGRAMF
!This looks poorly formatted but copy to clipboard seems to work OK.

Thanks a bunch for showing me the ins and outs of setting up the interface. I hastily put together that example and I haven't programmed in C (1 college course) in 11 years. My Fortran is fairly basic as well. I look up what I need when I need it and I don't need to program very often at all =p one more thing... what is ASCII NUL termination and how did you fix that up??

EDIT: I think I understand what you mean by ASCII NUL termination.
Basically there is no equivalence statement when you use strcat()
function (i.e. string2 = strcat(string1," in life"); is not a proper statement. So you simply code the strcat(string1," in life"); as such.

EDIT2: Why is it a problem if the length of string1 is less than the length specified in stringllen?? Shouldn't it be a problem if the length of string1 is longer then stringllen??

I am getting the same error on all of my Fortran INTERFACE SUBROUTINE declaration lines.

For example:

Line 50: INTERFACE
Line 51: SUBROUTINE GUIINIC(NAME, VER); BIND(C, NAME='GUIInit')

Error 1 error #5082: Syntax error, found END-OF-STATEMENT when expecting one of: :: / C:\...\GUILinkF.f 51

Any ideas as to what is wrong with the syntax??

You have a semicolon before BIND. Take it out.

Steve - Intel Developer Support

Thanks...

I originally had commas instead of semicolons before BIND but that was giving me the following error:

Error 1 error #5082: Syntax error, found ',' when expecting one of: ; K:\Pyrotec\Software\RSISimcon\930680IVF\EFPSBaseLib\GUIlink\GUILinkF.f 51

Now that I don't have any characters in between these errors are gone. I got led down the wrong path by several online references that had commas or semicolons before the BIND statement.

BIND can be a statement, but in this context it's sort of an attribute of the subroutine declaration. As a statement, it can be used only to specify variables and commons, not procedures, derived types or enumerators.

Steve - Intel Developer Support

Steve, thanks for the clarification on BIND.

BTW I'm so happy now, the code is now compiling properly after I made the modifications suggested by several of the posts above to the old legacy Fortran/C interfacing code.

Thanks everyone for your help =)

EDIT: I jumped to conclusions too fast... now I'm back to the unresolved external symbol problem again for all Fortran/C interfaces...

Error 1 error LNK2019: unresolved external symbol _GUIInit referenced in function _GUIINI EFPS68_lib.lib(GUILinkF.obj)

The linker is unable to find the C subroutines defined by the INTERFACE blocks =(

I figured out the problem.

I had to set Link Library Dependencies to 'Yes' Under project Configuration Properties => Librarian => Link Library Dependencies.

Now I have some new errors:

Error 135 error LNK2005: _fclose already defined in LIBCMTD.lib(fclose.obj) MSVCRTD.lib(MSVCR90D.dll)
Error 136 error LNK2005: _fprintf already defined in LIBCMTD.lib(fprintf.obj) MSVCRTD.lib(MSVCR90D.dll)
Error 137 error LNK2005: _fopen already defined in LIBCMTD.lib(fopen.obj) MSVCRTD.lib(MSVCR90D.dll)
Error 138 error LNK2005: _sprintf already defined in LIBCMTD.lib(sprintf.obj) MSVCRTD.lib(MSVCR90D.dll)
Error 139 error LNK2005: _free already defined in LIBCMTD.lib(dbgfree.obj) MSVCRTD.lib(MSVCR90D.dll)
Error 140 error LNK2005: _realloc already defined in LIBCMTD.lib(dbgrealloc.obj) MSVCRTD.lib(MSVCR90D.dll)
Error 141 error LNK2005: _malloc already defined in LIBCMTD.lib(dbgmalloc.obj) MSVCRTD.lib(MSVCR90D.dll)
Error 142 error LNK2005: _printf already defined in LIBCMTD.lib(printf.obj) MSVCRTD.lib(MSVCR90D.dll)
Error 143 error LNK2005: ___iob_func already defined in LIBCMTD.lib(_file.obj) MSVCRTD.lib(MSVCR90D.dll)
Error 144 error LNK2005: _strtok already defined in LIBCMTD.lib(strtok.obj) MSVCRTD.lib(MSVCR90D.dll)
Error 145 error LNK2005: _strchr already defined in LIBCMTD.lib(strchr.obj) MSVCRTD.lib(MSVCR90D.dll)
Error 146 error LNK2005: "private: __thiscall type_info::type_info(class type_info const &)" (??0type_info@@AAE@ABV0@@Z) already defined in LIBCMTD.lib(typinfo.obj) MSVCRTD.lib(ti_inst.obj)
Error 147 error LNK2005: "private: class type_info & __thiscall type_info::operator=(class type_info const &)" (??4type_info@@AAEAAV0@ABV0@@Z) already defined in LIBCMTD.lib(typinfo.obj) MSVCRTD.lib(ti_inst.obj)

Any ideas?? It's amazing how stubborn the linker can be. Of course it would help immensely if I did understand the ins and outs of all these project options.

You have "Mixed C Library Syndrome". Make sure that all the projects in the solution, and any outside library you link against, are compiled using the same setting for run-time libraries. LIBCMTD means one project is set to use the static debug libraries (probably the Fortran project as that is default), and MSVCRTD means another is set to use the DLL libraries (probably C/C++ as that is its default). In Fotran, this is under Libraries, in C++ under Code Generation.

Steve - Intel Developer Support

Thanks!! I changed the C++ to use the static run-time libraries and that resolved the issue. Now I'm down to 10 errors remaining. Getting closer to the light at the end of the tunnel...

OK so now I've come complete circle and I have the same 6 unresolved externals that have plagued me from the very beginning... suffice to say I'm getting extremely frustrated with this. Are there any workarounds for the following functions below?? I would rather hard code substitutes for these functions in then to try and tinker around with the IDE anymore.

Generating non-SAFESEH image.
EFPS68_lib.lib(PSWPTH.OBJ) : error LNK2019: unresolved external symbol _GETENVQQ@16 referenced in function _PSWPTH
EFPS68_lib.lib(PSWPTH.OBJ) : error LNK2019: unresolved external symbol _for_f90_index@20 referenced in function _PSWPTH
EFPS68_lib.lib(PSWPTH.OBJ) : error LNK2019: unresolved external symbol _for_len_trim@8 referenced in function _PSWPTH
EFPS68_lib.lib(PSWPTH.OBJ) : error LNK2001: unresolved external symbol _for_len_trim@8
EFPS68_lib.lib(PSWPTH.OBJ) : error LNK2001: unresolved external symbol _for_len_trim@8
EFPS68_lib.lib(PSWPTH.OBJ) : error LNK2019: unresolved external symbol __OtsMoveMinimum referenced in function _PSWPTH
EFPS68_lib.lib(PSWPTH.OBJ) : error LNK2019: unresolved external symbol __OtsFill referenced in function _PSWPTH
EFPS68_lib.lib(PSWPTH.OBJ) : error LNK2019: unresolved external symbol _SPLITPATHQQ@40 referenced in function _PSWPTH
Debug\RSISPYEXE.exe : fatal error LNK1120: 6 unresolved externals

I fail to see where this project with regard to PSWPTH.OBJ is attempting to link with old CVF libraries. Firstly, PSWPTH.f is being recompiled to generate a NEW *.obj file. And I'm sorry, but the linker is obviously searching the correct *.lib files...

    Searching C:\Program Files\Intel\Composer XE 2011 SP1\compiler\lib\ia32\libifcoremdd.lib:
    Searching C:\Program Files\Intel\Composer XE 2011 SP1\compiler\lib\ia32\libifportmd.lib:

...and it finds other external references in these files...

Found _for_trim
        Referenced in RSISPY.obj
        Referenced in RSIDECNFG.obj
        Loaded libifcoremdd.lib(libifcoremdd.dll)

...and IT EVEN FINDS THE EXACT EXTERNAL SYMBOLS that supposedly are unresolved for PSWPTH.OBJ referenced in other object files...

 Found _for_len_trim
        Referenced in RSISPY.obj
        Referenced in RSIDECNFG.obj
        Referenced in EFPS68_lib.lib(GUILinkF.obj)
        Loaded libifcoremdd.lib(libifcoremdd.dll)

Found _for_f90_index Referenced in EFPS68_lib.lib(fbxdrvrsi.obj) Referenced in EFPS68_lib.lib(SPYRIN.obj) Loaded libifcoremdd.lib(libifcoremdd.dll)

...so HOW ON EARTH does this linker NOT KNOW that _for_len_trim is referenced in PSWPTH.obj AND loaded in libifcoremdd.lib when it has already been done for other ojbect files?!!?!??!?!?

I run /dumpbin /linkermember /out:"output filename" and get the following information...

libifcoremdd.lib
1414 public symbols
...
1A100 __imp__for_f90_index
1A100 _for_f90_index
...
17AD0 __imp__for_len_trim
17AD0 _for_len_trim
...
17F __imp__for_f90_index
...
17F _for_f90_index
...
127 __imp__for_len_trim
...
127 _for_len_trim

There has to be a solution for this... ... ...

It looks like you are trying to mix /iface:cvf references with default ones. I doubt that is supported. I think it has been reiterated here that any old objects compiled with references to CVF or VS6 libraries must be rebuilt with recent compilers and ifort library replacements for DVF/CVF ones.

I understand that old objects compiled with references to CVF must be recompiled. I am recompiling this file in VS2008 with C#/C++ 2008 and IVF 12.1 and making a new *.obj file.

In PSWPTH.FOR I commented out DFWIN and DFLIB and replaced them with their IVF counterparts.

c USE DFWIN !04-10-2012
c USE DFLIB !04-10-2012
USE IFWIN !04-10-2012
USE IFCORE !04-10-2012
USE IFPORT !04-10-2012
USE IFQWIN !04-10-2012

Also I found that I had to add DFWIN.LIB and DFLIB.LIB to the "Ignore Specific Library" under "Librarian -> General" in the Fortran static library project and under "Linker -> Input" in the main Fortran executable even after commented out those lines. Somehow the project is still looking for them.

I have "Calling Convention" set to "Default" under "Fortran -> External Procedures" for both Fortran projects as well. Switching the calling convention from "Default" to "/iface:cvf" does not affect the linking errors one bit.

Right now I created a new Fortran *.f90 file and coded the exact same lines from PSWPTH.FOR into them, removed the old PSWPTH.FOR from the build and added in this new file with the same contents. Who knows, maybe the IDE will get tricked! Hahaha

Tim, I still don't understand why no one can give me an explanation of why the _for_len_trim is found referenced in GUILinkF.obj but not in PSWPTH.obj, when both files are part of the same project and both are being recompiled in the new IDE.

The (example) missing symbol isn't _for_len_trim - it's _for_len_trim@8.
That @8 suffix on that internal compiler function name is strong
(irrefutable?) evidence that there's object code from CVF still being
fed into the final link.

You shouldn't need to have those ignore specific library settings. That's more evidence that object code from CVF is still around.

The errors come via a library (EFPS68_lib.lib) - are you sure that the specific lib file being referenced is a lib file that is being built from object code files only made by ifort, and not some hangover from CVF days?

Post (attach) your build logs - the one for the library and the one for the final exe or DLL that actually generates the errors.

Hi Ian, here's the build log. I just don't understand how object code from CVF is lingering around. I've recompiled the same sources successfully in the new IDE in separate solutions. But this master solution containing all the Fortran and C++ code is killing me.

Attachments: 

AttachmentSize
Download buildlog.zip28.44 KB

That's the build log for the final link - could you also please attach the log for a rebuild-all of...

"K:\Pyrotec\Software\RSISimcon\930680IVF\RSISPY\EFPS68_lib\Debug\EFPS68_lib.lib"

(Presumably that's built by a different project in your master solution?)

Hi Ian, yes you are correct. That static library is built by another project in the master solution. I have a separate solution for the static library as well which compiles and builds fine. I'll attach that build log shortly.

Here is a reduced build log for EFPS68_lib:

Build Log

Build started:
Project: EFPS68_lib, Configuration: Debug|Win32

Output

Compiling with Intel Visual Fortran Compiler XE
12.1.1.258 [IA-32]...

ifort /nologo /debug:full /Od /I"C:\~root\base\Include"
/I"C:\~root\base\K~" /I"C:\Program Files\Intel\Composer XE
2011 SP1\compiler\lib\ia32" /module:"Debug\"
/object:"Debug\" /Fd"Debug\vc90.pdb" /traceback
/check:bounds /libs:dll /threads /dbglibs /4Yportlib /c /extfor:F /Qvc9
/Qlocation,link,"c:\Program Files\Microsoft Visual Studio
9.0\VC\\bin" "C:\~root\base\T~\EXAMPLE.F"

...

...

Creating library...

Creating temporary file "RSP1.rsp" with contents

[

/OUT:"Debug/EFPS68_lib.lib"
/LIBPATH:"C:\Program Files\Intel\Composer XE 2011
SP1\compiler\lib\ia32" /NOLOGO /NODEFAULTLIB:"nlsecure.lib"
/NODEFAULTLIB:"passwd.lib" /NODEFAULTLIB:"dfwin.lib"
/NODEFAULTLIB:"dfor.lib" /NODEFAULTLIB:"libc.lib"
/NODEFAULTLIB:"dfconsol.lib" /NODEFAULTLIB:"dfport.lib" ...

"Debug\PSWPTH.obj"

...

]

Creating command line "Lib @"C:\~root\R~\EFPS68_lib\Debug\RSP1.rsp""

xilib: executing 'lib'

Debug\CONVER.obj : warning LNK4042: object specified more
than once; extras ignored

PSWPTH.obj : warning LNK4006: _PSWPTH already defined in
NLSECURE.lib(PSWPTH.OBJ); second definition ignored

PSWPTH.obj : warning LNK4221: no public symbols found;
archive member will be inaccessible

PYTIME.obj : warning LNK4006: _PYTIME already defined in
NLSECURE.lib(PYTIME.OBJ); second definition ignored

PYDATE.obj : warning LNK4006: _PYDATE already defined in
NLSECURE.lib(PYDATE.OBJ); second definition ignored

PYDATE.obj : warning LNK4221: no public symbols found;
archive member will be inaccessible

EFPS68_lib - 0 error(s), 14 warning(s)

I think I see the problem now. PSWPTH is already defined in NLSECURE.lib and this library is most definitely compiled in CVF; I do not have the source for this file so I cannot recompile it in the new environment. The compiler is choosing to ignore the source of PSWPTH in PSWPTH.f90 and stick with the one in NLSECURE.lib. I thought that by ignoring this library in the compiler options that I would be able to workaround it. Perhaps I will exclude NLSECURE.lib from the build entirely and see if that resolves the issue and hope that the program is able to run fine without it.

Looks like that did the trick to allow the source to completely compile without any problems.

Now to check out the functionality...

Leave a Comment

Please sign in to add a comment. Not a member? Join today