Newsgroup: it.comp.lang.c++
Titolo: Inizializzatore

Questo è un problema abbastanza complicato.
Supponete di avere un insieme di file .c che
devono essere compilati in modo da dare
dei files .o.
In ciascuno di questi file .c, per ragioni che
per ora trascuriamo, viene incluso in file
di compilazione il codice di una routine
di inizializzazione del tipo:
static void __init (void)
{
}
che ha la funzione di eseguire delle operazioni
di servizio.
Alla fine del processo di compilazione, ottenuto
il file .ELF, ci saranno n di queste routines __init
nell'eseguibile, dove n è il numero dei files
oggetto generati durante la compilazione dell'
intero progetto.
Sarebbe necessario istruire il linker o il compilatore
ad eseguire tutte le inizializzazioni dei vari moduli
(ossia, tutte le __init) prima di eseguire il main()
del programma.
C'è qualche opzione del compilatore per farlo ?
Tutto il linkaggio avviene staticamente.
Grazie a chi mi vorrà aiutare.
 


Alcune considerazioni: di solito queste operazioni sono comuni nei sistemi
embedded dove c'e' un unico main che fa partire l' applicazione utente.
Non è comune farlo su OS un poco più complessi, dove ogni main corrisponde
ad un programma eseguibile ma in cui è l' OS stesso a preparare l' ambiente
prima di lanciare il programma....
Supponendo che si tratti di un sistema embedded con un unico main e quindi
gli __init siano usati per inizializzare (presumo) l' hardware ed il 
sistema, c'e'
da dire che *tutti* i sistemi embedded includono il modulo di start up, 
di solito
scritto in assembler (crt.asm, start.S o equivalente), che deve 
necessariamente essere
modificato per adeguarsi all' hardware target. Tutto cio' dipende dal 
compilatore
che viene utilizzato e dall' ambiente che si usa: ad esempio con 
CodeWarrior della
metrowerks queste operazioni sono 'trasparenti' e basta indicare i 
moduli di init.
Poi, ovviamente ogni funzione di __init *deve* *avere* un nome univoco, 
altrimenti
il linker da' errore: non mi pare sia proprio possibile avere N funzioni 
con lo stesso
nome.....
Ti conviene *prima* controllare la documentazione del tuo compilatore
o indicare quanto meno *cosa* stai usando....
brix
 

 del programma.
Puoi sfruttare l'inizializzazione delle variabili statiche. In ogni 
modulo metti il codice:
static int exec__init() {
	__init();
	return 1;
}
static int initialize=exec__init();
Il C garantisce che prima che il main venga eseguito tutte le variabili 
statiche vengono inizializzate e quindi i codici __init() vengono chiamati.
E.

 E.
Approccio interessante, ma mi sa' che non funziona....almeno, in molti 
ambienti
embedded non è possibile, se non passando dallo startup code, perche' le
variabili statiche sono azzerate da un apposito codice che non prevede la
possibilità di eseguire funzioni :-(
Bye
Brix

Allora, ti spiego il problema. Siamo su Nanodesktop,
il compilatore è il psp-gcc e la piattaforma è PSPE
(PSP emulator).
E' stato verificata l'impossibilità di eseguire codice C++
sull'emulatore, mentre sulla reale PSP il codice gira.
Sto lavorando per risolvere i vari problemi.
Ieri, innanzitutto, è stato verificato che su PSPE il
problema è dovuto al fatto che su PSPE non vengono
reinizializzati i costruttori globali prima dell'esecuzione
del main.
Ho lavorato tutta questa notte: sono riuscito a scrivere
2 routines che leggendo le sezioni .ctor e .dtor presenti
nel file oggetto possono eseguire l'inizializzazione dei
costruttori globali. A condizione che siano richiamati
dalla routine di inizializzazione (che nel caso di nd è
ndInitSystem () ).
Queste due routine possono accedere solo alla sezione
.ctor o .dtor del file oggetto dove vengono compilate,
non a quella di altri file oggetto che costituiscano
l'eseguibile, quindi l'idea era quella di inocularle in
ogni file oggetto che viene compilato per PSPE attraverso
un apposito file .h che verrebbe richiamato automaticamente
(ed in modo trasparente), quando l'utente include <nanodesktop.h>
Ho provato la tecnica, e funziona benino.
L'unico problema nasce da un fatto: così facendo ogni
file oggetto .o ha una sua copia della routine di inizializzazione
dei costruttori globali ed una sua copia della routine di
avvio dei distruttori globali.
Solo che ndInitSystem dovrebbe avviare nell'ordine tutti
i costruttori all'avvio (cioè, dovrebbe vedere con una
qualche routine quali sono i files oggetto che compongono
l'eseguibile e per ogni file oggetto dovrebbe richiamare
la giusta ctor_constructor_aux).
Stessa cosa per ndSystemHalt che dovrebbe avviare
nell'ordine tutti i distruttori (cioè, dovrebbe avere una
qualche routine che sappia quali sono i files oggetto
che compongono l'eseguibile e per ogni file oggetto
dovrebbe richiamare la giusta dtor_destructor_aux).
Non so se sia possibile fare così.
Ecco perchè avevo pensato, per aggirare l'ostacolo,
di sfruttare una qualche routines del compilatore che
debba essere eseguita prima del main. In questo modo,
l'inizializzazione dei costruttori di ogni modulo sarebbe
eseguita in automatico dal linker prima del main e
il problema sarebbe risolto (ma per i distruttori ?).
Ti faccio una domanda.
In C non esistono funzioni di questo tipo ?
NrModulesInELF
GetNameModule
GetRoutineAddressInThisModule
che possano essere richiamate dinamicamente dal codice C
(cioè, il codice C dovrebbe determinare l'indirizzo di una
certa routine a run-time, e non staticamente come si fa
quando si scrive x = &Routine).
Grazie
Ciao

 il problema sarebbe risolto (ma per i distruttori ?).
Per i distruttori puoi cavartela con atexit() probabilmente.
Per i costruttori la cosa ideale penso sia modificare il codice di 
startup (appunto quello che viene eseguito prima di main).
Si puo` fare anche a livello "userspace" senza essere altrettanto 
intrusivi con una tecnica simile a quella usata da SDL, che ridefinisce 
il main() sostituendo, tramite #define negli header, il main 
dell'applicazione con una "SDL_Main" che verra' poi chiamata alla fine 
del codice crossplatform di inizializzazione di SDL.
Guardati SDL_main.c in src/main/arch nelle distribuzioni sorgenti e 
SDL_main.h x i dettagli.
Bye,
  Gabry


Non è quello il punto. E' lo stessa tecnica che usiamo noi
con Nanodesktop in modalità KSU (il motivo percui
le applicazioni nd iniziano con ndMain e non come
main).
La vera questione cruciale, IMHO, è se un programma in C possa,
a runtime, ottenere:
a) informazioni sui files oggetto che compongono l'eseguibile
che è in esecuzione (in modo da sapere che in questo
eseguibile ci sono N files oggetto, e quindi N diverse
ctor_constructor_aux da qualche parte).
b) informazioni sull'indirizzo di una certa routine all'interno
di ogni file oggetto che costituisce l'eseguibile che è
in esecuzione (in modo da potere richiamare in ordine
le N istanze di ctor_constructor_aux).

 fine del codice crossplatform di inizializzazione di SDL.
Odiosissimo.
E' necessario includere SDL anche nel file che contiene il main, anche se quel file non ha nessuna dipendenza da SDL.
Preferisco, dove possibile, un inizializzatore statico (come e' stato detto, e' vero che alcune piattaforme embedded hanno problemi a riguardo, anche se IMHO e' un problema del compilatore piu' che della piattaforma o dell'ambiente).
--
Marco
-- 
I'm trying a new usenet client for Mac, Nemo OS X.
You can download it at 
http://www.malcom-mac.com/nemo