This is the Title of the Book, eMatter Edition
Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved.
|
279
First
Max.
Linie
Max.
Linie
Anhang B
ANHANG B
Grenzbereiche
Wie Sie gesehen haben, sind mit GNU make bemerkenswerte Dinge möglich. Tatsächlich
sind mir nur wenige Fälle bekannt, die
make in der Version 3.80 mit seiner unglaublich
mächtigen
eval-Anweisung an die Grenzen treiben. In diesem Kapitel wollen wir diese
Grenzen noch ein bisschen ausdehnen.
Datenstrukturen
Eine Möglichkeit, die man sich von make bei der Erstellung eines aufwändigen Makefile
gelegentlich wünschen würde, sind komplexe Datenstrukturen. Natürlich kann man sol-
che Strukturen in einem gewissen Rahmen simulieren, indem man zum Beispiel Variab-
lennamen mit Hilfe von Punkten in Teilnamen zerlegt. Je nach Geschmack kann man
auch
-> verwenden.
file.path = /foo/bar
file.type = unix
file.host = oscar
Diese »Datenstruktur« file kann man mit Hilfe von abgeleiteten Variablennamen sogar
an eine Funktion »übergeben«:
define remote-file
$(if $(filter unix,$($1.type)), \
/net/$($1.host)/$($1.path), \
//$($1.host)/$($1.path))
endef
Auf die Dauer ist dieser Notbehelf aber trotzdem unbefriedigend:
Man kann nicht ohne weiteres eine neue »Instanz« dieser »Struktur« erzeugen.
Zunächst einmal muss für eine neue Pseudoinstanz auch ein neuer Name generiert
werden. Ferner sollten die einzelnen Felder
1
belegt werden, da man anderenfalls
keine Garantie hat, dass die Pseudoinstanzen wirklich dieselben Felder haben.
1 Im englischen Original wird der Begriff »slot« verwendet. Das ist für das Verständnis des Abschnitts von Bedeu-
tung, wenn man Funktionsnamen wie »defslot« liest. – Anm.d.Ü.
This is the Title of the Book, eMatter Edition
Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved.
280
|
Anhang B: Grenzbereiche
Links
Max.
Linie
Max.
Linie
Die Struktur existiert nur in der Vorstellung des Benutzers als eine Menge verschie-
dener
make-Variablen. Wünschenswert wäre dagegen die Existenz als Element einer
einheitlichen Menge mit einem eindeutigen Namen. In diesem Fall könnte man die
Struktur bzw. eine Referenz auf die Struktur einer Variable zuweisen. So kann man
nur den Namen als Argument übergeben und muss sich mit einer komplexen und
unleserlichen Syntax herumschlagen, wenn man die einzelnen Felder lesen oder ver-
ändern will.
Der Zugriff auf ein Feld ist in keinster Weise gesichert. Ein Tippfehler in einem
beliebigen Teil des Namens führt dazu, dass ein falscher oder nicht definierter Wert
gelesen wird, ohne dass
make eine Warnung ausgeben würde.
Aber die Funktion
remote-file enthält einen Hinweis auf eine vollständigere Lösung.
Gehen wir also davon aus, dass wir tatsächlich Instanzen einer Struktur mit Hilfe abgelei-
teter Variablennamen implementieren wollen. Frühe objektorientierte Lisp-Systeme
haben ähnliche Techniken benutzt, einige tun es sogar heute noch. Die Instanzen einer
Struktur namens
file-info können ja durch symbolische Namen wie file_info_1 reprä-
sentiert sein.
Eine andere Instanz wäre dann
file_info_2. Die Felder der Struktur ergeben sich dann
über die folgenden Variablennamen:
file_info_1_path
file_info_1_type
file_info_1_host
Nachdem die Instanz einen symbolischen Namen hat, kann man sie in einer oder mehre-
ren Variablen ablegen. Ob es sich dabei um einfache oder rekursive Variablen handelt,
bleibt dem Programmierer überlassen:
before_foo = file_info_1
another_foo = $(before_foo)
Wir können Funktionsaufrufe benutzen, um Felder von file-info im Stil von Get- oder
Set-Methoden zu lesen:
path := $(call get-value,before_foo,path)
$(call set-value,before_foo,path,/usr/tmp/bar)
Wir können sogar noch weiter gehen und ein Template für file-info-Strukturen definie-
ren, mit dessen Hilfe man neue Instanzen erzeugen kann:
orig_foo := $(call new,file-info)
$(call set-value,orig_foo,path,/foo/bar)
tmp_foo := $(call new,file-info)
$(call set-value,tmp_foo,path,/tmp/bar)
Damit existieren zwei verschiedene Instanzen von file-info. Als Letztes führen wir noch
Standardwerte für die einzelnen Felder ein. Die Deklaration der Struktur
file-info
könnte dann wie folgt lauten:
This is the Title of the Book, eMatter Edition
Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved.
Datenstrukturen
|
281
Rechts
Max.
Linie
Max.
Linie
$(call defstruct,file-info, \
$(call defslot,path,), \
$(call defslot,type,unix), \
$(call defslot,host,oscar))
Das erste Argument der Funktion defstruct ist der Name der zu definierenden Funktion,
gefolgt von Aufrufen der Funktion
defslot. An defslot wird jeweils ein Paar bestehend
aus Feldname und Standardwert des Feldes übergeben. Beispiel B-1 zeigt die Implemen-
tation von defstruct sowie einige unterstützende Funktionen.
Beispiel B-1: Definition einer Datenstruktur mit make
# $(next-id) - Erzeuge eine eindeutige Nummer.
next_id_counter :=
define next-id
$(words $(next_id_counter))$(eval next_id_counter += 1)
endef
# all_structs - Liste aller definierten Strukturnamen
all_structs :=
value_sep := XxSepxX
# $(call defstruct, struct_name, $(call defslot, slot_name, value), ...)
define defstruct
$(eval all_structs += $1) \
$(eval $1_def_slotnames :=) \
$(foreach v, $2 $3 $4 $5 $6 $7 $8 $9 $(10) $(11), \
$(if $($v_name), \
$(eval $1_def_slotnames += $($v_name)) \
$(eval $1_def_$($v_name)_default := $($v_value))))
endef
# $(call defslot,slot_name,slot_value)
define defslot
$(eval tmp_id := $(next_id))
$(eval $1_$(tmp_id)_name := $1)
$(eval $1_$(tmp_id)_value := $2)
$1_$(tmp_id)
endef
# all_instances - Liste mit allen Instanznamen aller Strukturen
all_instances :=
# $(call new, struct_name)
define new
$(strip \
$(if $(filter $1,$(all_structs)),, \
$(error new-Aufruf mit unbekannter Struktur '$(strip $1)')) \
$(eval instance := $1@$(next-id)) \
$(eval all_instances += $(instance)) \
$(foreach v, $($(strip $1)_def_slotnames), \
$(eval $(instance)_$v := $($(strip $1)_def_$v_default))) \

Get GNU make, 3rd Edition now with O’Reilly online learning.

O’Reilly members experience live online training, plus books, videos, and digital content from 200+ publishers.