Como posso descobrir o que faz meu aplicativo combinar o CRT vinculado estaticamente e dinamicamente?

StackOverflow https://stackoverflow.com/questions/1569222

Pergunta

Desculpe pela longa postagem que se segue.

Eu sei que não é uma boa ideia misturar os tempos de execução C e C++ vinculados estaticamente e vinculados dinamicamente fornecidos pela Microsoft.Infelizmente, nosso aplicativo no trabalho já os mistura e estamos tentando consertar isso.Por vários motivos (entre os quais o desconhecimento do MSI, o facto de utilizarmos o NSIS que talvez não suporte bem os MSM, a falta de tempo e recursos) decidimos ligar os CRTs estaticamente em vez de dinamicamente.Eu sei os motivos pelos quais isso não é uma boa ideia, mas foi nossa escolha por enquanto.


Nosso código é principalmente C++ padrão complementado por muitas outras bibliotecas de código aberto.

A estrutura do aplicativo é:vários módulos que resultam em bibliotecas estáticas que são interligadas para criar várias coisas, entre as quais um executável que está nos causando problemas.

No Release construímos tudo nosso codifique com /MT.Para algumas das bibliotecas de código aberto usamos binários pré-compilados e alguns deles eram dlls pré-compilados com /MD o que nos fez misturar os tempos de execução.Então, nós mesmos os recompilamos com /MT e os fizemos resultar em bibliotecas estáticas e não em DLLs.Essa conversão não é feita para cada biblioteca, então ainda vinculamos com algumas dlls que usam /MD.


O resultado agora é que em depende.exe todas as nossas coisas exceto um executável não diretamente depende de msvcr80.dll ou msvcp80.dll.Por não depende diretamente Quero dizer que msvcr80.dll não é filho da raiz da árvore mostrada por depende.exe.Às vezes encontramos msvcr80.dll puxado por uma das DLLs da biblioteca, mas isso está alguns níveis mais profundos na árvore.

Como descubro por que o msvcr80.dll está no primeiro nível daquele executável incômodo?O que torna esse link executável diretamente para msvcr80.dll?

Um motivo talvez seja o fato de vincularmos estaticamente à biblioteca A, que vincula usa /MD para vincular dinamicamente ao CRT.Portanto, o código na biblioteca A termina em nosso executável, portanto, nosso executável é vinculado a msvcr80.dll.Mas como faço para descobrir qual das bibliotecas faz isso?


O que eu tentei até agora:

  • carregar os arquivos .lib vinculados estaticamente em depende.exe -> não funciona, pois depende.exe espera um executável ou dll, não uma biblioteca estática
  • use dumpbin.exe /DIRETIVOS nos arquivos .lib vinculados estaticamente -> nenhum deles mostrou msvcrt80.dll (enquanto em Debug, onde tentamos usar /MDd para tudo, eles mostraram msvcrt80d.dll o que me faz pensar que o método é bom e prova que todas as bibliotecas de código aberto vinculadas estaticamente são compiladas corretamente com /MT)
  • use o sinalizador de vinculador /VERBOSE:LIB -> ele mostrou que de fato está puxando msvcrt.lib, que é a biblioteca de importação para msvcr80.dll, então estamos com problemas, mas não disse por que está fazendo isso
  • use o sinalizador de vinculador /VERBOSE + no Visual Studio:Dependências Adicionais libcmt.lib + Ignorar todas as bibliotecas padrão SIM + Ignorar biblioteca específica:msvcrt.lib em uma tentativa desesperada de fazer o msvcrt.lib desaparecer ou ver quem o puxa.O resultado me surpreendeu:
    Searching C:\Program Files\Microsoft Visual Studio 8\VC\lib\msvcrt.lib:  
      Found "public: virtual void * __thiscall type_info::`vector deleting destructor'(unsigned int)" (??_Etype_info@@UAEPAXI@Z)  
        Referenced in libcmt.lib(typinfo.obj)  
        Loaded msvcrt.lib(ti_inst.obj)  
            msvcrt.lib(ti_inst.obj) : error LNK2005: "private: __thiscall type_info::type_info(class type_info const &)" (??0type_info@@AAE@ABV0@@Z) already defined in libcmt.lib(typinfo.obj)  
            msvcrt.lib(ti_inst.obj) : error LNK2005: "private: class type_info & __thiscall type_info::operator=(class type_info const &)" (??4type_info@@AAEAAV0@ABV0@@Z) already defined in libcmt.lib(typinfo.obj)  
      Found "void __stdcall `eh vector destructor iterator'(void *,unsigned int,int,void (__thiscall*)(void *))" (??_M@YGXPAXIHP6EX0@Z@Z)  
        Referenced in msvcrt.lib(ti_inst.obj)
        Loaded msvcrt.lib(ehvecdtr.obj)

Pelo que entendi, typinfo.obj em libcmt.lib faz referência a um símbolo, pesquisa-o em msvcrt.lib e depois de encontrá-lo em ti_inst.obj gera um erro que foi definido duas vezes.Mas isso não faz sentido.Se libcmt.lib já possui o símbolo, por que ele acaba procurando por ele em msvcrt.lib e, portanto, trazendo msvcr80.dll em meu executável?E de maneira mais geral, por que a biblioteca estática procuraria símbolos na biblioteca de importação dinâmica?Por que o vinculador olha para msvcrt.lib se eu o tenho na biblioteca específica Ignore?

Obrigado pela sua paciência :-).

Foi útil?

Solução

Eu tenho a solução para o meu problema.Provavelmente foi um erro estúpido deixado lá desde os tempos antigos.

msvcrt.lib foi explicitamente mencionado por nós na caixa Dependências Adicionais :-( então é claro que tornou a dll uma dependência.E por causa de todas as bibliotecas de código aberto, aquela caixa tem muito texto, então não percebemos.E para ser sincero nem pensamos em olhar aquela caixa com atenção, pois não imaginávamos que poderia haver um erro tão grosseiro em nossos projetos.

Outras dicas

Abra seu executável com depende.exe e execute o criador de perfil embutido em depende.Acredito que isso registrará por que todas as suas DLLs são carregadas e de onde elas são carregadas.Consulte a opção "Registrar chamadas de função LoadLibrary".

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top