- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello All
I have a mixed-language program that is being ported from Linux; it compiles/links/runs fine so I know I don't have a fundamental code issue, unless I have to make some changes specific to the environment.
The program is a C program which calls Fortran routines, which in turn call C routines initialized by the main C program. I have already found the configuration information at the following link: https://software.intel.com/en-us/articles/configuring-visual-studio-for-mixed-language-applications
The main C program appends an '_' to the name of the first FORTRAN routine it calls, as I had to do in Linux. Is this still required in this context?
void GIE(void)
{
/* Insert a call to the analysis here. */
f2scex_sub_();
}
SUBROUTINE f2scex_sub()
etc...
RETURN
END
On trying to link, I get:
warning C4013: 'f2scex_sub_' undefined; assuming extern returning int
But of course removing the '_' yields essentially the same message. Where do I start? I have found answers to random related questions, but no good overview of how to do this.
Thanks to all
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
A few things. First, you're getting an error from the C compiler - Fortran is not involved there. It's complaining about a mismatch between your call to f2scex_sub_ and the (lack of) declaration of that routine in the C source. You haven't shown your C declaration of the subroutine.
Next, the trailing underscore is a Linux/UNIX convention for Fortran procedures. Intel Fortran on Windows doesn't do that.
Now we come to name case. Again on Linux, the convention is that Fortran names are downcased. Not so on Windows.
Assuming that you get the C declaration issue fixed, my advice is to drop the trailing underscore. On the Fortran side, add BIND(C) after the () in the subroutine declaration:
SUBROUTINE f2scex_sub() BIND(C)
This will get you a downcased name.Now, if the routine actually has arguments, you may need to make some adjustments, but I suspect you have removed too much for me to give advice there.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you Steve
This is very helpful, although I may need a bit more..
- In the existing code, there is no declaration of f2scex_sub() in the C. Apparently the Portland Group compiler didn't need it, and I'm not quite sure what the C declaration of a FORTRAN routine is supposed to look like.
- There are no arguments to f2scex_sub().
- I removed the '_', added BIND(C) in the FORTRAN as you said, and 'extern void f2scex_sub();' in the C (not knowing any better), and on compiling I still get: f2scGIE.obj : error LNK2019: unresolved external symbol _f2scex_sub referenced in function _GIE. I guess my declaration is not up to snuff?
Thanks again!
Andreas
extern void f2scex_sub();
void GIE(void)
{
/* Insert a call to the analysis here. */
f2scex_sub();
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Well, what you did should have worked. Did you recompile the Fortran? Show me the SUBROUTINE line as it reads now.
Also, how have you told the C caller to find the Fortran code? If you built the Fortran into a static library you need to name that library in the C project settings (or add it as a source file). C/C++ projects no longer link in dependent non-C++ projects automatically.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks again
I do have a FORTRAN library, and for that I'm pretty sure I correctly named that library in the project settings. However the particular file containing f2scex_sub() is separate from that, and a source file in the project. I cleaned the project before I built it again after the changes.
As you may gather, this was once the main routine of a FORTRAN only program before the C was wrapped around it. Should the f2scex_sub be upper case?
SUBROUTINE f2scex_sub() BIND(C)
C PROGRAM F2SCEX
C
C MAJOR CHANGE: 12-15-08.
C Routine gacous() is removed and replaced by getnpd(). The function
C of routine gacous has been re-asssigned to the acoustics suite
C of tools. getnpd() will load the finalized NPD data.
C
include 'proj01.fd'
include 'dbchek.fd'
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ah - you just stuck the .f file in the C++ project. That won't work. You have to create a Fortran static library project to build this source and add that library to the C++ project.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you again, Steve
This took care of that issue, and actually makes things much easier in terms of organizing the code. I have one last issue.
Now, I have FORTRAN code that is trying to access C functions. As before, it can't find them. Is there something similar to '(BIND(C))' that I have to do to certain routines to get the FORTRAN to recognize the C code?
Thanks!
Andy
1>------ Build started: Project: VC_f2scex, Configuration: Debug Win32 ------
1>IVF_f2sc_lib.lib(gint.obj) : error LNK2019: unresolved external symbol _GET referenced in function _FGET
1>IVF_f2sc_lib.lib(gint.obj) : error LNK2019: unresolved external symbol _PUT referenced in function _FPUT
1>IVF_f2sc_lib.lib(gint.obj) : error LNK2019: unresolved external symbol _CHECK referenced in function _FFCHECK4
etc.
FORTRAN:
name(i:i)=char(0)
call putv(value,name,size)........
C:
void putv(void *Value, char *VarName, fortint *Size)
{
int iSize;
GenData *theGenData;
int *iValue;
int i;...........
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You need to write an interface block for the C routine - Fortran has many features to aid C interoperability. Some are going into a future Fortran standard but Intel Fortran 16 already supports them. For example, your putv routine would be declared this way:
interface subroutine putv (Value, VarName, Size) bind(C) use, intrinsic :: iso_c_binding type(*) :: Value character, dimension(*) :: VarName integer(C_INT) :: Size end subroutine putv end interface
Normally I would add INTENT attributes to the arguments but I didn't know what your routine did. "type(*)" matches C's void * (or just void if you also add the VALUE attribute.) The use of an array of characters will match a Fortran character variable scalar.
You would put this interface block in the declaration section of the routine that wants to call putv (or put it in a module and USE the module.)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks again!
For some reason though I get the following messages, referring to the statement :
type(*) :: Value
1>------ Build started: Project: IVF_f2sc_lib, Configuration: Debug Win32 ------
1>Compiling with Intel(R) Visual Fortran Compiler XE 13.1.3.198 [IA-32]...
1>gint.F
1>C:\Users\...\Documents\casepgms\Genie-205d1\src\Genie\gint.F(306): error #5082: Syntax error, found '::' when expecting one of: , <END-OF-STATEMENT> ;
1>C:\Users\...\Documents\casepgms\Genie-205d1\src\Genie\gint.F(306): error #6622: This statement is invalid in an INTERFACE block.
Other online resources I've found also suggest this should work, so I'm stumped. any thoughts?
Thanks
Andy
*** Put an array (vector) of real*8 values into the Genie database
subroutine fputv(value,s,size)
real value
character*(*) s
integer size
character*256 name
integer i
interface
subroutine putv (Value, VarName, Size) bind(C)
use, intrinsic :: iso_c_binding
character, dimension(*) :: VarName
integer(C_INT) :: Size
type(*) :: Value
end subroutine putv
end interface
do i=1,len(s)
name(i:i)=s(i:i)
enddo
i=len(s)+1
name(i:i)=char(0)
c call C routine...
call putv(value,name,size)
return
end
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You're using an old compiler version that doesn't support TYPE(*). As an alternative, use this:
interface subroutine putv (Value, VarName, Size) bind(C) use, intrinsic :: iso_c_binding character, dimension(*) :: VarName integer(C_INT) :: Size integer(C_INT) :: Value !DEC$ ATTRIBUTES NO_ARG_CHECK :: Value end subroutine putv end interface
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks so much Steve
It links without errors now. All done!
Andy
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page