- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have upgraded my project from CVF + VS6 to Intel Fortran + VS10. Both Fortran and C++ files are involved, each kind calling the other and using some common files. It worked in the older version.
But now I can't get the C++ routines to link to a Fortran COMMON block. My Fortran declares a file, for example, as follows: (NS, NBCOL, and JC are parameters)
!DEC$ ATTRIBUTES ALIAS: 'LENS1' :: LENS1
COMMON/LENS1/CVD(0:NS,JC),THD(0:NS,JC),RINDEX(NBCOL,0:NS,JC),
$ ANUM(30,0:NS,JC),WAVL(NBCOL,JC),WGTD(NBCOL,JC),ICORD(NBCOL,JC),
$ JUCODE(JC),NSPACE(0:NS,JC)
and then the C++ program is supposed to be able to access it with
#pragma pack(2)
extern struct lens1s {
double CVD[JC][NS+1];
double THD[JC][NS+1];
double RINDEX[JC][NS+1][NBCOL];
double ANUM[JC][NS+1][30];
double WAVL[JC][NBCOL];
double WGTD[JC][NBCOL];
int ICORD[JC][NBCOL];
int JUCODE[JC];
int NSPACE[JC][NS+1];
} LENS1;
#pragma pack()
where the constants are defined with an enum statement.
This is in accordance with the instructions and example in the online help file. But I get a linker error:
error LNK2001: unresolved external symbol "struct lens1s LENS1" (?LENS1@@3Ulens1s@@A)
Does anyone know how to fix this error?
But now I can't get the C++ routines to link to a Fortran COMMON block. My Fortran declares a file, for example, as follows: (NS, NBCOL, and JC are parameters)
!DEC$ ATTRIBUTES ALIAS: 'LENS1' :: LENS1
COMMON/LENS1/CVD(0:NS,JC),THD(0:NS,JC),RINDEX(NBCOL,0:NS,JC),
$ ANUM(30,0:NS,JC),WAVL(NBCOL,JC),WGTD(NBCOL,JC),ICORD(NBCOL,JC),
$ JUCODE(JC),NSPACE(0:NS,JC)
and then the C++ program is supposed to be able to access it with
#pragma pack(2)
extern struct lens1s {
double CVD[JC][NS+1];
double THD[JC][NS+1];
double RINDEX[JC][NS+1][NBCOL];
double ANUM[JC][NS+1][30];
double WAVL[JC][NBCOL];
double WGTD[JC][NBCOL];
int ICORD[JC][NBCOL];
int JUCODE[JC];
int NSPACE[JC][NS+1];
} LENS1;
#pragma pack()
where the constants are defined with an enum statement.
This is in accordance with the instructions and example in the online help file. But I get a linker error:
error LNK2001: unresolved external symbol "struct lens1s LENS1" (?LENS1@@3Ulens1s@@A)
Does anyone know how to fix this error?
1 Solution
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ah, you missed a step, or maybe two. MS changed things a lot in VS10 and made things much more complicated for mixed-language development. Please read the Fortran release notes section 3.8 "Microsoft Visual Studio 2010 Notes" for the gory details. You should have the proper release notes - at least if you have a relatively recent release.
Link Copied
17 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
No, it would not have worked in CVF with exactly the same code. You must use:
extern "C" struct ....
because C++ will "mangle" the name. Perhaps your old C++ code was in a file with a .c file type?
extern "C" struct ....
because C++ will "mangle" the name. Perhaps your old C++ code was in a file with a .c file type?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Actually, my old CVF + VS6 code had the "C" structure. But here's what the help file in VS10 says:
struct lens1s {
double CVD[JC][NS+1];
double THD[JC][NS+1];
double RINDEX[JC][NS+1][NBCOL];
double ANUM[JC][NS+1][30];
double WAVL[JC][NBCOL];
double WGTD[JC][NBCOL];
int ICORD[JC][NBCOL];
int JUCODE[JC];
int NSPACE[JC][NS+1];
} ;
#pragma pack()
extern "C" struct lens1s LENS1;
and I get a different link error:
error LNK2001: unresolved external symbol _LENS1
So that's not the solution, it seems. I have also tried putting external "C" and name LENS1 in the struct definition and deleting the extra extern line. No good either. What now?
As an example, suppose your Fortran code has a common block named Really, as shown:
!DEC$ ATTRIBUTES ALIAS:'Really' :: Really REAL(4) x, y, z(6) REAL(8) ydbl COMMON / Really / x, y, z(6), ydbl
You can access this data structure from your C code with the following external data structures:
#pragma pack(2) extern struct { float x, y, z[6]; double ydbl; } Really; #pragma pack()There is no "C" there, so I took it out. When I put it back in, my code reads
struct lens1s {
double CVD[JC][NS+1];
double THD[JC][NS+1];
double RINDEX[JC][NS+1][NBCOL];
double ANUM[JC][NS+1][30];
double WAVL[JC][NBCOL];
double WGTD[JC][NBCOL];
int ICORD[JC][NBCOL];
int JUCODE[JC];
int NSPACE[JC][NS+1];
} ;
#pragma pack()
extern "C" struct lens1s LENS1;
and I get a different link error:
error LNK2001: unresolved external symbol _LENS1
So that's not the solution, it seems. I have also tried putting external "C" and name LENS1 in the struct definition and deleting the extra extern line. No good either. What now?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The Fortran help talks about C. It does have a small mention that you need the "C" if you are using C++.
But try this instead: Take out the ATTRIBUTES ALIAS. Add:
BIND(C,NAME="LENS1") :: /LENS1/
I'm not sure what your common /REALLY/ is doing in there.
But try this instead: Take out the ATTRIBUTES ALIAS. Add:
BIND(C,NAME="LENS1") :: /LENS1/
I'm not sure what your common /REALLY/ is doing in there.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you for the helpful suggestion. Here's what I have now:
COMMON/LENS1/CVD(0:NS,JC),THD(0:NS,JC),RINDEX(NBCOL,0:NS,JC),
$ ANUM(30,0:NS,JC),WAVL(NBCOL,JC),WGTD(NBCOL,JC),ICORD(NBCOL,JC),
$ JUCODE(JC),NSPACE(0:NS,JC)
BIND(C,NAME="LENS1") :: /LENS1/
and in C++:
#pragma pack(4)
struct lens1s {
double CVD[JC][NS+1];
double THD[JC][NS+1];
double RINDEX[JC][NS+1][NBCOL];
double ANUM[JC][NS+1][30];
double WAVL[JC][NBCOL];
double WGTD[JC][NBCOL];
int ICORD[JC][NBCOL];
int JUCODE[JC];
int NSPACE[JC][NS+1];
} ;
#pragma pack()
And the linker error is
error LNK2001: unresolved external symbol _LENS1.
The external procedures property page uses the CVF default, which showed up automatically.
COMMON/LENS1/CVD(0:NS,JC),THD(0:NS,JC),RINDEX(NBCOL,0:NS,JC),
$ ANUM(30,0:NS,JC),WAVL(NBCOL,JC),WGTD(NBCOL,JC),ICORD(NBCOL,JC),
$ JUCODE(JC),NSPACE(0:NS,JC)
BIND(C,NAME="LENS1") :: /LENS1/
and in C++:
#pragma pack(4)
struct lens1s {
double CVD[JC][NS+1];
double THD[JC][NS+1];
double RINDEX[JC][NS+1][NBCOL];
double ANUM[JC][NS+1][30];
double WAVL[JC][NBCOL];
double WGTD[JC][NBCOL];
int ICORD[JC][NBCOL];
int JUCODE[JC];
int NSPACE[JC][NS+1];
} ;
#pragma pack()
And the linker error is
error LNK2001: unresolved external symbol _LENS1.
The external procedures property page uses the CVF default, which showed up automatically.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Surround your C++ code block containing the structure declaration with
extern "C" {
--- your C++ code block
}
to prevent the C++ name mangling from taking place.
I don't see the relevance of the "CVF default" property -- the C/C++ compiler knows nothing about Fortran, let alone CVF.
extern "C" {
--- your C++ code block
}
to prevent the C++ name mangling from taking place.
I don't see the relevance of the "CVF default" property -- the C/C++ compiler knows nothing about Fortran, let alone CVF.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You would need to spell the symbol the same on the C side as you told Fortran you would do.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Well, I thought I did. Here's my Fortran code:
COMMON/LENS1/CVD(0:NS,JC),THD(0:NS,JC),RINDEX(NBCOL,0:NS,JC),
$ ANUM(30,0:NS,JC),WAVL(NBCOL,JC),WGTD(NBCOL,JC),ICORD(NBCOL,JC),
$ JUCODE(JC),NSPACE(0:NS,JC)
BIND(C,NAME="LENS1") :: /LENS1/
and here it is in C++:
extern "C" {
#pragma pack(4)
struct lens1s {
double CVD[JC][NS+1];
double THD[JC][NS+1];
double RINDEX[JC][NS+1][NBCOL];
double ANUM[JC][NS+1][30];
double WAVL[JC][NBCOL];
double WGTD[JC][NBCOL];
int ICORD[JC][NBCOL];
int JUCODE[JC];
int NSPACE[JC][NS+1];
} ;
#pragma pack()
extern "C" struct lens1s LENS1;
}
... and here's what I get:
error LNK2001: unresolved external symbol _LENS1
Do you see any errors in my code?
COMMON/LENS1/CVD(0:NS,JC),THD(0:NS,JC),RINDEX(NBCOL,0:NS,JC),
$ ANUM(30,0:NS,JC),WAVL(NBCOL,JC),WGTD(NBCOL,JC),ICORD(NBCOL,JC),
$ JUCODE(JC),NSPACE(0:NS,JC)
BIND(C,NAME="LENS1") :: /LENS1/
and here it is in C++:
extern "C" {
#pragma pack(4)
struct lens1s {
double CVD[JC][NS+1];
double THD[JC][NS+1];
double RINDEX[JC][NS+1][NBCOL];
double ANUM[JC][NS+1][30];
double WAVL[JC][NBCOL];
double WGTD[JC][NBCOL];
int ICORD[JC][NBCOL];
int JUCODE[JC];
int NSPACE[JC][NS+1];
} ;
#pragma pack()
extern "C" struct lens1s LENS1;
}
... and here's what I get:
error LNK2001: unresolved external symbol _LENS1
Do you see any errors in my code?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Here is how things are situated.
The C-compiler does what you tell it to do. The Fortran compiler does what you tell it to do. Each is oblivious to the presence of the other.
Secondly, each compiler has a standard, but overridable, way of transforming symbol names. If the two transformed names, one from each compiler, do not match, the linker will fail.
Here is what to do. Compile the C++/C code, and use a tool such as Dumpbin to see the decorated name in the resulting .OBJ file. Then, transfer that decorated name into the
BIND(C,NAME="....")
attribute in your Fortran code.
You probably need _LENS1 in there, with the underscore. However, this is subject to variations with OS, compiler and architecture ( IA32 or X64 ? )
The C-compiler does what you tell it to do. The Fortran compiler does what you tell it to do. Each is oblivious to the presence of the other.
Secondly, each compiler has a standard, but overridable, way of transforming symbol names. If the two transformed names, one from each compiler, do not match, the linker will fail.
Here is what to do. Compile the C++/C code, and use a tool such as Dumpbin to see the decorated name in the resulting .OBJ file. Then, transfer that decorated name into the
BIND(C,NAME="....")
attribute in your Fortran code.
You probably need _LENS1 in there, with the underscore. However, this is subject to variations with OS, compiler and architecture ( IA32 or X64 ? )
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I ran DUMPBIN for one of the Fortran obj files, and here is what it says:
066 000C8D00 UNDEF notype External | _LENS1
So it seems to have the "_" already there, even though I did not add it myself:
COMMON/LENS1/CVD(0:NS,JC),THD(0:NS,JC),RINDEX(NBCOL,0:NS,JC),
$ ANUM(30,0:NS,JC),WAVL(NBCOL,JC),WGTD(NBCOL,JC),ICORD(NBCOL,JC),
$ JUCODE(JC),NSPACE(0:NS,JC)
BIND(C,NAME="LENS1") :: /LENS1/
I then tried DUMPBIN for a cpp file that includes
extern "C" {
#pragma pack(4)
struct lens1s {
double CVD[JC][NS+1];
double THD[JC][NS+1];
double RINDEX[JC][NS+1][NBCOL];
double ANUM[JC][NS+1][30];
double WAVL[JC][NBCOL];
double WGTD[JC][NBCOL];
int ICORD[JC][NBCOL];
int JUCODE[JC];
int NSPACE[JC][NS+1];
} ;
#pragma pack()
extern "C" struct lens1s LENS1;
}
It compiled with no errors, but the DUMPBIN output for the obj file does not contain the characters "LENS1". So I do not know what kind of decoration the linker expects.
I'm getting tons of other linker errors too. All of the calls from C++ to FORTRAN are unresolved -- but there are no link errors for FORTRAN calling C routines. So, either those worked or the linker never got that far. Is it possible that the linker is ignoring all of the FORTRAN obj files?
I'm also getting lots of errors like this:
1>atlsd.lib(AtlDebugAPI.obj) : error LNK2001: unresolved external symbol __imp__SetEvent@4
The references are apparently to some system routines (not mine). What's going on?
066 000C8D00 UNDEF notype External | _LENS1
So it seems to have the "_" already there, even though I did not add it myself:
COMMON/LENS1/CVD(0:NS,JC),THD(0:NS,JC),RINDEX(NBCOL,0:NS,JC),
$ ANUM(30,0:NS,JC),WAVL(NBCOL,JC),WGTD(NBCOL,JC),ICORD(NBCOL,JC),
$ JUCODE(JC),NSPACE(0:NS,JC)
BIND(C,NAME="LENS1") :: /LENS1/
I then tried DUMPBIN for a cpp file that includes
extern "C" {
#pragma pack(4)
struct lens1s {
double CVD[JC][NS+1];
double THD[JC][NS+1];
double RINDEX[JC][NS+1][NBCOL];
double ANUM[JC][NS+1][30];
double WAVL[JC][NBCOL];
double WGTD[JC][NBCOL];
int ICORD[JC][NBCOL];
int JUCODE[JC];
int NSPACE[JC][NS+1];
} ;
#pragma pack()
extern "C" struct lens1s LENS1;
}
It compiled with no errors, but the DUMPBIN output for the obj file does not contain the characters "LENS1". So I do not know what kind of decoration the linker expects.
I'm getting tons of other linker errors too. All of the calls from C++ to FORTRAN are unresolved -- but there are no link errors for FORTRAN calling C routines. So, either those worked or the linker never got that far. Is it possible that the linker is ignoring all of the FORTRAN obj files?
I'm also getting lots of errors like this:
1>atlsd.lib(AtlDebugAPI.obj) : error LNK2001: unresolved external symbol __imp__SetEvent@4
The references are apparently to some system routines (not mine). What's going on?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I did the DUMPBIN again, on a different C++ routine. (The one above had LENS1 defined but never used it.) Now there is a reference:
3F5 00000000 UNDEF notype External | _LENS1
So the Fortran obj and the C++ obj both call the common block by the same name. Yet the linker cannot find it. Does that give you any more clues?
3F5 00000000 UNDEF notype External | _LENS1
So the Fortran obj and the C++ obj both call the common block by the same name. Yet the linker cannot find it. Does that give you any more clues?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Maybe this is so obvious that it's not obvious - but are you actually linking the C++ library in? There are additional actions that you need to take after a conversion to do that - see section 3.8.2 (MS VS1010 notes) in the release notes for the most recent compiler version.
This C++ code:
[cpp]// cl /c /EHsc cpp-struct.cpp #include
extern "C" struct lens1s {
int i;
float f;
} LENS1;
extern "C" void c_fun()
{
std::cout << "C++ says: " << LENS1.i << std::endl;
LENS1.f = 3.0f;
}
[/cpp] Linked with this fortran code:
[fortran]! ifort /c fortran-struct.f90 cpp-struct.obj PROGRAM Hello USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT, C_FLOAT IMPLICIT NONE COMMON/LENS1/i,f INTEGER(C_INT) :: i REAL(C_FLOAT) :: f BIND(C,NAME="LENS1") :: /LENS1/ INTERFACE SUBROUTINE c_fun() BIND(C, NAME='c_fun') END SUBROUTINE c_fun END INTERFACE !******* i = 2 CALL c_fun PRINT "('Fortran says:',F5.2)", f END PROGRAM Hello [/fortran] ...works.
This C++ code:
[cpp]// cl /c /EHsc cpp-struct.cpp #include
[fortran]! ifort /c fortran-struct.f90 cpp-struct.obj PROGRAM Hello USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT, C_FLOAT IMPLICIT NONE COMMON/LENS1/i,f INTEGER(C_INT) :: i REAL(C_FLOAT) :: f BIND(C,NAME="LENS1") :: /LENS1/ INTERFACE SUBROUTINE c_fun() BIND(C, NAME='c_fun') END SUBROUTINE c_fun END INTERFACE !******* i = 2 CALL c_fun PRINT "('Fortran says:',F5.2)", f END PROGRAM Hello [/fortran] ...works.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Do not put the underscore in NAME=. The compiler will do whatever the C compiler does for name decoration. Think of NAME= as ALIAS,DECORATE.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It gets more interesting. I added a call to a nonexistent routine in one of the Fortran programs, to see if that would show up as another linker error. It did not.
Which tells me that the linker is simply ignoring all of the Fortran obj files. How do I make it include them? (I converted from CVF + VS 6 to Intel Fortran + VS 10, and did the conversion after opening VS10. Then I used the option to Extract Compaq Visual Fortran.) That seemed to work, and all of the source files, both C++ and Fortran, are in the Solution Explorer panel. If I modify a Fortran file, it gets recompiled, so that works properly too. Just the linker seems screwed up.
Advice, please?
Which tells me that the linker is simply ignoring all of the Fortran obj files. How do I make it include them? (I converted from CVF + VS 6 to Intel Fortran + VS 10, and did the conversion after opening VS10. Then I used the option to Extract Compaq Visual Fortran.) That seemed to work, and all of the source files, both C++ and Fortran, are in the Solution Explorer panel. If I modify a Fortran file, it gets recompiled, so that works properly too. Just the linker seems screwed up.
Advice, please?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ian:
This is very helpful, but I can only find Release Notes for Intel Visual Fortran Composer XE, and there is no section 3.8.2 in that file. Where are the Release Notes for MS VS1010? I searched my whole computer, and found only the Intel flavors.
This is very helpful, but I can only find Release Notes for Intel Visual Fortran Composer XE, and there is no section 3.8.2 in that file. Where are the Release Notes for MS VS1010? I searched my whole computer, and found only the Intel flavors.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ah, you missed a step, or maybe two. MS changed things a lot in VS10 and made things much more complicated for mixed-language development. Please read the Fortran release notes section 3.8 "Microsoft Visual Studio 2010 Notes" for the gory details. You should have the proper release notes - at least if you have a relatively recent release.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Okay, I found a section in the Intel Release Notes that says one must be sure that the Fortran lib is included with the project dependencies. I checked, and it is already there. Is that the extra step you referred to?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve:
This is a great answer. I followed the steps in section 3.8.2 and 3.8.2, adding the extra references. Wow! The link error to LENS1 goes away, and the link error to my nonexistant routine shows up! This is real progress.
I still have link errors to the Fortran routines from C, but I'll pound on it myself before asking for help here. (I may be back!) Many thanks for taking the time to respond. Especially on Sunday.
This is a great answer. I followed the steps in section 3.8.2 and 3.8.2, adding the extra references. Wow! The link error to LENS1 goes away, and the link error to my nonexistant routine shows up! This is real progress.
I still have link errors to the Fortran routines from C, but I'll pound on it myself before asking for help here. (I may be back!) Many thanks for taking the time to respond. Especially on Sunday.

Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page