2011-03-04 19 views
5

Sto lavorando su un set relativamente grande di librerie di codice C in codice seriale, che saranno quindi parallelizzate in CUDA dai miei collaboratori.Come posso rendere facile la compilazione del mio progetto altamente modulare per gli utenti finali?

Per questo progetto il mio codice si riduce essenzialmente a

#include "Initialize.cpp" 
#include "PerformMoves.cpp" 
#include "CollectResults.cpp" 

main() 
{ 
    //DECLARE General Vars 

    Initialize(); 

    for (unsigned int step=0; step < maxStep; step++) 
    { 
     PerformMoves(); 
    } 

    CollectResults(); 
} 

Ora i passi che ho eseguire all'interno di inizializzazione e PerformMoves saranno molto diverse a seconda del tipo di simulazione che sto costruendo. La velocità è della massima performance in quanto il mio codice è una simulazione Monte Carlo che eseguirà milioni di mosse, ognuna delle quali comporta potenzialmente migliaia di calcoli. Quindi voglio evitare qualsiasi condizionale non necessario.

Quindi essenzialmente voglio diversi moduli C "plug and play", ad es.

InitializeSimType1.cpp InitializeSimType2.cpp InitializeSimType3.cpp

PerformMovesType1.cpp PerformMovesType2.cpp PerformMovesType3.cpp

....

Ogni ottimizzato per una un certo tipo di procedura di simulazione, senza il "fluff" di grandi condizionali per gestire una varietà di cas es.

Attualmente ho due diversi tipi di simulazioni, e solo questi in due cartelle diverse e compilare come segue:

g ++ Main.cc Initialize.cpp PerformMoves.cpp CollectResults.cpp -o MC_Prog

Mi piacerebbe passare a una sorta di schema di compilazione condizionale, dove ho un file di configurazione di ordinamento in cui specifico le opzioni e afferra i file cpp corretti e li compila.

Suppongo che un file makefile + config sia la mia migliore scommessa, ma al di là degli obiettivi di base e una compilazione molto lineare sono abbastanza alle prime armi nel mondo dei makefile complessi.

Quali sono alcuni buoni modi in cui è possibile creare un sistema di compilazione basato su elenchi, che consentirebbe agli utenti con conoscenze C di base di costruire facilmente un obiettivo con i moduli desiderati. I miei utenti finali non avranno una grande quantità di conoscenza dei makefile (o conoscenze di programmazione in generale), quindi un sistema complesso sul loro fine è fuori questione. Voglio che abbiano fondamentalmente un sistema trasparente basato su file di configurazione che consenta loro di scegliere un modulo Initialize, un modulo PerformMoves e un modulo CollectResults. Una volta che hanno modificato questo file di configurazione con i loro plettri, voglio che siano in grado di eseguire una compilazione a comando singolo.

In altre parole che vogliono essere in grado di creare un file README che indirizza gli utenti:

  1. ingresso queste voci in questo file di configurazione (dà il nome file di configurazione, le opzioni per mettere per ogni voce del file di configurazione). ..
  2. Compile con questo comando (dà singolo comando)

So che questa è una domanda piuttosto astratto e complesso, ma so che ci sono alcuni esperti/c Makefile là fuori che mi potesse offrire qualche buona guida.

+1

Bene per uno che non dovresti usare così tante capitali nelle tue istruzioni. – Hello71

+0

Nel mio codice reale seguo la convenzione di denominazione MSDN suggerita da Microsoft, che è (l'ultima volta che ho controllato) per limitare la prima lettera di tutte le parole all'interno di vars. Il codice di cui sopra ho appena sfruttato molto rapidamente per dare un'idea approssimativa di ciò che stavo cercando di fare. Capisco che ci sono molte idee diverse sull'involucro variabile, ma ho pensato che MSFT fosse un'autentica autorità, quindi segui i loro suggerimenti. È una cattiva idea? –

+0

Sembra sempre meglio utilizzare i trattini bassi per la modifica e il dinking con il codice. La SM è, dopo tutto, la società che ha inventato la notazione ungherese. –

risposta

1

mi viene in mente un paio di sistemi di compilazione simili:

  1. Quando si crea GCC si costruisce librerie con routine di supporto (ad esempio libgcc.a). Vuole assicurarsi che solo le funzioni necessarie si colleghino al tuo programma. Poiché l'unità di granularità del linker è un singolo .o, crea un file .c decine di volte con diverse opzioni -D_enable_xxx per attivare singolarmente ciascuna funzione. Quindi utilizza ar per creare il .o risultante in un .a a cui è possibile eseguire il collegamento per ottenere solo ciò di cui si ha bisogno.
  2. Il server di finestre X ha diverse funzioni che eseguono operazioni in gran parte identiche tranne che la matematica nel ciclo molto più interno è diversa. Ad esempio, potrebbe contenere xor o and o or bit. Non vuole un condizionale nel suo ciclo interno, quindi costruisce lo stesso file più volte con diverse opzioni -D_math_xor per produrre dozzine di .o ciascuna con una funzione che esegue l'operazione matematica specifica racchiusa nella funzione di loop. Utilizza tutto il .o (poiché l'operazione è effettivamente selezionata dal client X, non al momento della compilazione), quindi la tecnica .a non è importante.

suona come si potrebbe usare un mix di quelli per la produzione di una libreria di .o dove ognuno è pre-compilato con le opzioni specifiche e quindi rigenerare solo main.c più e più volte di chiamare funzioni diverse e che collega contro il tuo libaray.

In base alle vostre commenti qui sotto, qui ci sono un paio di altre idee:

  1. Quando si crea binutils, GCC, glibc, ecc si estrae la distribuzione dei sorgenti ma non costruiscono all'interno della struttura di origine . Invece lo mkdir obj-mytarget; cd obj-mytarget; ../path/to/gcc/configure --options...; make lo script configure crea config.h e uno Makefile specifico per le opzioni (e, naturalmente, le funzionalità di sistema). Un grande vantaggio di questa configurazione è che tutti i prodotti di costruzione (da .o a file eseguibili) per quel set di opzioni sono autonomi e non interferiscono con le build utilizzando altre opzioni.
  2. La classica configurazione del kernel BSD viene eseguita modificando un file (in modo idiomatico viene fornito un nome tutto maiuscolo come GENERIC che produce il kernel predefinito o LINT che attiva tutto per scopi di analisi statica) e quindi richiama config CONFNAME. config analizza il semplice file di configurazione e crea un albero di directory che prende il nome dal file. L'albero delle directory contiene un Makefile e vari file .h per controllare la compilazione. Gli stessi vantaggi di base del metodo di cui sopra.
  3. avr-libc (una libc per microcontrollori AVR Atmel) automatizza gli approcci di cui sopra creando automaticamente directory di destinazione per dozzine di microcontrollori (con variazioni di dimensioni della memoria, disponibilità periferica, ecc.) E creando tutte le delle variazioni in un singolo passaggio. Il risultato sono molte librerie, fornendo un ambiente cross-build in grado di indirizzare qualsiasi AVR. Potresti usare un'idea simile per costruire automaticamente ogni permutazione del tuo programma.
+0

Ciao Ben , Grazie per il buon consiglio! Vedo che sia GCC che X Window Server utilizzano una sorta di compilazione personalizzata basata su macro, che si avvicina a quello che voglio, ma non esattamente quello che speravo. Questo tipo di il sistema sembra essere utile per la compilazione di più target predefiniti che condividono componenti drop-in comuni (pensate a un ristorante che condividono gli ingredienti) Il mio obiettivo sarebbe avere un file di configurazione che fornisce queste informazioni e una singola marca obiettivo per il mio eseguibile centrale (pensa a un'insalata dove puoi prenderti r elementi per ottenere la tua entrata in rete). –

+0

Per finire il mio pensiero, in questo modo l'utente può modificare questo file, ad esempio 'CONFIG', e quindi digitare' make MC_Prog' e selezionerà automaticamente i componenti drop-in giusti tramite le coppie variabile/valore nel file di configurazione. In questo modo gli utenti finali non devono preoccuparsi di bandiere complesse o una tonnellata di obiettivi, ottengono semplicemente un file CONFIG di semplice comprensione e un singolo target di creazione primario (insieme a target ausiliari appropriati come clean, ecc.) . Sto assumendo che ciò di cui ho bisogno è una sorta di analisi del testo/logica condizionale all'interno del makefile stesso ... –

+0

o un sistema di script che analizza il file di configurazione e auto-genera/chiama un makefile appropriato. Sto pensando che MAGGIO sia la mia migliore scommessa - ho detto uno script * .py che analizza le coppie var/value in 'CONFIG' (ignorando le righe di commento) che sputa e chiama un makefile. In questo modo modificano semplicemente i valori in 'CONFIG' su una delle opzioni fornite nei commenti, quindi eseguono lo script e il sistema di compilazione fa il suo trucco senza alcuna complessità. Sembra una buona soluzione? –

Problemi correlati