Registrazione di ogni file sorgente C / C ++ per creare un elenco di runtime delle fonti utilizzate

StackOverflow https://stackoverflow.com/questions/618581

Domanda

Per una libreria di debug e registrazione, voglio essere in grado di trovare, in fase di esecuzione, un elenco di tutti i file di origine che il progetto ha compilato e collegato. Suppongo che includerò una sorta di intestazione in ogni file sorgente e la macro __FILE__ del preprocessore può darmi una costante di carattere per quel file, quindi ho solo bisogno di & Quot; broadcast & Quot; tali informazioni da ciascun file devono essere raccolte da una funzione di runtime.

La domanda è come farlo elegantemente, specialmente se si può fare da C invece di C ++. In C ++ probabilmente proverei a creare una classe con una memoria statica per contenere l'elenco dei nomi dei file. Ogni file di intestazione creerebbe un'istanza statica file-locale di quella classe, che al momento della creazione aggiungerebbe il puntatore FILE o qualsiasi altra cosa ai membri di dati statici della classe, forse come un elenco collegato.

Ma non credo che funzionerà in C, e anche in C ++ non sono sicuro che sia garantito che ogni elemento verrà creato.

È stato utile?

Soluzione

Non farei questo genere di cose proprio nel codice. Scriverei uno strumento che analizzava il file di progetto (vcproj, makefile o addirittura scansionava la directory del progetto per i file * .c *) e generava un file sorgente C aggiuntivo che conteneva i nomi di tutti i file sorgente in una sorta di pre struttura dati inizializzata.

Vorrei quindi rendere questo strumento parte del processo di compilazione in modo che ogni volta che esegui una creazione ciò avvenga automaticamente. In fase di esecuzione, tutto ciò che dovresti fare è leggere quella struttura di dati che è stata costruita.

Altri suggerimenti

Sono d'accordo con Ferruccio, il modo migliore per farlo è nel sistema di compilazione, non nel codice stesso. Come espansione della sua idea, aggiungi una destinazione al tuo sistema di compilazione che scarica un elenco dei file (che deve sapere comunque) in un file C come una stringa o matrice di stringhe e compila questo file nel tuo sorgente. Ciò evita molte complicazioni nella fonte ed è espandibile, se si desidera aggiungere ulteriori informazioni, come il numero di versione dal sistema di controllo del codice sorgente, chi ha creato l'eseguibile, ecc.

Esiste un modo standard su UNIX e Linux - ident. Per ogni file sorgente che crei un tag ID, di solito è assegnato dal tuo sistema di controllo versione, ad es. Parole chiave SVN .

Quindi per scoprire il nome e la revisione di ciascun file sorgente basta usare il comando <=>. Se devi farlo in fase di esecuzione, controlla come <=> funziona - la fonte dovrebbe essere disponibile gratuitamente.

Non c'è modo di farlo in C. In C ++ puoi creare una classe come questa:

struct Reg {
   Reg( const char * file ) {
      StaticDictionary::Register( file );
};

dove StaticDictionary è un contenitore singleton per tutti i nomi di file. Quindi in ciascun file sorgente:

static Reg regthisfile( __FILE__ );

Vorresti rendere il dizionario un Meyers singleton per evitare problemi di ordine di creazione.

Non credo che tu possa farlo nel modo in cui descrivi un " passivo " modalità. Cioè, eseguirai in qualche modo il codice per ogni file sorgente da aggiungere al registro, è difficile farlo accadere automaticamente.

Ovviamente, è possibile rendere quel codice molto discreto usando le macro. Potrebbe essere problematico per i file sorgente C che non hanno un & Quot; entrypoint & Quot ;, quindi se il tuo codice non è già organizzato come & Quot; moduli & Quot ;, con ad es. una funzione init() per ogni modulo, potrebbe essere difficile. Il codice di inizializzazione statico potrebbe essere possibile, non sono sicuro al 100% se l'ordine in cui le cose sono inizializzate crea problemi qui.

L'uso dell'archiviazione static nel modulo di registro sembra un'idea eccellente, un semplice elenco collegato o una semplice tabella hash dovrebbero essere abbastanza facili da implementare, se il tuo progetto non include già alcuna libreria di utilità per scopi generici.

In C ++ la tua soluzione funzionerà. È garantito.

Modifica: Ho appena scoperto una soluzione nella mia testa: modifica una regola nel tuo makefile da aggiungere '-include " cfiles_register.h "' a ciascun 'g ++ file.cpp'.

%.o : %.cpp
    $(CC) -include 'cfiles_register.h' -o $@ $<

metti la tua proposta nella domanda di implementazione a quel 'cfiles_register.h'.

L'uso di istanze statiche in C ++ funzionerebbe perfettamente.

Puoi farlo anche in C, ma devi usare funzionalità specifiche di runtime - per MSVC CRT dai un'occhiata a http://www.codeguru.com/cpp/misc/misc/threadsprocesses/article.php/c6945/

Per C - potresti farlo con una macro - definire una variabile denominata corrispondente al tuo file, e quindi puoi scansionare i simboli del tuo eseguibile, proprio come un'idea:

 #define TRACK_FILE(name) char _file_tracker_##name;

usalo nel tuo my_c_file.c in questo modo:

 TRACK_FILE(my_c_file_c)

e quindi grep tutti i nomi di file / variabili dal binario in questo modo

nm my-binary | grep _file_tracker

Non proprio carino, ma ...

Orribile idea, ne sono certo, ma usa un singleton. E su ogni file fai qualcosa come

  Singleton.register(__FILE__); 

a livello globale. Funzionerà solo su file cpp. Ho fatto qualcosa di simile anni fa come novizio, e ha funzionato. Ma mi farebbe rabbrividire per farlo ora. Aggiungerei un passaggio di build ora.

Sono d'accordo con coloro che affermano che è meglio evitare di farlo in fase di esecuzione, ma in C è possibile inizializzare una variabile statica con una chiamata di funzione, ovvero in ogni file:

static int doesntmatter = register( __FILE__);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top