Ipotizziamo che libooc.a è una libreria con un modulo initializers.o che definisce l'array initializers[] come mostrato sopra contenente solo il puntatore null. Il modulo libreria viene usato dal linker se l'array non viene definito in un modolo precedente a libooc.a nella linea di comando che invoca l'esecuzione del compilatore.
nm stampa la tabella dei simboli del task risultante dalla prima compilazione. Munch è un piccolo programma che genera un nuovo modulo initializers.c che fa riferimento a tutte le funzioni di inizializzazione da considerare. Nella seconda compilazione il linker usa questo modulo piuttosto che il modulo di default in libooc.a per definire gli inizializzatori initializers[] più idenei per il task.
Più che un array, munch può generare una funzione che andrà a chiamare tutte le funzioni di inizializzazione. Tuttavia, come vedremo nel capitolo 12, sarà una lista di classi che potrà essere resa disponibile con questa tecnica, piuttosto che un'inizializzazione.
L'output di nm dipende generalmente dal tipo di sistema UNIX utilizzato. Fortunatamente, l'opzione -p fa in modo che la versione di nm di Berkeley stampi la tabella dei simboli in ordine, mentre su System-V-nm produce un output pulito che sembra molto simile a quello dell'output ottenuto sulla distribuzione Berkeley. Ecco qui una versione di munch per entrambe le distribuzioni, l'implementazione è realizzata utilizzando awk.
NF != 3 || $2 != "T" || $1 !˜ /ˆ[0—9a—fA—F]+$/ { next } $3 ˜ /ˆ_?init[A—Z][A—Za—z]+$/ { sub(/ˆ_/, "", $3) names[$3] = 1 } END { for (n in names) printf "extern void %s (void);\n", n print "\nvoid (* initializers [])(void) = {" for (n in names) printf "\t%s,\n", n print "0 };" }
La prima condizione non considera tutte le entries nella tabella dei simboli eccetto quelle che si chiamano del tipo
0003ea8 T_initPoint
Ipotizziamo che un nome che inizi per Init e una lettera maiuscola a seguire – solo lettere nei successivi caratteri – si riferisce alla sintassi che esprime una funzione di inizializzazione, e un carattere underscore opzionale viene tralasciato (alcuni compilatori lo generano in automatico, altri no) e il resto viene salvato come indice di un array names[]. Una volta che tutti i nomi sono trovati, munch genera le dichiarazioni delle funzioni e definisce gli initializers[].
L'array names[] viene usato perchè ogni nome deve essere considerato due volte. I nomi sono memorizzati come indici piuttosto che come valori di elementi per evitare duplicati. Munch può anche essere usato per generare il modulo di default per la libreria.
$ munch < /dev/null > initializers.c
Munch prende due esecuzioni del linker, richiede una copia dump della tabella dei simboli ottenuta tramite nm e si aspetta di ottenere un formato di un certo tipo. Si affida poi ad un pattern noto e ben stringente per selezionare le funzioni di inizializzazione. Si tratta di una politica di gestione del problema un po' macchinosa. Tuttavia, munch è veramente molto semplice da portare da una piattaforma all'altra e i pattern di selezione delle funzioni di inizializzazione possono essere adattati a tutta una serie di costruttori statici senza troppe difficoltà. Non a caso, il sistema C++ sviluppato da AT&T è stato implementato per molti hosts con una (complicata) variante di munch.