Come affrontare il problema della (compilazione) di una grande base di codici?

10

Sebbene io possa programmare, non ho ancora alcuna esperienza con il lavoro su grandi progetti. Quello che ho fatto fino ad ora è stato la codifica di piccoli programmi che sono stati compilati in pochi secondi (vari esercizi c / c ++ come algoritmi, principi di programmazione, idee, paradigmi o semplicemente provando api ...) o lavorando su alcuni progetti più piccoli che erano fatto in un linguaggio di scripting (s) (python, php, js) dove non è necessaria la compilazione.

Il fatto è che, quando si codifica in un linguaggio di scripting, ogni volta che voglio provare se qualcosa funziona, eseguo semplicemente la sceneggiatura e vedo cosa succede. Se le cose non funzionano, posso semplicemente cambiare il codice e provarlo di nuovo eseguendo nuovamente lo script e continuando a farlo finché non ottengo il risultato che volevo. Il mio punto è che non devi aspettare qualsiasi cosa per compilare e per questo è abbastanza facile prendere una grande base di codice, modificarla, aggiungervi qualcosa o semplicemente giocarci - è possibile vedere immediatamente le modifiche.

Come esempio prenderò Wordpress. È abbastanza facile provare a capire come creare un plugin per questo. Innanzitutto, si inizia creando un semplice plug-in "Hello World", quindi si crea un'interfaccia semplice per il pannello di amministrazione per familiarizzare con l'API, quindi lo si costruisce e si crea qualcosa di più complesso, cambiando nel frattempo l'aspetto di un paio di volte .. L'idea di dover ricompilare qualcosa di così grande come WP ancora e ancora, dopo ogni piccola modifica per provare "se funziona" e "come funziona / si sente" sembra inefficiente, lento e sbagliato.

Ora, come potrei farlo con un progetto che è scritto in un linguaggio compilato? Vorrei contribuire ad alcuni progetti open-source e questa domanda continua a infastidirmi. La situazione probabilmente differisce da progetto a progetto, dove alcuni di essi che sono stati pensati con saggezza saranno "modulari" in qualche modo, mentre altri saranno solo un grande blob che deve essere ricompilato ancora e ancora.

Mi piacerebbe sapere di più su come questo è fatto correttamente. Quali sono alcune pratiche comuni, approcci e progetti (modelli?) Per far fronte a questo? Come viene chiamata questa "modularità" nel mondo dei programmatori e cosa dovrei cercare su Google per saperne di più? È spesso che i progetti escono dalle loro prime proporzioni di pensiero che diventano fastidiose dopo un po '? C'è un modo per evitare compilazione lunga di progetti non ben progettati? Un modo per modularli in qualche modo (magari escludendo parti non vitali del programma durante lo sviluppo (altre idee?))?

Grazie.

    
posta pootzko 27.09.2011 - 19:02
fonte

7 risposte

6

Proprio come è stato detto, non ricompilate mai l'intero progetto ogni volta che apportate una piccola modifica. Invece, ricompili solo la parte del codice che è stata modificata, e le sue dipendenze.

In C / C ++, la compilazione è piuttosto semplice. compilare traduci ciascun file sorgente in codice macchina (li chiamiamo file oggetto * .o) e poi collega tutti i tuoi file oggetto in un unico grande file eseguibile.

Proprio come MainMa menzionato, alcune librerie sono incorporate in file separati, che saranno collegati dinamicamente in fase di esecuzione con l'eseguibile. Queste librerie sono chiamate Shared Objects (* .so) in Unix e DLL (Dynamically Linked Libraries) in Windows. Le librerie dinamiche hanno molti vantaggi, uno dei quali è che non è necessario compilarli / collegarli, a meno che il loro codice sorgente non cambi in modo efficace.

Esistono strumenti di automazione della build che ti aiutano:

  • Specifica le dipendenze tra le diverse parti del tuo albero dei sorgenti.
  • Avvia compilazioni puntuali e discrete solo nella parte che è stata modificata.

I più famosi (make, ant, maven, ...) possono rilevare automaticamente quali parti del codice sono state cambiate dall'ultima compilazione, e esattamente quale oggetto / binario deve essere aggiornato.

Tuttavia, questo è un costo (relativamente piccolo) di dover scrivere uno "script di build". È un file che contiene tutte le informazioni sulla tua build, come definire gli obiettivi e le loro dipendenze, definire quale compilatore vuoi e quali opzioni usare, definire il tuo ambiente di costruzione, i percorsi della tua libreria, ... Forse hai sentito parlare di Makefile (molto comune nel mondo Unix), o build.xml (molto popolare nel mondo Java). Questo è quello che fanno.

    
risposta data 27.09.2011 - 19:48
fonte
7

Non ricompilate l'intero progetto ogni volta. Ad esempio, se si tratta di un'applicazione C / C ++, è probabile che verrà separata in librerie (DLL in Windows), ogni libreria verrà compilata separatamente.

Il progetto stesso viene generalmente compilato quotidianamente su un server dedicato: quelli sono build notturni. Questo processo può richiedere molto tempo, poiché include non solo il tempo di compilazione, ma anche il tempo impiegato per eseguire test di unità, altri test e altri processi.

    
risposta data 27.09.2011 - 19:10
fonte
5

Ecco la mia lista di cose che puoi provare ad accelerare le build di C / C ++:

  • Sei configurato per ricostruire solo ciò che è cambiato? La maggior parte degli ambienti lo fa per impostazione predefinita. Non è necessario ricompilare un file se questo o nessuno degli header è cambiato. Allo stesso modo, non c'è motivo di ricostruire un dll / exe se tutto il link in objs / lib non è cambiato.
  • Inserisci elementi di terze parti che non cambiano mai e le intestazioni associate in alcune aree della libreria di codici di sola lettura. Hai solo bisogno delle intestazioni e dei binari associati. Dovresti mai aver bisogno di ricostruirlo dal sorgente diverso forse da una volta.
  • Durante la ricostruzione di tutto, i due fattori limitanti della mia esperienza sono stati numero di core e velocità del disco . Prendi una quadricromia robusta, una macchina hyperthreaded con un hdd davvero buono e le tue prestazioni miglioreranno. Considera una guida a stato solido: tieni presente che quelli a basso costo potrebbero essere peggio di un buon hdd. Prendi in considerazione l'utilizzo del raid per aumentare il tuo hdd
  • Utilizza un sistema di build distribuito come Incredibuild che suddividerà la compilazione su altre workstation sulla tua rete. (Assicurati di avere una rete solida).
  • Imposta un unity build per salvarti dai file di intestazione che si ricaricano costantemente .
risposta data 27.09.2011 - 19:51
fonte
4

Penso che tutte le risposte finora fatte siano state allusive, è che i progetti software di grandi dimensioni sono quasi sempre suddivisi in parti molto più piccole. Ogni pezzo è normalmente memorizzato nel proprio file.

Questi pezzi sono individualmente compilati per creare oggetti. Gli oggetti sono quindi collegati insieme per formare il prodotto finale. [In un certo senso, è un po 'come costruire roba fuori da Lego. Non provi a modellare l'ultima cosa da un unico grande pezzo di plastica, ma combini un po 'di pezzi più piccoli per realizzarlo.

Rompere il progetto in pezzi che sono compilati individualmente consente alcune cose belle che accadano.

Edificio incrementale

Prima di tutto, quando cambi un pezzo, di solito non devi ricompilare tutti i pezzi. In generale, finché non cambi il modo in cui gli altri pezzi interagiscono con il tuo pezzo, gli altri non devono essere ricompilati.

Ciò dà origine all'idea di edificio incrementale . Quando si esegue una build incrementale, vengono ricompilati solo i pezzi di quelli interessati dal cambiamento. Ciò accelera notevolmente i tempi di sviluppo. È vero, potresti ancora dover aspettare che tutto si ricolleghi, ma è comunque un risparmio rispetto alla necessità di ricompilare e ricollegare tutto. (A proposito: alcuni sistemi / linguaggi supportano il collegamento incrementale in modo che solo le cose che sono cambiate debbano essere ricollegate, il cui costo è in genere scadente in termini di prestazioni e dimensioni del codice.)

Test unità

La seconda cosa che ti permette di fare piccoli pezzi è testare individualmente i pezzi prima che sono combinati. Questo è noto come Test unità . Durante il test delle unità, ogni unità viene testata individualmente prima di essere integrata (combinata) con il resto del sistema. I test unitari vengono normalmente scritti in modo da poter essere eseguiti rapidamente senza coinvolgere il resto del sistema.

Il caso limite dell'applicazione del test è visto in Test Driven Development (TDD). In questo modello di sviluppo, nessun codice è scritto / modificato a meno che non si debba correggere un test fallito.

Rendilo più semplice

Quindi abbattere le cose sembra buono, ma sembra anche che sia necessario molto lavoro per costruire il progetto: devi capire cosa sono cambiati i pezzi e cosa dipende da quei pezzi, compilare ogni pezzo e quindi collegare tutto insieme .

Fortunatamente, i programmatori sono pigri *, quindi inventano molti strumenti per semplificare il loro lavoro. A tal fine, sono stati scritti molti strumenti per automatizzare l'attività di cui sopra. Il più famoso di questi è già stato menzionato (make, ant, maven). Questi strumenti ti permettono di definire quali pezzi devono essere messi insieme per rendere il tuo progetto finale e come i pezzi dipendono l'uno dall'altro (ad esempio, se lo cambi, questo deve essere ricompilato). Il risultato è che emettere un solo comando fa capire cosa deve essere ricompilato, lo compila e ricollega tutto.

Ma questo continua a capire come le cose si relazionano tra loro. Questo è un sacco di lavoro e, come ho detto prima, i programmatori sono pigri. Quindi hanno escogitato un'altra classe di strumenti. Questi strumenti sono stati scritti per determinare le dipendenze per te! Spesso gli strumenti fanno parte di Integrated Development Environments (IDE) come Eclipse e Visual Studio, ma ci sono anche alcuni standalone usati per applicazioni generiche e specifiche (makedep, QMake per programmi Qt).

* In realtà, i programmatori non sono veramente pigri, a loro piace solo passare il tempo a lavorare sui problemi, non a svolgere attività ripetitive che possono essere automatizzate da un programma.

    
risposta data 28.09.2011 - 15:26
fonte
4
  • Ricostruzione parziale

Se il progetto implementa un DAG di compilazione appropriato, allora puoi farla franca solo con la ricompilazione dei file oggetto interessati dalla tua modifica.

  • Processo di compilazione multiplo

Assumendo anche un DAG di compilazione appropriato, è possibile compilare utilizzando più processi. Un lavoro per core / CPU è la norma.

  • Test eseguibili

È possibile creare più eseguibili per test che collegano solo determinati file oggetto.

    
risposta data 28.09.2011 - 08:17
fonte
3

The idea of having to recompile something as big as WP over and over again, after each minor change to try "if it works" and "how it work/feels" just seems inefficient, slow and wrong.

L'esecuzione di qualcosa interpretato è anche molto inefficiente, lento e (discutibilmente) sbagliato. Ti stai lamentando dei requisiti di tempo sul PC dello sviluppatore, ma la compilazione non causa dei requisiti di tempo sul PC dell'utente , che è probabilmente molto peggio.

Ancora più importante, i sistemi moderni possono eseguire ricostruzioni incrementali abbastanza avanzate e non è comune ricompilare l'intero processo per modifiche minori - i sistemi compilati possono includere componenti di script, in particolare per elementi come l'interfaccia utente.

    
risposta data 27.09.2011 - 19:48
fonte
2

Oltre alla risposta di MainMa, abbiamo anche aggiornato le macchine su cui lavoriamo. Uno dei migliori acquisti che abbiamo fatto è stato un SSD per quando non puoi fare a meno di ricompilare l'intero progetto.

Un altro suggerimento sarebbe provare un compilatore diverso. Nel frattempo, passiamo dal compilatore Java a Jikes e ora passiamo all'utilizzo del compilatore in bundle con Eclipse (non so se ha un nome) che sfrutta meglio i processori multicore.

Il nostro progetto di file 37.000 ha impiegato circa 15 minuti per compilare da zero prima di apportare queste modifiche. Dopo le modifiche è stato ridotto a 2-3 minuti.

Ovviamente, vale la pena menzionare di nuovo il punto di MainMa. Non ricompilare l'intero progetto ogni volta che vuoi vedere una modifica.

    
risposta data 27.09.2011 - 19:35
fonte

Leggi altre domande sui tag