PGI Inter-languauge Questions


How do you call pgf77-pgf90-pghpf routines from g++?

The answer is straightforward but detailed.

main.c:

extern "C" void foo_ ( int * );
extern "C" void pghpf_init(int *);
int __argc_save;
char **__argv_save;
static int zz = 0;

main(int argc, char **argv)
{
    int i;
    __argc_save = argc;  
    __argv_save = argv; 

    pghpf_init(&zz);  
    i = 19;
    foo_(&i);
}
 
foo.f90:
        subroutine foo (i)
        integer i
        print *, i
        end subroutine foo

pgf90 -c foo.f90
g++ main.c foo.o -L/usr/pgi/linux86/lib 
    -I/usr/pgi/linux86/include -lpgf90 -lpgf90_rpm1 
    -lpgf902 -lpgf90rtl -lpgftnrtl -lm -lpgc -lgcc

(assumes compilers installed in /usr/pgi)

In the case of code compiled with pgf77, the similar example is as follows:

main.c:  
 
extern "C" void foo_ ( int * );
int __argc_save;
char **__argv_save;
 
main(int argc, char **argv)
{
    int i;
    __argc_save = argc;
    __argv_save = argv;
 
    i = 19;
    foo_(&i);
}
 
foo.f:
        subroutine foo (i)
        integer i
        print *, i
        end 
 
pgf77 -c foo.f
g++ main.c foo.o -L/usr/pgi/linux86/lib
    -I/usr/pgi/linux86/include -lpgftnrtl -lpgc
  

The follow up question is


What arguments can be passed from C++ to f90?

Only the f77-style of passing arrays to an f90 routine from c++ will work. E.g., the dummy arrays of the f90 routine called from c/c++/f77 cannot be assumed shape or f90 pointer.

Example:
C/C++
          float a[100];
          int  n = 100;
          foo_(a,&n);
    ...
F90
    subroutine foo(a,n)
    real a(:)           ! does not work - a cannot be assumed shape
    ...
 
    subroutine foo(a,n)
    real a(n)           ! should work

What about passing command line arguments (argc, argv) from gcc programs to pgf77 compiled code?

Again remember that pgi compilers use different globals than gcc does.

% more cmain.c

int __argc_save;
char **__argv_save;

main(int argc, char **argv)
{
   char          bool1, letter1;
   int           numint1, numint2;
   float         numfloat1;
   double        numdoub1;
   short         numshor1;
   extern        void forts_ ();
   int           i;
    __argc_save = argc;
    __argv_save = argv;
   for (i=0; i < argc; i++){
       printf("main: command line arg %d is %s\n",i,argv[i]);
   }
   forts_(&bool1,&letter1,&numint1,&numint2,&numfloat1,
          &numdoub1,&numshor1, 1);
   printf("main:  %s %c %d %d %3.1f %.0f %d\n",
          bool1?"TRUE":"FALSE",letter1,numint1,
          numint2, numfloat1, numdoub1, numshor1);
}

% more forts.f 

        subroutine forts ( bool1, letter1, numint1,
     & numint2, numfloat1, numdoub1, numshor1)
       character*(128) arg
       logical*1           bool1
       character           letter1
       integer             numint1, numint2
       double precision    numdoub1
       real                numfloat1
       integer*2           numshor1
       integer             i,j
 
       bool1 = .true.
       letter1 = "v"
       numint1 = 11
       numint2 = -44
       numdoub1 = 902
       numfloat1 = 39.6
       numshor1 = 299
       i = iargc()
       print *,"forts: argc=",i
       do j=0,i
       call getarg(j,arg)
       print *,"forts: arg ",j," is ", arg
       end do
       return
       end

% gcc -c cmain.c
% pgf77 -o c2f -Mnomain cmain.o forts.f

Linking:
 
% c2f 123 456 momma

main: command line arg 0 is c2f
main: command line arg 1 is 123
main: command line arg 2 is 456
main: command line arg 3 is momma
 forts: argc=           3
 forts: arg            0 is c2f

 forts: arg            1 is 123

 forts: arg            2 is 456

 forts: arg            3 is momma

main:  TRUE v 11 -44 39.6 902 299



How do you pass data between f77 and C/C++ routines.?

Here are some examples. See Chapter 10 of the User's Guide for more information.

fortran calling C


% more fmain.f

       program fort2c
       logical*1              bool1
       character              letter1
       integer*4              numint1, numint2
       real                   numfloat1
       double precision       numdoub1
       integer*2              numshor1
       external cfunc
       call cfunc (bool1, letter1, numint1, numint2,
     & numfloat1, numdoub1, numshor1)
       write( *, 100)
     & bool1, letter1, numint1, numint2, numfloat1,
     & numdoub1, numshor1
100    format(1x,"bool1     =  ", L2,/,
     &          " letter1   =  ", A2,/,
     &          " numint1   = ", I5,/,
     &          " numint2   = ", I5,/,
     &          " numfloat1 = ", F6.1,/,
     &          " numdoub1  = ", F6.1,/,
     &          " numshor1  = ", I5,/)
       end

% more csub.c

#define TRUE 0xff
#define FALSE 0
void
cfunc_( bool1, letter1, numint1, numint2, numfloat1,\
        numdoub1, numshor1, len_letter1)
   char    *bool1, *letter1;
   int     *numint1, *numint2;
   float   *numfloat1;
   double  *numdoub1;
   short   *numshor1;
   int     len_letter1;
{
   *bool1 = TRUE;
   *letter1 = 'v';
   *numint1 = 11;
   *numint2 = -44;
   *numfloat1 = 39.6 ;
   *numdoub1 = 39.2 ;
   *numshor1 = 981;
}

%pgcc -c csub.c
%pgf77 fmain.f csub.o

% a.out

 bool1     =   T
 letter1   =   v
 numint1   =    11
 numint2   =   -44
 numfloat1 =   39.6
 numdoub1  =   39.2
 numshor1  =   981


C calling fortran


% more cmain.c

main ()
{
   char          bool1, letter1;
   int           numint1, numint2;
   float         numfloat1;
   double        numdoub1;
   short         numshor1;
   extern        void forts_ ();
   forts_(&bool1,&letter1,&numint1,&numint2,&numfloat1,
          &numdoub1,&numshor1, 1);
   printf(" bool1 = %s\n letter1 =  %c\n numint1 =  %d \n numint2 = %d \n numfloat1 = %3.1f \n 
numdoub1 = %.0f \n numshor1 = %d\n", bool1?"TRUE":"FALSE",letter1,numint1, numint2, numfloat1, numdoub1, numshor1); } % more fsub.f subroutine forts ( bool1, letter1, numint1, & numint2, numfloat1, numdoub1, numshor1) logical*1 bool1 character letter1 integer numint1, numint2 double precision numdoub1 real numfloat1 integer*2 numshor1 bool1 = .true. letter1 = "v" numint1 = 11 numint2 = -44 numdoub1 = 902 numfloat1 = 39.6 numshor1 = 299 return end % pgcc -c cmain.c % pgf77 -Mnomain cmain.o fsub.f Linking: % a.out bool1 = TRUE letter1 = v numint1 = 11 numint2 = -44 numfloat1 = 39.6 numdoub1 = 902 numshor1 = 299


C++ calling fortran


% more cpmain.C

#include <iostream>
extern "C" {
extern  void forts_ ( char *, char *, int *, int *, float *, double *, short * );
}
main ()
{
   char          bool1, letter1;
   int           numint1, numint2;
   float         numfloat1;
   double        numdoub1;
   short         numshor1;
   forts_(&bool1, &letter1, &numint1, &numint2, &numfloat1, &numdoub1, &numshor1);
   cout << " bool1     = ";
   bool1?cout << "TRUE ":cout << "FALSE "; cout   << endl;
   cout << " letter1   = "     << letter1   << endl;
   cout << " numint1   = "     << numint1   << endl;
   cout << " numint2   = "     << numint2   << endl;
   cout << " numfloat1 = "     << numfloat1 << endl;
   cout << " numdoub1  = "     << numdoub1  << endl;
   cout << " numshor1  = "     << numshor1  << endl ;
}  

% more fsub.f

       subroutine forts ( bool1, letter1, numint1,
     & numint2, numfloat1, numdoub1, numshor1)
       logical*1           bool1
       character           letter1
       integer             numint1, numint2
       double precision    numdoub1
       real                numfloat1
       integer*2           numshor1
    
       bool1      = .true.
       letter1    = "v"
       numint1    = 11
       numint2    = -44
       numdoub1   = 902
       numfloat1  = 39.6
       numshor1   = 299
       return
  
% pgf77 -c fsub.f
% pgCC cpmain.C fsub.o

cpmain.C:
Linking:

% a.out

 bool1     = TRUE
 letter1   = v
 numint1   = 11
 numint2   = -44
 numfloat1 = 39.6
 numdoub1  = 902
 numshor1  = 299



f77 calling C++


% more fmain.f

       logical*1              bool1
       character              letter1
       integer*4              numint1, numint2
       real                   numfloat1
       double precision       numdoub1
       integer*2              numshor1
       external cfunc
       call cplus_func (bool1, letter1, numint1,
     & numint2, numfloat1, numdoub1, numshor1)
       write( *, 100)
     & bool1, letter1, numint1, numint2, numfloat1,
     & numdoub1, numshor1
100    format(1x,"bool1     =  ", L2,/,
     &          " letter1   =  ", A2,/,
     &          " numint1   = ", I5,/,
     &          " numint2   = ", I5,/,
     &          " numfloat1 = ", F6.1,/,
     &          " numdoub1  = ", F6.1,/,
     &          " numshor1  = ", I5,/)
       end

% more cpsub.C

#define TRUE 0xff
#define FALSE 0
extern "C" {
extern void cplus_func_ (
        char    *bool1,
        char    *letter1,
        int     *numint1,
        int     *numint2,
        float   *numfloat1,
        double  *numdoub1,
        short   *numshort1,
        int     len_letter1) {
        *bool1= TRUE;
        *letter1 = 'v';
        *numint1 = 11;
        *numint2  = -44;
        *numfloat1 = 39.6;
        *numdoub1 = 39.2;
        *numshort1 = 981;
}
}

% pgCC -c cpsub.C

cpsub.C:

% pgf77 fmain.f cpsub.o

Linking:

% a.out

 bool1     =   T
 letter1   =   v
 numint1   =    11
 numint2   =   -44
 numfloat1 =   39.6
 numdoub1  =   39.2
 numshor1  =   981
 


C calling C++


% more cmain.c

extern void func2_cplus(int a, int b, int *c);
#include <stdio.h>
main()
{
   int a,b,c;
   a=8;
   b=2;
   printf("main: a = %d b = %d ptr c = %x\n",a,b,&c);
   func2_cplus(a,b,&c);
   printf("main: res = %d\n",c);
}

% more cpsub.C

#include <iostream>
extern "C" void func2_cplus(int num1,int num2,int *res)
{
   cout <<  "sub:  a = " << num1 << " b = " << num2 << " ptr c = " << res << endl << endl;
   *res=num1/num2;
   cout << "sub:  res = " << *res << endl ;
}

% pgcc -c cmain.c
% pgCC cmain.o cpsub.C

cpsub.C:
Linking:

% a.out

main: a = 8 b = 2 ptr c = bffffca4
sub:  a = 8 b = 2 ptr c = 0xbffffca4
 
sub:  res = 4
main: res = 4



C++ calling C


% more cpmain.C

extern "C" void func1_cplus(int n, int m, int *p);
#include <iostream>
main()
{
   int a,b,c;
   a=8;
   b=2;
   cout << "main: a = " << a << " b = " << b << " ptr c = " << &c << endl;
   func1_cplus(a,b,&c);
   cout << "main: res = " << c << endl;
}

% more csub.c

#include <stdio.h>
 
void func1_cplus(num1, num2, res)
int num1, num2, *res;
{
    printf("sub:  a = %d b = %d ptr c = %x\n",num1,num2,res);
    *res=num1/num2;
    printf("\nsub:  res = %d\n",*res);
}
 
% pgcc -c csub.c
% pgCC cpmain.C csub.o

cpmain.C:
Linking:

% a.out

main: a = 8 b = 2 ptr c = 0xbffffca4
sub:  a = 8 b = 2 ptr c = bffffca4
 
sub:  res = 4
main: res = 4


How do you pass string data from HPF to an external C function?

In summary, you need a function prototype in your fortran program if the C function returns a value. Next you need to explicitly pass the length of the string to the C function. In the example below we pass in the string followed by its length using the len_trim intrinsic. By default values are passed by reference, so the C function receives the addresses of the actual arguments...

First the HPF:

        program p
        integer*4 call_c                 ! C function prototype
        character(len=128) :: my_string
        my_string = 'this is a test 1234567890'
        ierr=call_c(my_string,len_trim(my_string))
        print *, ierr
        end

Here's the C:

int call_c_(char *string, unsigned *len){
   char * c_string;
   c_string = (char*) malloc(sizeof(char)*((*len)+1));
   memcpy((void*) c_string, (const void*) string, *len);
   c_string[*len] = '\0';
   printf("string = %s\n",c_string);
   free(c_string);
   return 0;
}


How do you pass data between f77 and f90?

f77 calling f90


% more fmain.f
 
        program fmain
  integer i
  i= 19
  call f90sub(i)
  end

% more f90sub.f90

        subroutine f90sub (i)
  include 'lib3f.h' 
  character(32) argstring
        integer i
        print *, i
  print *, "iargc = ", iargc()
  do j=0,iargc()
     call getarg(j,argstring)
     print *,"arg",j," is ",argstring
        end do
        end subroutine f90sub

% pgf77 -c fmain.f
% pgf90 -o f2f90 f90sub.f90 fmain.o 
 
f90sub.f90:
Linking:

 
% f2f90 is a good call 123

           19
 iargc =            5
 arg           0 is f2f90                           
 arg           1 is is                              
 arg           2 is a                               
 arg           3 is good                            
 arg           4 is call                            
 arg           5 is 123



f90 calling f77


% more f90main.f90
 
        program f90main
  interface
           extrinsic (f77_local) subroutine f77sub(i)
           integer , intent(in) :: i
           end subroutine f77sub
  end interface
  integer i
  i= 19
  call f77sub(i)
  end

% more f77sub.f

        subroutine f77sub (i)
  character*32 argstring
        integer i
        print *, i
  print *, "iargc = ", iargc()
  do j=0,iargc()
     call getarg(j,argstring)
     print *,"arg",j," is ",argstring
        end do
        end


% pgf77 -c f77sub.f
% pgf90 -o f902f f90main.f90 f77sub.o


f90main.f90:
Linking:


% f902f is a good call also 123

           19
 iargc =            6
 arg           0 is f902f                           
 arg           1 is is                              
 arg           2 is a                               
 arg           3 is good                            
 arg           4 is call                            
 arg           5 is also                            
 arg           6 is 123



How about an example of hpf calling every type language routine?

Here is an example of an hpf program calling a c, f77, f90, hpf, and C++, program, and even a subroutine compiled.

pghpf -Mf90 -c 

% more hpfmain.f
       program hpf2all
       logical*1              bool1
       character              letter1
       integer*4              numint1, numint2
       real                   numfloat1
       double precision       numdoub1
       integer*2              numshor1
        interface
           extrinsic (f77_local) subroutine csub(
     & bool1, letter1, numint1, numint2,
     & numfloat1, numdoub1, numshor1)
       logical*1, intent(out) ::        bool1
       character, intent(out) ::        letter1
       integer*4, intent(out) ::        numint1, numint2
       real, intent(out) ::             numfloat1
       double precision, intent(out) :: numdoub1
       integer*2, intent(out) ::        numshor1
           end subroutine csub
        end interface
        interface
           extrinsic (f77_local) subroutine f77sub(
     & bool1, letter1, numint1, numint2,
     & numfloat1, numdoub1, numshor1)
       logical*1, intent(out) ::        bool1
       character, intent(out) ::        letter1
       integer*4, intent(out) ::        numint1, numint2
       real, intent(out) ::             numfloat1
       double precision, intent(out) :: numdoub1
       integer*2, intent(out) ::        numshor1
           end subroutine f77sub
        end interface
        interface
           subroutine hpfsub(
     & bool1, letter1, numint1, numint2,
     & numfloat1, numdoub1, numshor1)
       logical*1, intent(out) ::        bool1
       character, intent(out) ::        letter1
       integer*4, intent(out) ::        numint1, numint2
       real, intent(out) ::             numfloat1
       double precision, intent(out) :: numdoub1
       integer*2, intent(out) ::        numshor1
           end subroutine hpfsub
        end interface
        interface
           extrinsic (f90_local) subroutine hpf90sub(
     & bool1, letter1, numint1, numint2,
     & numfloat1, numdoub1, numshor1)
       logical*1, intent(out) ::        bool1
       character, intent(out) ::        letter1
       integer*4, intent(out) ::        numint1, numint2
       real, intent(out) ::             numfloat1
       double precision, intent(out) :: numdoub1
       integer*2, intent(out) ::        numshor1
           end subroutine hpf90sub
        end interface
        interface
           extrinsic (f90_local) subroutine f90sub(
     & bool1, letter1, numint1, numint2,
     & numfloat1, numdoub1, numshor1)
       logical*1, intent(out) ::        bool1
       character, intent(out) ::        letter1
       integer*4, intent(out) ::        numint1, numint2
       real, intent(out) ::             numfloat1
       double precision, intent(out) :: numdoub1
       integer*2, intent(out) ::        numshor1
           end subroutine f90sub
        end interface
        interface
           extrinsic (f77_local) subroutine cplus(
     & bool1, letter1, numint1, numint2,
     & numfloat1, numdoub1, numshor1)
       logical*1, intent(out) ::        bool1
       character, intent(out) ::        letter1
       integer*4, intent(out) ::        numint1, numint2
       real, intent(out) ::             numfloat1
       double precision, intent(out) :: numdoub1
       integer*2, intent(out) ::        numshor1
           end subroutine cplus
        end interface
       call csub (bool1, letter1, numint1, numint2,
     & numfloat1, numdoub1, numshor1)
       write( *, 100)
     & bool1, letter1, numint1, numint2, numfloat1,
     & numdoub1, numshor1
100    format(1x,"csub:  ",/,
     &          " bool1     =  ", L2,/,
     &          " letter1   =  ", A2,/,
     &          " numint1   = ", I5,/,
     &          " numint2   = ", I5,/,
     &          " numfloat1 = ", F9.1,/,
     &          " numdoub1  = ", F9.1,/,
     &          " numshor1  = ", I5,/)
       call f77sub (bool1, letter1, numint1, numint2,
     & numfloat1, numdoub1, numshor1)
       write( *, 200)
     & bool1, letter1, numint1, numint2, numfloat1,
     & numdoub1, numshor1
200    format(1x,"f77sub:  ",/,
     &          " bool1     =  ", L2,/,
     &          " letter1   =  ", A2,/,
     &          " numint1   = ", I5,/,
     &          " numint2   = ", I5,/,
     &          " numfloat1 = ", F9.1,/,
     &          " numdoub1  = ", F9.1,/,
     &          " numshor1  = ", I5,/)

       call hpfsub (bool1, letter1, numint1, numint2,
     & numfloat1, numdoub1, numshor1)
       write( *, 400)
     & bool1, letter1, numint1, numint2, numfloat1,
     & numdoub1, numshor1
400    format(1x,"hpfsub:  ",/,
     &          " bool1     =  ", L2,/,
     &          " letter1   =  ", A2,/,
     &          " numint1   = ", I5,/,
     &          " numint2   = ", I5,/,
     &          " numfloat1 = ", F9.1,/,
     &          " numdoub1  = ", F9.1,/,
     &          " numshor1  = ", I5,/)

       call hpf90sub (bool1, letter1, numint1, numint2,
     & numfloat1, numdoub1, numshor1)
       write( *, 500)
     & bool1, letter1, numint1, numint2, numfloat1,
     & numdoub1, numshor1
500    format(1x,"hpf90sub:  ",/,
     &          " bool1     =  ", L2,/,
     &          " letter1   =  ", A2,/,
     &          " numint1   = ", I5,/,
     &          " numint2   = ", I5,/,
     &          " numfloat1 = ", F9.1,/,
     &          " numdoub1  = ", F9.1,/,
     &          " numshor1  = ", I5,/)
       call f90sub (bool1, letter1, numint1, numint2,
     & numfloat1, numdoub1, numshor1)
       write( *, 600)
     & bool1, letter1, numint1, numint2, numfloat1,
     & numdoub1, numshor1
600    format(1x,"f90sub:  ",/,
     &          " bool1     =  ", L2,/,
     &          " letter1   =  ", A2,/,
     &          " numint1   = ", I5,/,
     &          " numint2   = ", I5,/,
     &          " numfloat1 = ", F9.1,/,
     &          " numdoub1  = ", F9.1,/,
     &          " numshor1  = ", I5,/)
       call cplus (bool1, letter1, numint1, numint2,
     & numfloat1, numdoub1, numshor1)
       write( *, 700)
     & bool1, letter1, numint1, numint2, numfloat1,
     & numdoub1, numshor1
700    format(1x,"cplus:  ",/,
     &          " bool1     =  ", L2,/,
     &          " letter1   =  ", A2,/,
     &          " numint1   = ", I5,/,
     &          " numint2   = ", I5,/,
     &          " numfloat1 = ", F9.1,/,
     &          " numdoub1  = ", F9.1,/,
     &          " numshor1  = ", I5,/)
       end program hpf2all

% more csub.c
#define TRUE 0xff
#define FALSE 0
void
csub_( bool1, letter1, numint1, numint2, numfloat1,\
        numdoub1, numshor1, len_letter1)
   char    *bool1, *letter1;
   int     *numint1, *numint2;
   float   *numfloat1;
   double  *numdoub1;
   short   *numshor1;
   int     len_letter1;
{
   *bool1 = TRUE;
   *letter1 = 'a';
   *numint1 = 11;
   *numint2 = -11;
   *numfloat1 =10123.4;
   *numdoub1 = 20123.4;
   *numshor1 = 111;
}

% more f77sub.f
       subroutine f77sub ( bool1, letter1, numint1,
     & numint2, numfloat1, numdoub1, numshor1)
       logical*1           bool1
       character           letter1
       integer             numint1, numint2
       double precision    numdoub1
       real                numfloat1
       integer*2           numshor1
    
       bool1      = .false.
       letter1    = "b"
       numint1    = 22
       numint2    = -22
       numfloat1  = 30123.4
       numdoub1   = 40123.4
       numshor1   = 222
       return
       end 
 
% more hpfsub.f 
       subroutine hpfsub ( bool1, letter1, numint1,
     & numint2, numfloat1, numdoub1, numshor1)
       logical*1           bool1
       character           letter1
       integer             numint1, numint2
       double precision    numdoub1
       real                numfloat1
       integer*2           numshor1
    
       bool1      = .true.
       letter1    = "c"
       numint1    = 33
       numint2    = -33
       numfloat1  = 50123.4
       numdoub1   = 60123.4
       numshor1   = 333
       return
       end subroutine hpfsub
  
% more hpf90sub.f 
       subroutine hpf90sub ( bool1, letter1, numint1,
     & numint2, numfloat1, numdoub1, numshor1)
       logical*1           bool1
       character           letter1
       integer             numint1, numint2
       double precision    numdoub1
       real                numfloat1
       integer*2           numshor1
    
       bool1      = .false.
       letter1    = "d"
       numint1    = 44
       numint2    = -44
       numfloat1  = 70123.4
       numdoub1   = 80123.4
       numshor1   = 444
       return
       end subroutine hpf90sub
 
% more f90sub.f   
       subroutine f90sub ( bool1, letter1, numint1,
     & numint2, numfloat1, numdoub1, numshor1)
       logical*1           bool1
       character           letter1
       integer             numint1, numint2
       double precision    numdoub1
       real                numfloat1
       integer*2           numshor1
    
       bool1      = .true.
       letter1    = "e"
       numint1    = 55
       numint2    = -55
       numfloat1  = 90123.4
       numdoub1   = 100123.4
       numshor1   = 555
       return
       end subroutine f90sub

% more cplus.C
#define TRUE 0xff
#define FALSE 0
extern "C" {
extern void cplus_ (
        char    *bool1,
        char    *letter1,
        int     *numint1,
        int     *numint2,
        float   *numfloat1,
        double  *numdoub1,
        short   *numshort1,
        int     len_letter1) {
        *bool1= FALSE;
        *letter1 = 'f';
        *numint1 = 66;
        *numint2  = -66;
        *numfloat1 = 110123.4;
        *numdoub1 = 120123.4;
        *numshort1 = 666;
}
}

% pgcc  -c csub.c
% pgf77 -c f77sub.f
% pghpf -c hpfsub.f
% pghpf -c -Mf90 hpf90sub.f
% pgf90 -c -Mx,50,2 f90sub.f
% pgCC  -c cplus.C
% pghpf -o hpf2all hpfmain.f csub.o f77sub.o hpfsub.o hpf90sub.o f90sub.o cplus.o 

% hpf2all 

 csub:  
 bool1     =   T
 letter1   =   a
 numint1   =    11
 numint2   =   -11
 numfloat1 =   10123.4
 numdoub1  =   20123.4
 numshor1  =   111

 f77sub:  
 bool1     =   F
 letter1   =   b
 numint1   =    22
 numint2   =   -22
 numfloat1 =   30123.4
 numdoub1  =   40123.4
 numshor1  =   222

 hpfsub:  
 bool1     =   T
 letter1   =   c
 numint1   =    33
 numint2   =   -33
 numfloat1 =   50123.4
 numdoub1  =   60123.4
 numshor1  =   333

 hpf90sub:  
 bool1     =   F
 letter1   =   d
 numint1   =    44
 numint2   =   -44
 numfloat1 =   70123.4
 numdoub1  =   80123.4
 numshor1  =   444

 f90sub:  
 bool1     =   T
 letter1   =   e
 numint1   =    55
 numint2   =   -55
 numfloat1 =   90123.4
 numdoub1  =  100123.4
 numshor1  =   555

 cplus:  
 bool1     =   F
 letter1   =   f
 numint1   =    66
 numint2   =   -66
 numfloat1 =  110123.4
 numdoub1  =  120123.4
 numshor1  =   666
 

Visual C++ Interfacing


How do you build and link pgf77-pgf90 routines from Visual C++?

The answer is pretty straight forward. You link the same f77/f90 libraries you would link under pgCC, using the Visual C++ linker.

To build an executable using the following source on a linux86 and NT system using pgCC or VC++ and pgf77 or pgf90.

c.C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef __PGI
extern "C" {
void f_(float *, char *, int *, int *, int);
void c2_(int *, float *);
}
#else

void f_(float *, char *, int *, int *, int);
void c2_(int *, float *);
#endif

void main (void) {
int i, nchar;
char  b[80];
char  *c;
float a[3];
    i = 3;
    a[0] = 10.0;
    a[1] = 20.0;
    a[2] = 30.0;
    sprintf(b, "a.dat");
    nchar = strlen(b);
    printf("string length = %d\n", nchar);
    c = (char *) malloc (nchar*sizeof(char));
    strncpy(c,b,nchar);
    f_(a, c, &i, &nchar, nchar);
}

void c2_(int *b, float *a){
    printf("CALLBACK %d %f %f %f\n",*b, a[0], a[1], a[2]);
}


The following fortran file was used

f.f

  subroutine f(a,b,i,j)
        character *(*)  b
  dimension a(*)
  print*, i, a(1), a(2), a(3)
        print*, j
        print*, "String in F77=",b(1:j)
        open(11,file=b(1:j))
        write(11,*) "writing in f77"
        close(11)
  call c2(i,a)
  return
  end


The program 'c' was built and executed on a linux x86 system as follows

% pgf77/f90 -c f.f
% pgCC -o c c.C f.o -lpgftnrtl -lpgc
% pgCC -o c90 c.C
f.o -lpgf90 -lpgf90_rpm1 -lpgf902 -lpgf90rtl -lpgftnrtl -lm -lpgc

% c

string length = 5
            3   10.00000       20.00000       30.00000
            5
 String in F77=a.dat
CALLBACK 3 10.000000 20.000000 30.000000


On an NT system, under PGI Workstation, create the following object files using pgf77/f90.

PGI> pgf77 -c -Munix f.f
PGI> pgf90 -o f90.o -c -Munix f.f

Under VC++ The file c.C opened as a C++ source file. It was compiled w/o errors.

The object file c.obj was copied to the pgi working area my_dir milesto c.o.


Linking on NT using pgf90/pgf77 (not necessary to recompile, but okay to)

PGI> pgf90 -o c90 c.o f.f -Munix -Mnomain -msvcrt -mslibs
PGI> pgf77 -o c c.o f.f -Munix -Mnomain -msvcrt -mslibs


Linking on NT using VC++

Under Project>Settings

In the Link page, add the following objects and libraries to the 'Object/library modules' window, at the beginning:

for f.o

C:\PGI\nt86\lib\pgstdinit-mslibs.o
my_dir\f.o
C:\PGI\nt86\lib\libpgftnrtl.a
C:\PGI\nt86\lib\libpgc.a
libc.lib
oldnames.lib

for f90.o

C:\PGI\nt86\lib\pgstdinit-mslibs.o
my_dir\f90.o
C:\PGI\nt86\lib\libpgf90.a
C:\PGI\nt86\lib\libpgf90_rpm1.a
C:\PGI\nt86\lib\libpgf902.a
C:\PGI\nt86\lib\libpgf90rtl.a
C:\PGI\nt86\lib\libpgftnrtl.a
C:\PGI\nt86\lib\libpgc.a
libc.lib
oldnames.lib

set the flag 'Ignore all default libraries'

The executables run as on linux86


How do you build and link pgf77-pgf90 OpenMP routines from Visual C++?

The big question is not whether you can or not, but whether the resulting application is truly running parallel. This example assumes a version of NT (service pack 4.0 or greater?) that supports SMP.

Here is a simple program that wastes cycles but scales well. It times the process so that a successful execution on two processors will take half the time of one processor.

Here is a timer we use, dclock. It is written in assembler.

dclock.s

        .file   "dclock-pentium.s"
        .align    8
        .data
# .clock:  .double 0.0000000075          # 133MHz
# .clock:  .double 0.00000000666667      # 150 MHz
# .clock:  .double 0.0000000060          # 166 MHz
.clock: .double 0.0000000050          # 200 MHz
#  .clock: .double 0d4.28571429183673480000e-09 # 233.3333 MHz
# .clock:  .double 0.00000000333333      # 300 MHz
# .clock:  .double 0.00000000222223      # 450 MHz
# .clock:  .double 0.000000002           # 500 MHz
# .clock:  .double 0.0000000018181818    # 550 MHz
# .clock:  .double 0.0000000016666667    # 600 MHz
# .clock:  .double 0.0000000015384615    # 650 MHz
# .clock:  .double 0.0000000014285714    # 700 MHz
# .clock:  .double 0.0000000013658095    # 733 MHz
# .clock:  .double 0.0000000013333333    # 750 MHz
# .clock:  .double 0.0000000012500000    # 800 MHz
# .clock:  .double 0.000000001           # 1.0 GHz
# .clock:  .double 0.000000000666        # 1.5 GHz
# .clock:  .double 0.00000000059         # 1.7 GHz
# .clock:  .double 0.0000000005          # 2.0 GHz

.low:   .long 0x00000000
.high:  .long 0x00000000
        .text
        .align    4
        .globl   _DCLOCK@0, dclock, _dclock, _dclock_, dclock_
_DCLOCK@0:
dclock:
_dclock:
_dclock_:
dclock_:
        .byte   0x0f, 0x31

        movl    %eax, .low
        movl    %edx, .high

        fildll  .low
        fmull   .clock
        ret


it is set for a 200 MHz cpu, so use the .clock val that applies to your machine.

Here is a c main program that you will compile with VC++

ex4main.c
#include <stdio.h>
#include <stdlib.h>
void ex4_(int *);
void main(int argc, char** argv)
{
   int i;
   if(argc == 1) exit(0);
   i = atoi(argv[1]);
   printf( "(main) calling ex4 with i = %d \n", i );
   ex4_(&i);
}

Here is a fortran OpenMP routine that will use 2 cpus if you have them. Compile it.

pgf77 -mp -c -Munix ex4,f

ex4.f

subroutine ex4(i)
        integer i,k
        integer omp_get_num_procs, omp_get_max_threads
        real*8 dclock, time1, time2
        print *,"num procs   =", omp_get_num_procs()
        print *,"max threads =", omp_get_max_threads()
        call omp_set_num_threads(1)
        time1 = dclock()
!$omp parallel
!$omp do
         do k = 1, 2
            call delay(i)
         enddo
!$omp end parallel
        time2 = dclock() - time1
        print *, " 1 cpu test - delay value doubled =", i*2,
     *    " time =", time2, " seconds"
        if (omp_get_num_procs() .ge. 2) then
             call omp_set_num_threads(2)
             print *, " more than 1 cpu, trying parallel"
        else
             print *, " only 1 cpu, program exiting"
             return
        endif
        time1 = dclock()
!$omp parallel
!$omp do
         do k = 1, 2
            call delay(i)
         enddo
!$omp end parallel
        time2 = dclock() - time1
        print *, " 2 cpu test - delay value doubled =", i*2,
     *    " time =", time2, " seconds"
        return
        end


Here is a simple delay program that wastes cycles w/o reading memory, so it should scale well.

       subroutine delay(n)
       integer n
       integer i
       do i=1,n
          call abc()
       end do
       return
       end
       subroutine abc()
       integer i
       do i=1,1000000
           call def()
       end do
       return
       end
       subroutine def()
         return
       end


To link using pgf77, do the following

pgf77 -Mnomain -Munix -mp -msvcrt -mslibs -o ex4 ex4main.o ex4.f delay.f
dclock.s

Note that ex4main.obj was renamed ex4main.o (not necessary) Also note that the -mslibs switch causes the MS linker to be used.


To link using VC++

pgf77 -c -Munix -mp ex4.f
pgf77 -c -Munix dclock.s
pgf77 -c -Munix delay.f

in VC++ project settings, add the following files to the object/library module section of Link page in the front (you may also want to set the nodefault libs flag)

C:\PGI\nt86\lib\pgstdinit-mslibs.o
my_dir\ex4.o
my_dir\delay.o
my_dir\dclock.o
C:\PGI\nt86\lib\libpgmp.a  <---- only needed when compiling -mp
C:\PGI\nt86\lib\libpgftnrtl.a
C:\PGI\nt86\lib\libpgc.a
libc.lib
oldnames.lib



On a machine configured with dual cpus, it should execute as follows-- (note that we execute the program with a value that will delay some amount - 113 for a 200 MHz machine was ~4 seconds)

PGI$ ex4main.exe 113
(main) calling ex4 with i = 113
 num procs   =           2
 max threads =           1
  1 cpu test - delay value doubled =         226 time = 8.014712320000399      seconds
  more than 1 cpu, trying parallel
  2 cpu test - delay value doubled =         226 time = 4.028287394990912      seconds
Click me