.NET Native e compilazione

Le applicazioni desktop di Windows .NET Framework vengono scritte in un particolare linguaggio di programmazione e compilate in linguaggio intermedio (IL). In fase di esecuzione, un compilatore JIT (Just-In-Time) è responsabile della compilazione del codice IL nel codice nativo per il computer locale subito prima dell'esecuzione di un metodo per la prima volta. Al contrario, la catena di strumenti .NET Native converte il codice sorgente in codice nativo in fase di compilazione. Questo articolo confronta .NET Native con altre tecnologie di compilazione disponibili per le app .NET Framework e offre anche una panoramica pratica del modo in cui .NET Native produce codice nativo che consente di comprendere il motivo per cui le eccezioni che si verificano nel codice compilato con .NET Native non si verificano nel codice compilato tramite JIT.

Generazione di file binari nativi

Un'applicazione destinata .NET Framework e che non viene compilata usando la catena di strumenti .NET Native è costituita dall'assembly dell'applicazione, che include quanto segue:

  • Metadati che descrivono l'assembly, le relative dipendenze, i tipi che contiene e i relativi membri. Metadati usati per la reflection, l'accesso ad associazione tardiva e in alcuni casi dal compilatore e dagli strumenti di compilazione.

  • Codice di implementazione. È costituito dai codici operativi del linguaggio intermedio (IL). In fase di esecuzione, il compilatore JIT lo converte in codice nativo per la piattaforma di destinazione.

Oltre all'assembly principale dell'applicazione, un'app richiede che siano presenti gli elementi seguenti:

  • Qualsiasi libreria di classi aggiuntiva o assembly di terze parti necessario. Allo stesso modo, questi assembly includono i metadati che lo descrivono, i relativi tipi e membri, nonché il linguaggio intermedio che implementa tutti i membri del tipo.

  • Libreria di classi .NET Framework. Si tratta di una raccolta di assembly installata nel sistema locale insieme a .NET Framework. Gli assembly inclusi nella libreria di classi .NET Framework contengono un set completo di metadati e codice di implementazione.

  • Common Language Runtime Si tratta di una raccolta di librerie a collegamento dinamico che eseguono servizi quali caricamento di assembly, gestione della memoria e Garbage Collection, gestione delle eccezioni, compilazione JIT, comunicazione remota e interoperabilità. Come la libreria di classi, il runtime viene installato nel sistema locale come parte dell'installazione di .NET Framework.

Per l'esecuzione corretta dell'app devono essere presenti l'intero CLR, così come i metadati e il linguaggio intermedio per tutti i tipi in assembly specifici dell'applicazione, assembly di terze parti e assemby di sistema.

Compilazione JIT

L'input per la catena .NET Native strumenti è l'app UWP compilata dal compilatore C# o Visual Basic distribuzione. In altre parole, la catena .NET Native strumenti inizia l'esecuzione al termine della compilazione di un'app UWP da parte del compilatore del linguaggio.

Suggerimento

Poiché l'input per .NET Native è rappresentato dal linguaggio intermedio e dai metadati scritti negli assembly gestiti, è comunque possibile eseguire la generazione di codice personalizzato o altre operazioni personalizzate usando gli eventi di pre-compilazione o post-compilazione oppure modificando il file di progetto MSBuild.

Tuttavia, le categorie di strumenti che modificano il linguaggio intermedio e dunque impediscono alla catena di strumenti .NET Native di analizzare il linguaggio intermedio dell'app non sono supportati. Le soluzioni di offuscamento rappresentano i principali strumenti di questo tipo.

Durante la conversione di un'app dal linguaggio intermedio al codice nativo, la catena di strumenti .NET Native esegue operazioni simili alle seguenti:

  • Per alcuni percorsi di codice, sostituisce il codice basato sulla reflection e i metadati con codice nativo statico. Ad esempio, se un tipo di valore non esegue l'override del metodo <xref:System.ValueType.Equals%2A?displayProperty=nameWithType>, il test predefinito per verificare l'uguaglianza usa la reflection per recuperare gli oggetti <xref:System.Reflection.FieldInfo> che rappresentano i campi del tipo di valore, quindi confronta i valori di campo di due istanze. Durante la compilazione in codice nativo, la catena di strumenti .NET Native sostituisce il codice di reflection e i metadati con un confronto statico tra i valori dei campi.

  • Ove possibile, tenta di eliminare tutti i metadati.

  • Include negli assembly finali dell'app solo il codice di implementazione effettivamente richiamato dall'applicazione. Questo incide in particolare sul codice nelle librerie di terze parti e nella libreria di classi .NET Framework. Di conseguenza, un'app non dipende più da librerie di terze parti o dall'intera libreria di classi .NET Framework Class; infatti, il codice di terze parti e le librerie di classi .NET Framework sono ora locali rispetto all'app.

  • Sostituisce il CLR completo con un runtime sottoposto a refactoring che contiene principalmente il Garbage Collector. Il runtime con refactoring si trova in una libreria denominata mrt100_app.dll, locale dell'app e di dimensioni pari a poche centinaia di KB. Questo è possibile perché il collegamento statico elimina la necessità di molti dei servizi eseguiti dal CLR.

    Nota

    .NET Native usa lo stesso Garbage Collector del CLR standard. Nel Garbage Collector di.NET Native la Garbage Collection in background è abilitata per impostazione predefinita. Per altre informazioni sulla Garbage Collection, vedere Principi fondamentali di Garbage Collection.

Importante

.NET Native compila un'intera applicazione in un'applicazione nativa. Non consente di compilare in codice nativo un singolo assembly che contiene una libreria di classi in modo che sia possibile chiamarlo indipendentemente dal codice gestito.

L'app risultante prodotta dalla catena di strumenti .NET Native viene scritta in una directory denominata ilc.out nella directory Debug o Release del progetto. È costituita dai file seguenti:

  • <appName>.exe, un eseguibile stub che trasferisce semplicemente il controllo a Main un'esportazione speciale in <appName> .dll.

  • <appName>.dll, una libreria a collegamento dinamico di Windows che contiene tutto il codice dell'applicazione, nonché il codice della libreria di classi .NET Framework e di tutte le librerie di terze parti da cui si ha una dipendenza. Contiene anche codice di supporto, ad esempio il codice necessario per l'interoperabilità con Windows e per serializzare gli oggetti nell'app.

  • mrt100_app.dll, un runtime sottoposto a refactoring che fornisce servizi di runtime, ad esempio Garbage Collection.

Tutte le dipendenze vengono acquisite dal manifesto APPX dell'app. Oltre al file eseguibile dell'applicazione, alla DLL e a mrt100_app.dll, che sono inclusi direttamente nel pacchetto appx, include altri due file:

  • msvcr140_app.dll, la libreria run-time C (CRT) usata da mrt100_app.dll. Il file è incluso da un riferimento di framework nel pacchetto.

  • mrt100.dll. Questa libreria include funzioni che consentono di migliorare le prestazioni di mrt100_app.dll, anche se la sua assenza non impedisce il funzionamento di mrt100_app.dll. Viene caricata dalla directory system32 sul computer locale, se presente.

Poiché la catena di strumenti .NET Native collega il codice di implementazione nell'app solo se sa che l'applicazione richiama effettivamente tale codice, è possibile non includere nell'applicazione i metadati o il codice di implementazione necessari negli scenari seguenti:

  • Reflection.

  • Chiamata dinamica o ad associazione tardiva.

  • Serializzazione e deserializzazione.

  • Interoperabilità COM.

In mancanza del codice di implementazione o dei metadati necessari, il runtime .NET Native genera un'eccezione. È possibile evitare queste eccezioni e assicurarsi che la catena di strumenti .NET Native includa i metadati e il codice di implementazione necessari usando un file di direttive di runtime. Si tratta di un file XML che specifica gli elementi di programma il cui codice di implementazione e i cui metadati devono essere disponibili in fase di esecuzione e assegna loro criteri di runtime. Di seguito è riportato il file di direttive di runtime predefinito aggiunto a un progetto UWP compilato dalla catena .NET Native strumenti:

<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
  <Application>
    <Assembly Name="*Application*" Dynamic="Required All" />
  </Application>
</Directives>

Questo abilita per la reflection e la chiamata dinamica tutti i tipi, nonché i relativi membri, in tutti gli assembly nel pacchetto dell'app. Non abilita però la reflection o l'attivazione dinamica dei tipi negli assembly della libreria di classi .NET Framework. In molti casi, questo è sufficiente.

Vedi anche