19

Recentemente ho iniziato a utilizzare il compilatore java di Eclipse, perché è significativamente più veloce del javac standard. Mi è stato detto che è più veloce perché esegue la compilazione incrementale. Ma sono ancora un po 'incerto su questo dato che non riesco a trovare alcuna documentazione autorevole su entrambi - la funzione incrementale "di eclispse e sun's - compilers". È vero che il compilatore di Sun compila sempre ogni file sorgente e il compilatore di Eclipse compila solo i file modificati e quelli che sono interessati da tale cambiamento?Lo standard Sun javac può eseguire la compilazione incrementale?

Edit: non sto usando la funzione Eclipse autobuild ma invece sto impostando

-Dbuild.compiler=org.eclipse.jdt.core.JDTCompilerAdapter 

per la mia formica costruisce.

+1

Oracle ha compiuto uno sforzo per risolvere questo problema con lo strumento 'sjavac'. Domanda correlata: http://stackoverflow.com/questions/26424759/what-is-sjavac-who-is-it-for-and-how-do-i-use-it – aioobe

risposta

14

e 'vero che il compilatore di Sun compila sempre ogni file sorgente e compilatore di Eclipse compilare modificato solo file e quelli che sono interessati da un tale cambiamento?

Credo che tu abbia ragione su entrambi i fronti.

Ovviamente è possibile forzare Eclipse a ricompilare tutto.

Ma l'altra parte dell'equazione è che gli strumenti di compilazione Java come Ant e Maven sono in grado di compilare solo le classi che sono state modificate e il loro albero di classi dipendenti.

EDIT

In Formica, compilazione incrementale può essere fatto in due modi:

  • Di default il <javac> task confronta i timestamp di .java e corrispondenti .class file, e dice solo il compilatore Java ricompilare file sorgente (.java) più recenti dei corrispondenti file di destinazione (.class) o che non hanno affatto un file di destinazione.

  • Il <depend> task tiene conto anche delle dipendenze tra le classi, che determina leggendo e analizzando le informazioni sulle dipendenze incorporate nei file .class. Dopo aver determinato quali file .class non sono aggiornati, l'attività <depend> li elimina in modo che una successiva attività <javac> li ricompili. Tuttavia, questo non è del tutto infallibile. Ad esempio, ampie modifiche al codice sorgente possono portare all'attività <depend> che potrebbe essere l'analisi delle dipendenze obsolete. Inoltre alcuni tipi di dipendenza (ad esempio sulle costanti statiche) non sono evidenti nel formato file .class.

    Per capire perché Ant <depend> non è infallibile, leggere la sezione "Limitazioni" di documentation.

+0

Puoi spiegare come funziona la compilazione parziale con Ant lavoro? In che modo Ant forza il compilatore di Sun a compilare solo i file modificati e ad ignorare altri file nell'albero dei sorgenti? –

+0

Suppongo che tu abbia risposto alla mia domanda iniziale, ma mentre fornisci ulteriori informazioni mi sto confondendo di più. Se capisco bene, mi sembra che l'operazione javac senza clean precedente sia un'operazione molto pericolosa, perché non compila le classi dipendenti se il loro timestamp non viene modificato. (Divertente, mi sono appena reso conto che probabilmente avevo questo problema ieri e mi sembrava un vero mistero.) –

+0

Perché dovresti compilare una classe dipendente se non è cambiata? –

2

Eclipse lo fa certamente. Inoltre lo fa a tempo di risparmio se si dispone di tale opzione attivata (ed è di default). Sembra che anche il sole non lo faccia (è molto facile da testare, basta fare un piccolo progetto in cui A è la classe principale che usa la classe B, ma B non usa la classe A. Quindi cambia A e compila il progetto di nuovo, controlla se il timestamp per b.class è stato modificato.

Questo è il modo in cui funzionano molti compilatori (anche gcc per esempio). È possibile utilizzare strumenti come formica e make per compilare solo la parte del progetto che è stata modificata. che questi strumenti non sono perfetti, a volte eclissare solo perde traccia delle modifiche e avrete bisogno di fare una completa ricostruzione.

3

Javac compila solo i file di origine che sono denominati sulla riga di comando o dipendono e non sono aggiornati. Eclipse potrebbe avere un modo più fine di decidere cosa significhi.

+0

Puoi collegare alcuni documenti che supportano questa risposta? Penso che 1) le dipendenze non siano compilate da plain javac e 2) Eclipse ha il proprio compilatore completamente diverso, non solo un modo più fine di decidere. Non posso provarlo, ma è per questo che ho chiesto:) ... –

+0

http://download.oracle.com/javase/6/docs/technotes/tools/windows/javac.html#searching. Certo che puoi provarlo: imposta le condizioni che ho descritto e vedrai tu stesso. – EJP

+0

Questo è corretto: javac compila i file che gli dici di compilare, non "ogni file sorgente". Non decide da solo quali file debbano essere compilati, quindi non è incrementale nel senso in cui l'OP stava chiedendo informazioni. Inoltre (come ha detto EJP) quando javac sta compilando la classe A e trova altri file .java da cui dipende A, esso (a seconda di un numero di fattori) li compila anch'essi. Questo non è lo stesso che cerca di file che potrebbero essere interessati dalle modifiche apportate ai A.java, e penso che è dove le persone si confondono. – gatkin

2

Riprendendo quello che ho sentito qui e fraseggio che per la gente pigri come me:

È possibile ottenere incrementale costruisce con il compito javac in formica, ma si dovrebbe utilizzare l'dipendono compito di cancellare i file .class per il tuo .java modificato E non devi lasciare la dichiarazione include non specificata nell'attività javac. (Specificando solo il percorso src nell'attività javac e lasciando incluse le cause non specificate, javac ricompila tutte le origini che trova.)

Qui ci sono i miei compiti di javac e di dipendenze. Con il compilatore java Oracle standard, vengono compilati solo i file .java che modifico. Spero che questo ti aiuti!

<depend srcdir="JavaSource" destdir="${target.classes}" cache="${dependencies.dir}" closure="yes"> 
    <classpath refid="compiler.classpath" /> 
    <include name="**/*.java"/> 
</depend> 

<javac destdir="${target.classes}" debug="true" debuglevel="${debug.features}" optimize="${optimize.flag}" fork="yes" deprecation="no" source="1.6" target="1.6" encoding="UTF-8" includeantruntime="no"> 
    <classpath refid="compiler.classpath"/> 
    <src path="JavaSource"/> 
    <include name="**/*.java" /> <!-- This enables the incremental build --> 
</javac>