Partilhar via


.NET nativo e compilação

Os aplicativos da área de trabalho do Windows destinados ao .NET Framework são escritos em uma linguagem de programação específica e compilados em linguagem intermediária (IL). Em tempo de execução, um compilador just-in-time (JIT) é responsável por compilar o IL em código nativo para a máquina local imediatamente antes de um método ser executado pela primeira vez. Em contraste, a cadeia de ferramentas .NET Native converte o código-fonte em código nativo em tempo de compilação. Este artigo compara o .NET Native com outras tecnologias de compilação disponíveis para aplicativos do .NET Framework e também fornece uma visão geral prática de como o .NET Native produz código nativo que pode ajudá-lo a entender por que as exceções que ocorrem no código compilado com o .NET Native não ocorrem no código compilado pelo JIT.

Gerando binários nativos

Um aplicativo destinado ao .NET Framework e que não é compilado usando a cadeia de ferramentas nativa do .NET consiste no assembly do aplicativo, que inclui o seguinte:

  • Metadados que descrevem a assemblagem, as suas dependências, os tipos que contém e os seus membros. Os metadados são usados para reflexão e acesso tardio e, em alguns casos, também por compiladores e ferramentas de compilação.

  • Código de implementação. Isto consiste em códigos operacionais de linguagem intermediária (IL). No tempo de execução, o compilador just-in-time (JIT) o traduz em código nativo para a plataforma de destino.

Além do conjunto do aplicativo principal, um aplicativo requer que o seguinte esteja presente:

  • Quaisquer bibliotecas de classes adicionais ou assemblies de terceiros que sejam exigidos pelo seu aplicativo. Esses assemblies também incluem metadados que descrevem as assemblies, os seus tipos e os seus membros, bem como o IL que implementa todos os membros dos tipos.

  • A biblioteca de classes do .NET Framework. Esta é uma coleção de assemblies que é instalada no sistema local com a instalação do .NET Framework. Os assemblies incluídos na biblioteca de classes do .NET Framework incluem um conjunto completo de metadados e código de implementação.

  • O Ambiente de Execução de Linguagem Comum. Esta é uma coleção de bibliotecas de vínculo dinâmico que executam serviços como carregamento de assemblies, gerenciamento de memória e coleta de lixo, tratamento de exceções, compilação just-in-time, comunicação remota e interop. Como a biblioteca de classes, o ambiente de execução é instalado no sistema local como parte da instalação do .NET Framework.

Observe que o Common Language Runtime, bem como os metadados e IL para todos os tipos em assemblies específicos da aplicação, assemblies de terceiros e assemblies do sistema, devem estar presentes para que a aplicação seja executada com êxito.

Compilação just-in-time

A entrada para a cadeia de ferramentas nativa do .NET é o aplicativo UWP criado pelo compilador C# ou Visual Basic. Em outras palavras, a cadeia de ferramentas nativa do .NET começa a execução quando o compilador de linguagem termina a compilação de um aplicativo UWP.

Sugestão

Como a entrada para o .NET Native é a IL e os metadados gravados em assemblies gerenciados, você ainda pode executar a geração de código personalizado ou outras operações personalizadas usando eventos pré ou pós-compilação ou modificando o arquivo de projeto MSBuild.

No entanto, não há suporte para categorias de ferramentas que modificam a IL e, assim, impedem que a cadeia de ferramentas .NET analise a IL de um aplicativo. Os ofuscadores são as ferramentas mais notáveis deste tipo.

Durante a conversão de um aplicativo de IL para código nativo, a cadeia de ferramentas nativa do .NET executa operações como as seguintes:

  • Para determinados caminhos de código, ele substitui o código que depende de reflexão e metadados por código nativo estático. Por exemplo, se um tipo de valor não sobrescrever o método ValueType.Equals, o teste padrão de igualdade usará reflexão para obter os objetos FieldInfo que representam os campos do tipo de valor e depois compara os valores dos campos das duas instâncias. Ao compilar para código nativo, a cadeia de ferramentas .NET Native substitui o código de reflexão e os metadados por uma comparação estática dos valores de campo.

  • Sempre que possível, tenta eliminar todos os metadados.

  • Ele inclui nos assemblies finais do aplicativo apenas o código de implementação que é realmente invocado pelo aplicativo. Isso afeta particularmente o código em bibliotecas de terceiros e na biblioteca de classes do .NET Framework. Como resultado, um aplicativo não depende mais de bibliotecas de terceiros ou da biblioteca de classes completa do .NET Framework; em vez disso, o código em bibliotecas de classes de terceiros e do .NET Framework agora é local para o aplicativo.

  • Ele substitui o CLR completo por um runtime refatorado, que se concentra principalmente no coletor de lixo. O tempo de execução refatorado é encontrado em uma biblioteca chamada mrt100_app.dll que é local para o aplicativo e tem apenas algumas centenas de kilobytes de tamanho. Isso é possível porque a vinculação estática elimina a necessidade de muitos dos serviços executados pelo common language runtime.

    Observação

    O .NET Native usa o mesmo coletor de lixo que o Common Language Runtime padrão. No coletor de lixo nativo do .NET, a coleta de lixo em segundo plano é habilitada por padrão. Para obter mais informações sobre a coleta de lixo, consulte Fundamentos da coleta de lixo.

Importante

O .NET Native compila um aplicativo inteiro para um aplicativo nativo. Ele não permite que você compile um único assembly que contém uma biblioteca de classes para código nativo para que ele possa ser chamado independentemente do código gerenciado.

O aplicativo resultante que é produzido pela cadeia de ferramentas .NET Native é gravado em um diretório chamado ilc.out no diretório Debug ou Release do diretório do seu projeto. Consiste nos seguintes ficheiros:

  • <appName>.exe, um executável de stub que simplesmente transfere o controle para uma exportação de Main especial em <appName>.dll.

  • <appName>.dll, uma biblioteca de vínculo dinâmico do Windows que contém todo o código do seu aplicativo, bem como o código da Biblioteca de Classes do .NET Framework e quaisquer bibliotecas de terceiros das quais você dependa. Ele também contém código de suporte, como o código necessário para interoperar com o Windows e serializar objetos em seu aplicativo.

  • mrt100_app.dll, um runtime refatorado que fornece serviços como coleta de lixo.

Todas as dependências são capturadas pelo manifesto APPX do aplicativo. Além do aplicativo exe, dll e mrt100_app.dll, que são agrupados diretamente no pacote appx, isso inclui mais dois arquivos:

  • msvcr140_app.dll, a biblioteca de tempo de execução C (CRT) usada por mrt100_app.dll. É incluído por uma referência-quadro no pacote.

  • mrt100.dll. Esta biblioteca inclui funções que podem melhorar o desempenho de mrt100_app.dll, embora a sua ausência não impeça mrt100_app.dll de funcionar. Ele é carregado a partir do diretório system32 na máquina local, se estiver presente.

Como a cadeia de ferramentas nativa do .NET vincula o código de implementação ao seu aplicativo somente se souber que seu aplicativo realmente invoca esse código, os metadados ou o código de implementação necessário nos seguintes cenários podem não ser incluídos no seu aplicativo:

  • Reflexão.

  • Invocação dinâmica ou tardia.

  • Serialização e desserialização.

  • Interoperabilidade COM.

Se os metadados necessários ou o código de implementação estiverem ausentes no tempo de execução, o tempo de execução do .NET Native lançará uma exceção. Você pode evitar essas exceções e garantir que a cadeia de ferramentas nativa do .NET inclua os metadados necessários e o código de implementação, usando um arquivo de diretivas de tempo de execução, um arquivo XML que designa os elementos do programa cujos metadados ou código de implementação devem estar disponíveis em tempo de execução e atribui uma política de tempo de execução a eles. A seguir está o arquivo de diretivas de tempo de execução padrão que é adicionado a um projeto UWP que é compilado pela cadeia de ferramentas nativa .NET:

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

Isso permite todos os tipos, bem como todos os seus membros, em todas as assemblies no pacote da sua aplicação para reflexão e invocação dinâmica. No entanto, ele não permite reflexão ou ativação dinâmica de tipos em assemblies da biblioteca de classes do .NET Framework. Em muitos casos, isso é adequado.

Ver também