Ícone do site Embarcadero RAD Studio, Delphi, & C++Builder Blogs

Problemas na combinação de objetos Classic e Clang: avisos do linker e melhoria da estabilidade do aplicativo

mixing classic and clang large size 2

O vinculador C ++ Builder irá avisá-lo quando você misturar arquivos de objeto vinculados a clássico e clang, ajudando a evitar erros de vinculação ou de tempo de execução.

Hoje, em 2020, recomendamos o uso dos compiladores Clang modernos, especialmente com o trabalho que temos feito para Win64 (por exemplo, um depurador totalmente novo) e as melhorias de RTL para facilitar a atualização do clássico. No entanto, muitos clientes atualizam em etapas: primeiro do Win32 clássico para o Clang Win32 e, em seguida, adicionando o Win64. Na verdade, geralmente recomendamos isso diretamente como uma estratégia de atualização, para passar para o Clang primeiro e depois para o Win64, em duas etapas.

No entanto, há um problema comum ao passar dos compiladores clássicos para os compiladores clang. Os arquivos de objeto (bibliotecas .obj e .lib) gerados pelos compiladores clássicos e Clang Win32 não são binários compatíveis entre si. (Tanto o clássico quanto o clang podem se vincular ao Delphi, mas o clássico e o clang não podem se vincular.) Se você tentar construir um aplicativo em que algumas partes são construídas com o Clang e outras com o clássico, tudo misturado, você pode esperar qualquer coisa dos erros do vinculador à instabilidade do tempo de execução. Ainda assim, é fácil de fazer acidentalmente, tanto durante a atualização quanto apenas ao adicionar uma nova biblioteca ou EXE ao seu projeto.

Na versão 10.3.3, e isso foi documentado na ajuda online, mas não foi publicado no blog na época, adicionamos um novo aviso do linker para ajudá-lo a detectar essas situações.

Antes de mostrar a solução, vamos dar uma olhada rápida no que pode acontecer se você tiver esse erro em suas compilações.

Problemas quando compiladores incompatíveis

Na versão 10.3.3 e posteriores, você receberá um aviso do vinculador – veja abaixo – antes de qualquer um dos seguintes. Mas se você estiver usando uma versão mais antiga, antes de adicionarmos o aviso de diagnóstico do problema, você poderá ver apenas os erros a seguir. Eles aparecem ao vincular o aplicativo.

Erros de tempo de link

Quando um aplicativo criado com o conjunto de ferramentas Clang está vinculado a uma biblioteca clássica, você pode ver os seguintes erros:

[crayon-67684295bb129890568591/]

Quando um aplicativo criado com o conjunto de ferramentas Classic é vinculado a uma biblioteca do Clang, você pode ver os seguintes erros:

[crayon-67684295bb131610906634/]

Erros de tempo de execução

Em alguns casos, você pode não ver nenhum erro de vinculador e executará seu aplicativo. Provavelmente, em algum ponto, seu aplicativo irá travar e será difícil descobrir o porquê, porque o código parece bom. Na realidade, será devido a dois compiladores diferentes fazerem as coisas de maneiras diferentes – layout de memória diferente, alinhamento, expectativas de biblioteca de tempo de execução, tratamento de exceções, todos os tipos de diferenças possíveis.

Não é uma boa situação ter erros de linker estranhos ou comportamento de tempo de execução estranho. Então, adicionamos um aviso para verificar essa situação.

Diagnosticando: um Aviso de Novo Linker

RAD Studio / C ++ Builder 10.3.3 e mais recente avisa sobre a mistura de clang e clássico ao vincular. (Se ocorrerem erros do vinculador como o acima, este aviso é emitido antes deles, portanto, você verá o aviso antes de quaisquer erros devido ao problema.)

A mensagem diz ‘Aviso: incompatibilidade do compilador’. e depois diz o que esperava e o que encontrou:

[crayon-67684295bb133699404721/]

Então, como o vinculador verifica se há objetos mistos e como ele sabe o que esperar?

No erro acima, eu tenho um aplicativo VCL vinculado a uma biblioteca estática. O aplicativo VCL é desenvolvido com Clang. A biblioteca é construída com clássicos. O aplicativo clang vincula-se à biblioteca com:

[crayon-67684295bb135424963078/]

see documentation on linking with #pragma comment vs #link.

É muito fácil cometer o erro de incompatibilidade de compiladores. Como você pode ver na captura de tela à direita, não é fácil dizer qual compilador Win32 está sendo usado. Isso é algo que poderíamos melhorar, mas agora ele lista a plataforma de destino, não o compilador.

Nosso compilador agora emite em cada objeto um registro (um pequeno pedaço de dados) dizendo com qual compilador ele foi construído (por exemplo, Clang Win32). Ao vincular, o vinculador recebe um conjunto de arquivos de objeto e bibliotecas, na ordem do comando linha. Ele olha para o primeiro objeto com o qual se vincula e marca que espera que todos os outros objetos sejam construídos com o mesmo compilador do primeiro. Para cada objeto que ele vincula (e dada uma biblioteca, que é apenas um conjunto de objetos, para cada objeto na biblioteca) ele verifica se foi construído com o compilador que está esperando.

Caso contrário, emite o aviso acima, que também pode ser visto na imagem à direita. Você pode ver que ele lista o objeto incorreto e com o que foi construído, e também explica por que estava procurando um compilador diferente. O objetivo é ajudá-lo a diagnosticar a configuração de sua compilação.

TLDR

Resumo rápido: misturar arquivos-objeto construídos com dois compiladores em um binário é uma má ideia. O vinculador lhe dará um aviso se você fizer isso, e lhe dirá o que foi construído com o que para que você possa corrigi-lo. Isso corrige problemas do vinculador e corrige problemas de estabilidade do aplicativo!

Leitura Adicional

Empacotando componentes ou bibliotecas escritas em compiladores Classic e Clang C ++ Win32
Esta nova página docwiki discute o aviso do vinculador, mas também contém um pouco mais de informações. Ele aborda como usar clang ou binários clássicos se você for um desenvolvedor de aplicativos e criar aplicativos com várias partes (talvez vinculando a uma biblioteca C ++ de código aberto que você também está criando) e também tem outra seção para se você for uma biblioteca desenvolvedor (por exemplo, escrever componentes ou bibliotecas e distribuí-los aos seus clientes).

Sair da versão mobile