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

Mixed language compiling linking, help needed.

Andreas_G_
Beginner
507 Views

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

 

 

0 Kudos
10 Replies
Steven_L_Intel1
Employee
507 Views

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. 

 

0 Kudos
Andreas_G_
Beginner
507 Views

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();
}

 

0 Kudos
Steven_L_Intel1
Employee
507 Views

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.

0 Kudos
Andreas_G_
Beginner
507 Views

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)Capture.JPG
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'   

0 Kudos
Steven_L_Intel1
Employee
507 Views

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.

0 Kudos
Andreas_G_
Beginner
507 Views

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;...........

 

0 Kudos
Steven_L_Intel1
Employee
507 Views

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.)

0 Kudos
Andreas_G_
Beginner
507 Views

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

0 Kudos
Steven_L_Intel1
Employee
507 Views

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

 

0 Kudos
Andreas_G_
Beginner
507 Views

Thanks so much Steve

It links without errors now. All done!

Andy
 

0 Kudos
Reply