Zum Inhalt springen

Fortran: Anhang E

Aus Wikibooks
<< zur Fortran-Startseite
< Anhang D: Quellcodedokumentation Anhang F: Style Guides >




Einleitung

[Bearbeiten]

Hier wird keine Einführung in die Verwendung und Syntax von make- und config-Tools geboten, sondern nur kurz auf einige Spezialitäten hingewiesen, die bei den ersten Einsatzversuchen derartiger Werkzeuge im Zusammenhang mit Fortran zu beachten sind.

Grundsätzlich kann bei der Erstellung von Makefiles und Konsorten eine ähnliche Vorgehensweise wie bei konventionellen C-Programmen gewählt werden. Es ist bei Fortran-Programmen jedoch zu bedenken, dass bei Verwendung von Modulen mod-Dateien generiert werden (ab Fortran 90). Diese mod-Dateien sind in weiterer Folge für das Kompilieren von moduleinbindenden Quellcodedateien und den Linkvorgang von entscheidender Bedeutung. Somit ist bei hierarchisch verzweigten Quellcodeverzeichnisbäumen Obacht zu geben, dass jeweils auch Zugriff zu diesen mod-Dateien gegeben ist. Dies kann geschehen durch

  • geeigneten Aufbau der Makefiles,
  • durch Verwendung von Tools, die solche Abhängkeiten automatisch auflösen
  • oder auch durch explizite Bekanntgabe der entsprechenden Pfade an Compiler und Linker.

Explizite Bekanntgabe von Modulpfaden

[Bearbeiten]

gfortran

[Bearbeiten]

Standardmäßig werden include- und mod-Dateien im aktuellen Verzeichnis gesucht. Die Suche kann aber mit folgendem Compilerschalter auf andere Pfade ausgedehnt werden:

  • -I...: Suchpfad für
    • include-Dateien
    • mod-Dateien
erweitern.

Standardmäßig werden mod-Dateien in das aktuelle Verzeichnis geschrieben. Dieses Verhalten kann mit folgendem Schalter geändert werden:

  • -J...: Legt Verzeichnis fest, in das die mod-Dateien geschrieben werden, gleichzeitig auch Suchpfad für mod-Dateien.
(Alias für -M... um Konflikte mit bisherigen GCC-Optionen zu vermeiden)
  • -I...: Suchpfad für
    • include-Dateien
    • mod-Dateien
erweitern.

GNU Make

[Bearbeiten]

GNU Make erkennt derzeit leider nur FORTRAN 77-Dateien mit der Endung .f automatisch. Für "free source form"-Fortran-Programme sind daher einige vorbereitende Arbeiten nötig, um dann auch die Vorteile (und Nachteile) der impliziten Anwendung von "Pattern Rules" genießen zu dürfen. Werden alle Makeschritte für Fortran-Dateien explit vorgegeben, dann kann man sich dies natürlich sparen.

Ein einfaches Beispiel

[Bearbeiten]

Es sei ein einfaches Beispiel gegeben, das eine FORTRAN 77-, eine Fortran 2003- und eine C-Datei enthält. Diese Dateien liegen im selben Verzeichnis.

Quellcode-Dateien

[Bearbeiten]

main.f90:

Fortran 2003 (oder neuer)-Code
! Das Hauptprogramm
program main
  implicit none 

  interface
    function addition( a, b ) bind( c )
      use, intrinsic :: iso_c_binding
      real( kind = c_float ), value :: a
      real( kind = c_float ), value :: b
      real( kind = c_float )        :: addition
    end function addition
    
    subroutine sub()
    end subroutine sub
  end interface

  call sub()
  write (*,*) addition( 2.5, 3.3 )
  
! Ausgabe:  
!    Summe =
!      5.8  
end program main

func.c:

Programmcode
/* Addiere zwei Zahlen */
float addition(float a, float b)
{
  return (a + b);  
}

sub.f:

0   . |  1    .    2    .    3    .    4    .    5    .    6    .    7 |  .    8  
12345678901234567890123456789012345678901234567890123456789012345678901234567890
C  Eine einfache FORTRAN 77-Subroutine          
      SUBROUTINE SUB
      WRITE( *, * ) 'Summe ='   
      END
12345678901234567890123456789012345678901234567890123456789012345678901234567890
0   . |  1    .    2    .    3    .    4    .    5    .    6    .    7 |  .    8  

Explizite Vorgabe der Makeschritte

[Bearbeiten]

Makefile:

FC = gfortran        # oder ifx, ...

prog: main.o func.o sub.o
	$(FC) -o $@ $^

main.o: main.f90
	$(FC) -c $^

func.o: func.c
	$(CC) -c $^
	
sub.o: sub.f
	$(FC) -c $^	

Nutzung von "Pattern Rules"

[Bearbeiten]

Makefile:

FC  = gfortran      # oder ifx, ...

%.o: %.f90
	$(FC) -c $<

prog: main.o func.o sub.o
	$(FC) -o $@ $^

Die Generierung der Objektdateien aus den Quellcodedateien geschieht hier implizit. Für C- und FORTRAN 77-Dateien sucht sich GNU Make die entsprechenden Regeln aus seiner internen Regel-Datenbank. Für .f90-Dateien wurde der entsprechende Befehl hier von uns explizit durch eine "Pattern Rule" vorgegeben.

Die make-Ausgabe sieht so aus:

gfortran -c main.f03
cc    -c -o func.o func.c
gfortran   -c -o sub.o sub.f
gfortran -o prog main.o func.o sub.o

Solange die Quelldateien im selben Verzeichnis liegen, ist die Erstellung eines Makefiles ziemlich einfach. Wenn aber die Quelldateien gestaffelt in Unterverzeichnissen gespeichert sind und womöglich noch Abhängigkeiten von einem Unterverzeichis zum anderen gegeben sind, dann kann die ganze Sache ziemlich kompliziert werden. Im Anschluss wird eine einfache nichtrekursive Make-Variante gezeigt.

Nichtrekursive Make-Variante

[Bearbeiten]

Vor der Programmerstellung:

-- (D) projektverzeichnis
 |-- (F) Makefile
 |-- (F) module.mk
 |-- (F) main.f90
 |
 |-- (D) kreis
 | |-- (F) module.mk
 | |-- (F) kreis.f90
 | |-- (F) kreissegment.f90
 |
 |-- (D) quadrat
 | |-- (F) module.mk
 | |-- (F) quadrat.f90 

(D) ... directory
(F) ... file

Nach der Programmerstellung durch Aufruf von make:

-- (D) projektverzeichnis
 |-- (F) Makefile
 |-- (F) module.mk
 |-- (F) main.f90
 |-- (F) main.o
 |-- (F) prog
 |-- (F) kreis.mod
 |-- (F) kreissegment.mod
 |-- (F) quadrat.mod
 |
 |-- (D) kreis
 | |-- (F) module.mk
 | |-- (F) kreis.f90
 | |-- (F) kreissegment.f90
 | |-- (F) kreis.o
 | |-- (F) kreissegment.o
 |
 |-- (D) quadrat
 | |-- (F) module.mk
 | |-- (F) quadrat.f90 
 | |-- (F) quadrat.o

Quellcode-Dateien

[Bearbeiten]

main.f90:

Fortran 90/95-Code (free source form)
program main
  use kreis
  use kreissegment
  use quadrat
  implicit none
  
  call k()
  call q()
  call ks()
end program main 

kreis/kreis.f90:

Fortran 90/95-Code (free source form)
module kreis
  implicit none
 
  private
  public :: k
    
  contains
    subroutine k()
      print *, "Ich bin ein Kreis!"
    end subroutine k
end module kreis

kreis/kreissegment.f90:

Fortran 90/95-Code (free source form)
module kreissegment
  use kreis
  implicit none
  
  private
  public :: ks
  
  contains
    subroutine ks()
      call k()
      print *, "Hihi, war nur ein Scherz. Ich bin ein Kreissegment!"
    end subroutine ks
end module kreissegment

quadrat/quadrat.f90:

Fortran 90/95-Code (free source form)
module quadrat
  implicit none

  private
  public :: q
  
  contains
    subroutine q()
      print *, "Ich bin ein Quadrat!"
    end subroutine q
end module quadrat

Makefile, Include-Dateien

[Bearbeiten]

Makefile:

FC       := gfortran   # oder ifx, ...
SRC      := 

OBJ      = $(subst .f90,.o,$(SRC))

%.o: %.f90
	$(FC) -c -o $@ $<

include kreis/module.mk
include quadrat/module.mk
include module.mk

prog: $(OBJ)
	$(FC) -o $@ $^

module.mk:

SRC += main.f90

kreis/module.mk:

SRC += kreis/kreis.f90 kreis/kreissegment.f90

quadrat/module.mk:

SRC += quadrat/quadrat.f90

Es gibt nur ein Makefile im Projekthauptverzeichnis. Sämtliche unterverzeichnisspezifischen Details (hier nur die Bekanntgabe der Quellcodedateien) werden in den jeweiligen Unterverzeichnissen in eigenen Include-Dateien (.mk) festgelegt und in das Makefile eingebunden. Da, anders als beim rekursiven Make, nicht in die einzelnen Unterverzeichnisse gewechselt wird, werden allfällige mod-Dateien auch nur in das Projekthauptverzeichnis (= das aktuelle Verzeichnis) geschrieben.

Weiterführende Make-Infos

[Bearbeiten]

CMake

[Bearbeiten]

CMake ist kein Make-Klon, sondern ein moderner Autotools-Ersatz.

Gleiches Beispiel wie bei #Nichtrekursive_Make-Variante, es muss in diesem Fall nur eine CMakeLists.txt-Datei im Projekthauptverzeichnis erstellt werden. Makefile und dazugehörende Dateien werden automatisch beim cmake-Aufruf erstellt.

CMakeLists.txt:

PROJECT(bsp Fortran)

SET(src
      main.f90
      kreis/kreis.f90
      kreis/kreissegment.f90
      quadrat/quadrat.f90
   )

ADD_EXECUTABLE(prog ${src})

Generieren der Makefiles, etc.:

  • FC=gfortran cmake .
-- Check for working Fortran compiler: /xyz/bin/g95
-- Check for working Fortran compiler: /xyz/bin/g95 -- works
-- Checking whether /xyz/bin/g95 supports Fortran 90
-- Checking whether /xyz/bin/g95 supports Fortran 90 -- yes
-- Configuring done
-- Generating done
-- Build files have been written to: /abc/projektverzeichnis

Mittels FC=... wird der zu verwendende Fortran-Compiler festgelegt. Wenn irgendein auf dem System installierter Fortran-Compiler verwendet werden soll, kann diese Vorgabe auch entfallen. In der CMakeLists.txt muss die Programmiersprache Fortran ausdrücklich aktiviert werden. Entweder wie hier im PROJECT-Statement oder alternativ auch über die ENABLE_LANGUAGE-Anweisung.


Programmerstellung:

  • make
Scanning dependencies of target prog
[ 25%] Building Fortran object CMakeFiles/prog.dir/kreis/kreis.o
[ 50%] Building Fortran object CMakeFiles/prog.dir/kreis/kreissegment.o
[ 75%] Building Fortran object CMakeFiles/prog.dir/quadrat/quadrat.o
[100%] Building Fortran object CMakeFiles/prog.dir/main.o
Linking Fortran executable prog


CMake-Homepage:

SCons

[Bearbeiten]

Die Konfigurations-Dateien von SCons sind Python-Dateien.

Ein einfaches Beispiel

[Bearbeiten]

Gegeben seien die weiter oben gelisteten Dateien kreis/kreis.f90 kreis/kreissegment.f90 quadrat/quadrat.f90 main.f90. Um dieses Beispiel zu bauen, erstellt man im Quellcode-Verzeichnis zuerst eine SConstruct-Datei, z.B.:

src_files = Split('kreis/kreis.f90 kreis/kreissegment.f90 quadrat/quadrat.f90 main.f90')
Program('prog', src_files)

Dann startet man scons in einer Konsole (zuvor natürlich, wenn noch nicht geschehen, in das entsprechende Quellcode-Verzeichnis wechseln) und erhält z.B. folgende Ausgabe:

scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
gfortran -o kreis/kreis.o -c kreis/kreis.f90
gfortran -o kreis/kreissegment.o -c kreis/kreissegment.f90
gfortran -o quadrat/quadrat.o -c quadrat/quadrat.f90
gfortran -o main.o -c main.f90
gfortran -o prog kreis/kreis.o kreis/kreissegment.o quadrat/quadrat.o main.o
scons: done building targets.

Gestartet wird das erstellte Programm in diesem Beispiel mittels ./prog. Ausgabe:

Ich bin ein Kreis!
Ich bin ein Quadrat!
Ich bin ein Kreis!
Hihi, war nur ein Scherz. Ich bin ein Kreissegment!

Bereinigt werden kann das Verzeichnis (oder können die Verzeichnisse) mit scons -c. Als Ausgabe erscheint dann in der Konsole:

scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Cleaning targets ...
Removed kreis/kreis.o
Removed kreis.mod
Removed kreis/kreissegment.o
Removed kreissegment.mod
Removed main.o
Removed quadrat/quadrat.o
Removed quadrat.mod
Removed prog
scons: done cleaning targets.

Das wars. Für weiterführende Informationen siehe die nachfolgenden Weblinks.

[Bearbeiten]

<< zur Fortran-Startseite
< Anhang D: Quellcodedokumentation Anhang F: Style Guides >