简体   繁体   中英

How to link a fortran subroutine to a cpp main program?

I am trying to compile a c++ program but it does not work. At first, I should said that c++ is not a language I really know, I use Fortran. Anyway, the main c++ program calls a fortran subroutine. I can compile this subroutine but when I want to compile the c++ program there is a link error. The real program is just huge and calls many subroutines, so I did a simple test (simple program calling just one subroutine) and it does not work as well! When I want to create the .x my subroutine is undefined. Here is the c++ program (test-TQINIT.cpp) and the subroutine (TQINIT.f).

test-TQINIT.cpp:

  #include <iostream>

  using namespace std;

  extern "C"
  {
  void  TQINIT_(int*, int*);
  }

  main()
  { int NWG;
        NWG=80000;
    int *IWSG = new int[NWG];
 TQINIT_(IWSG,&NWG);
  }

TQINIT.f:

  SUBROUTINE TQINIT(IWSG,NWG)
  IMPLICIT NONE

  INTEGER NWG
  INTEGER IWSG(NWG)
  LOGICAL TQG2ERR
  INTEGER IERR

  CALL TQRSERR

  CALL TQINI(NWG,IWSG)

  IF (TQG2ERR(IERR)) THEN
    WRITE(6,*)'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
    WRITE(6,*)'ERROR INITIALIZING (TQINIT) !!!'
    WRITE(6,*)'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
    STOP
  ENDIF

  END

I compile the subroutine using:

  gfortran -c TQINIT.f 

and get a TQINIT.o

Then I compile the main program using:

  g++ -c test-TQINIT.cpp 

and get a test-TQINIT.o.

Then for create the .x I use (TQINIT.f need the library):

  g++ test-TQINIT.o TQINIT.o -L/usr/local/thermocalc/3.0/SDK/TQ8 -ltq-linux-x86_64-gfortran44-8 -o test-TQINIT.x

This is what I get:

  test-TQINIT.o: In function `main':
  test-TQINIT.cpp:(.text+0x33): undefined reference to `TQINIT_'
  collect2: ld returned 1 exit status

I hope someone will be able to help me. Thank you by advance.

Fortran is case-insensitive, and the name of the subroutines in the object file normally (as far as I know) end up in lowercase with an underscore, so yours is probably named tqinit_ and not TQINIT_ , so your call in C++ should be lowercase.

You can verify the name in the object file with the objdump -t TQINIT.o command given in Alexander Vogt's answer, or the simpler nm TQINIT.o which is more terse.

If you use the ISO_C_BINDING in Fortran, you will have control over the precise routine names that will be seen by the other language, eg, case, no underscores. You can also declare the arguments so that consistency with C/C++ will be guaranteed. For more on this topic, see https://stackoverflow.com/questions/tagged/fortran-iso-c-binding

I'm no expert on mixing C and Fortran, but I have always linked the Fortran Code directly using

g++ test-TQINIT.cpp TQINIT.o -L/usr/local/thermocalc/3.0/SDK/TQ8 \
    -ltq-linux-x86_64-gfortran44-8 -o test-TQINIT.x

instead of compiling those two files separately and then linking... Perhaps this helps (although your way should work as well, at least it does with the simple example I tried).

BTW: You can find out how the functions in your Fortran object are called by issuing

objdump -t TQINIT.o

This should give you the correct function name to call.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM