Programmieren in Fortran 90/95


  1. Mixed-Language-Programming (Einbinden von C/C++-Routinen in Fortran-Programme)
  2. Ein einfaches Beispiel:

    Eine C++-Routine bestimmt nach der Formel von Pythagoras die Länge der Hypotenuse in einem rechtwinkligen Dreieck

    Die C++-Routine crout.cpp:

    // C++ - Routine
    #include <iostream.h>
    #include <math.h>
    
    extern "C" void pythagoras (float a, float b, float *c)
    {
            *c = (float) sqrt(a*a+b*b);
    }
    

    Diese C++-Routine soll in ein Fortran 90 - Programm eingebunden werden. (Handelt es sich nicht um C++, sondern um reinen C-Code (.c) so sollte iostream.h durch stdio.h ersetzt werden. Auch wird extern "C" vor den C-Routinen nicht gebraucht.) Die weiteren Abläufe sind für C++ und C-Programme identisch.

    Das Fortran-Programm fmain.f90:

    ! Aufrufen einer C++ bzw. C-Routine von Fortran aus
    
    ! Die C-Routine wird innerhalb eines Modules deklariert
    module cproc
       interface  ! die Schnittstelle zur C++-Routine
          subroutine pythagoras (a, b, res)
             !DEC$ ATTRIBUTES C :: pythagoras     ! Compiler-Directiven
             !DEC$ ATTRIBUTES REFERENCE :: res    ! systemabhaengig: hier CVF, Windows
             real :: a, b, res
          end subroutine
        end interface
    end module
    
    
    program fmain
       use cproc 
       implicit none
       real :: x, y, z
    
          write(*,*) ' Berechnung der Hypotenusenlaenge eines rechtwickligen Dreiecks'
          write(*,*) ' Geben Sie die beiden Seitenlaengen ein, die den rechten Winkel'
          write(*,*) ' einschliessen:'
          read(*,*) x, y
    
          call pythagoras(x,y,z)
          write(*,*) ' Die Laenge der Hypotenuse betraegt: ', z 
    end program fmain
    

    Im Fortran-Programm wird fuer die C-Routine ein Interface-Block definiert, der Angaben zum Datenaustausch zwischen Fortran und C enthält. Dieser Interface-Block wird in ein Modul eingebunden, welches dann wieder von anderem Programmteilen (hier vom Hauptprogramm) genutzt wird.

    Weitere Informationen und Unterstützung zu der Thematik erhalten Sie im "Programming Guide" unter "Mixed Language Programming". Das Beispiel ist im wesentlichen dem Handbuch vom CVF-Compiler (unter Programming Guide, Mixed Language Programming) entnommen. Dort sind auch die notwendigen Compiler-Directiven angeführt. Die Anweisungen mit !DEC$ sind COMPILER-Directriven Notwendigkeit von Form und Inhalt sind abhängig von den verwendeten Systemen. Für weitere Informationen zum "Mixed-Language-Programming" mit den dem CVF unter Windows empfiehlt es sich, in den Hilfeseiten des CVFs nachzuschlagen.

    Windows: Compilieren mit dem CVF-Compiler (in der Entwicklungsumgebung)

    1. Als Pendant zum CVF v6.6 wird als C/C++-Compiler der Microsoft Visual C++ v6.0 benötigt. Dieser muss auf dem Rechner installiert sein.
    2. Compilieren in der Entwicklungsumgebung
      1. leeres Projekt erzeugen (Fortran Console Application) und benennen (z.B. hypo_test)
      2. das fmain.90 - Programm erstellen bzw. hinzufügen
      3. in der Menüleiste unter Project -> Export Makefile wählen und hypo_test.mak schreiben lassen. Dabei "Write dependencies when writing makefiles" aktivieren
    3. Das Programm "builden"
      • Beim Linken kommt noch eine Warnung. Diese lässt sich vermeiden, wenn man unter Project -> Project Settings auf der "Karteikarte" mit dem Titel "Link" das Häkchen bei "Link incrementally" entfernt.
    4. Programm ausführen und testen
      • arbeitet als Fortran Console Application und bringt die richtigen Ergebnisse

    Windows: Compilieren mit dem CVF-Compiler (an der Kommandozeile)

    1. Als Pendant zum CVF v6.6 wird als C/C++-Compiler der Microsoft Visual C++ v6.0 benötigt. Dieser muss auf dem Rechner installiert sein.
    2. Compilieren an der Kommandozeile (in der DOS-BOX)
      Die beiden Programme crout.cpp und fmain.f90 sollen sich im gleichen Verzeichnis befinden.
    3. Zur Initialisierung von Pfad- und Makrovariablen muss zunächst die Datei DFVARS.BAT aus dem Verzeichnis
      ...\Microsoft Visual Studio\DF98\BIN
      ausgeführt werden
    4. Compilieren und Linken (Builden)
      • cl -c crout.cpp
        df fmain.f90 crout.obj /link /out:prog.exe
      Hier wird zunächst mit der Kommandozeilenform des Intel-C++-Compilers aus der C++-Routine ein Objectcode erzeugt (crout.obj). Im zweiten Schritt wird die Fortran 90 - Routine fmain.f90 mit dem CVF-Compiler (df) in Objectcode übersetzt. Die beiden Objectcode-Files werden danach mit dem df zusammen mit den notwendigen Systembibliotheken zum ausführbaren Programm prog.exe verknüpft.
    5. Programm ausführen und testen
      • mit prog oder prog.exe an der Kommandozeile
      • bringt die richtigen Ergebnisse

      Achtung: wurde der 3. Schritt vergessen, erscheint u.U. später beim Linken die Fehlermeldung "LINK: fatal error LNK1181: cannot open input file "dfor.lib"", weil aufgrund der fehlenden Initialisierung der Pfad zu den Fortran-Betriebssystem-Bibliotheken nicht gefunden wird.

      Unix: Mixed-Language-Programming

      Wie bereits in Unix: die automatische Generierung eines universellen Makefiles besprochen, kann das Perl-Script makemake von Michael Wester dazu verwendet werden, aus Quellprogrammen in C, Fortran 90 und FORTRAN 77 ein Makefile für die Compilierung der verschiedenen Quellen zu generieren.

      Voraussetzung ist, dass

      • auf dem Rechner Perl (und die entsprechenden Compiler) installiert sind
      • das Perl-Script ausfürbar gemacht wurde
        chmod u+x makemake
      • alle für das Programm benötigten Quelltexte (und nur diese) in einem eigenen Verzeichnis stehen
      In unserem Fall handelt es sich um die C-Routine crout.c, die der C++-Routine crout.cpp entspricht:

      /* C - Routine */
      #include 
      #include 
      
      void pythagoras (float a, float b, float *c)
      {
              *c = (float) sqrt(a*a+b*b);
      }
      

      die in das Fortran 90 - Programm fmain.f90 eingebunden werden soll.

      ! Demoprogramm:
      ! Aufrufen einer C-Routine von Fortran aus
      
      ! Die C-Routine wird innerhalb eines Modules deklariert
         module cproc
            interface  ! definierte Schnittstelle 
               subroutine pythagoras (a, b, res)
                       !DEC$ ATTRIBUTES C :: pythagoras
                       !DEC$ ATTRIBUTES REFERENCE :: res
                   real :: a, b, res
               end subroutine
            end interface
              end module
      
      
      program fmain
          use cproc 
              implicit none
              real :: x, y, z
              
              write(*,*) ' Berechnung der Hypotenusenlaenge eines rechtwickligen Dreiecks'
              write(*,*) ' Geben Sie die beiden Seitenlaengen ein, die den rechten Winkel'
              write(*,*) ' einschliessen:'
      
              read(*,*) x, y
              
              call pythagoras(x,y,z)
              write(*,*) ' Die Laenge der Hypotenuse betraegt: ', z 
      end program fmain
      

      Bitte beachten Sie, dass auch unter Unix weiterhin die Compiler-Directiven für den CVF-Compiler verwendet werden. Dies ist möglich und notwendig, weil als Fortran 90 - Compiler auf dem Rechner, auf dem die Compilierung vorgenommen wird, die Unix-Version dieses Compilers im Einsatz ist. Wird ein anderer Fortran 90 - Compiler verwendet, sind die benötigten Directiven auf dem Handbuch des sich im Einsatz befindlichen Compilers zu entnehmen.

      Durch den Aufruf von
      ./makemake prog
      wird das Makefile

      PROG =  prog
      
      SRCS =  fmain.f90 crout.c
      
      OBJS =  fmain.o crout.o
      
      LIBS =
      
      CC = cc
      CFLAGS = -O
      FC = f77
      FFLAGS = -O
      F90 = f90
      F90FLAGS = -O
      LDFLAGS = -s
      
      all: $(PROG)
      
      $(PROG): $(OBJS)
              $(F90) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
      
      clean:
              rm -f $(PROG) $(OBJS) *.mod
      
      .SUFFIXES: $(SUFFIXES) .f90
      
      .f90.o:
              $(F90) $(F90FLAGS) -c $<
      
      fmain.o: fmain.o
      

      generiert. Hier kann man noch bezüglich der Compiler und der Compilerflags Änderungen anbringen, z.B. soll als C-Compiler statt dem cc der gcc verwendet werden. Deshalb wird die Zeile
         CC = cc
      durch
         CC = gcc
      ausgetauscht. Der Aufruf von
         make
      lassen sich die einzelnen Programmteile fehlerfrei compilieren und zum ausführbaren Programm prog linken

      
         f90 -O -c fmain.f90
         gcc -O -c crout.c
         f90 -s -o prog fmain.o crout.o 
      

      Mit dem 1. Befehl wird aus dem Fortran 90 - Programm fmain.f90 mittels des Compilers f90 optimierter (Flag -O) Objectcode (Flag -c, Dateiname fmain.o) erzeugt.

      Mit der zweiten Anweisung wird mit dem GNU-C-Compiler (gcc) der C-Code crout.c in optimierten Objectcode (crout.o) übersetzt.

      Der f90 wird schließlich herangezogen, um die beiden Objectcode Dateien zusammen mit Systembibliotheken zum ausführbaren Programm prog zu linken. Die Flag -s stellt eine optimierende Linker-Flag dar und mit -o wird gewünschte Name des Executables (hier: prog) angegeben.

      Anstatt mit dem makemake -Script von Michael Wester zu arbeiten, hätte man analog an der Kommandozeile diese drei Anweisungen auch direkt eingeben können.

      Der Aufruf von

         ./prog
      
      startet das Executable und gibt die richtigen Resultate
        Berechnung der Hypotenusenlaenge eines rechtwickligen Dreiecks
        Geben Sie die beiden Seitenlaengen ein, die den rechten Winkel
        einschliessen:
      3. 4.0
        Die Laenge der Hypotenuse betraegt:    5.000000    
      

      Fehlen die benötigten Compilerdirectiven, treten beim Linken Fehler auf. Hier ist es also notwendig, die Programme speziell nach den Erfordernissen der Compiler anzupassen. Damit werden diese Mixed-Language-Programmpakete compiler- und betriebssystemabhägig und sich sind mehr so einfach - wie reine Fortran 90 - Programme portierbar.

      Unabhängig vom Betriebssystem gilt:
      Die Verknüpfung von C bzw. C++-Routinen mit Fortran-Code kann, besonders wenn Zeichenketten, Pointer etc. in den Routinen vorkommen, sehr viel komplexer als in diesem einfachen Beispiel werden.

Zurück zur Vorlesungsseite


Heidrun.Kolinsky@uni-bayreuth.de
(Dr. Heidrun Kolinsky, Rechenzentrum der Universität Bayreuth, Gebäude NW2, Raum 159, Universitätsstraße 30, D-95440 Bayreuth, Tel. 0921/55-2687)