O endereço C ++ 11 preocupa-se em passar objetos std lib entre limites de biblioteca dinâmica / compartilhada? (ou seja, dlls e assim)?


34

Uma das minhas principais reclamações sobre C ++ é a dificuldade na prática de passar objetos de biblioteca std fora dos limites da biblioteca dinâmica (por exemplo, dll / so).

A biblioteca std geralmente é apenas de cabeçalho. O que é ótimo para fazer algumas otimizações incríveis. No entanto, para as DLLs, elas geralmente são criadas com configurações diferentes do compilador que podem impactar a estrutura / código interno dos contêineres de uma biblioteca std. Por exemplo, no MSVC, uma dll pode criar com a depuração do iterador ativada, enquanto outra cria com a desativação. Essas duas DLLs podem ter problemas ao passar contêineres std. Se eu expor std::stringna minha interface, não posso garantir que o código que o cliente está usando std::stringseja uma correspondência exata da minha biblioteca std::string.

Isso leva a problemas difíceis de depurar, dores de cabeça etc. Você controla rigidamente as configurações do compilador em sua organização para evitar esses problemas ou usa uma interface C mais simples que não terá esses problemas. Ou especifique para seus clientes as configurações esperadas do compilador que eles devem usar (o que é ruim se outra biblioteca especificar outras configurações do compilador).

Minha pergunta é se o C ++ 11 tentou ou não fazer alguma coisa para resolver esses problemas?


3
Não sei a resposta para sua pergunta, mas posso dizer que suas preocupações são compartilhadas; elas são a chave do motivo pelo qual eu não usarei C ++ em meus projetos, pois valorizamos a estabilidade da ABI em detrimento de cada último ciclo de eficiência potencial.
Donal Fellows

2
Por favor, distinguir. É difícil entre DLLs. Entre SOs sempre funcionou muito bem.
Jan Hudec

1
Estritamente falando, esse não é um problema apenas de C ++. É possível ter esse problema com outros idiomas.
MrFox

2
@JanHudec Posso garantir que entre SOs não funcione tão magicamente como você parece indicar. Dada a visibilidade do símbolo e a maneira como o nome do arquivo geralmente funciona, você pode estar mais isolado de um problema, mas compilar um arquivo .so com diferentes sinalizadores / etc.
Sdg

3
@sdg: Com sinalizadores padrão e visibilidade padrão, ele funciona. Se você as alterar e tiver problemas, é problema seu e de mais ninguém.
Jan Hudec

Respostas:


20

Você está certo de que qualquer coisa STL - na verdade, qualquer coisa de qualquer biblioteca de terceiros modelada - é melhor evitar em qualquer API pública do C ++. Você também deseja seguir a longa lista de regras em http://www.ros.org/reps/rep-0009.html#definition para inibir a quebra da ABI, o que torna a programação das APIs públicas do C ++ uma tarefa árdua.

E a resposta em relação ao C ++ 11 é não, esse padrão não está afetando isso. Mais interessante é por que não? A resposta é que o C ++ 17 é muito comovente e, para que os módulos C ++ sejam implementados, precisamos de modelos exportados para funcionar, e para isso precisamos de um compilador do tipo LLVM, como o clang, que pode despejar o AST completo no disco e depois faça pesquisas dependentes de chamador para lidar com os muitos casos de violação de ODR em qualquer projeto grande de C ++ - que, a propósito, inclui muitos códigos GCC e ELF.

Por fim, vejo muitos comentários de ódio e pró-CCG da MSVC. Eles são muito mal informados - o GCC no ELF é fundamental e irremediavelmente incapaz de produzir código C ++ válido e correto. Os motivos para isso são muitos e muitos, mas citarei rapidamente um exemplo de caso: o GCC no ELF não pode produzir com segurança extensões do Python escritas usando o Boost.Python, onde mais de uma extensão baseada no Boost.Python é carregada no Python. Isso porque o ELF com sua tabela de símbolos C global é simplesmente incapaz de impedir violações de ODR que causam segfaults, enquanto PE e MachO e, de fato, a especificação proposta dos Módulos C ++ usam tabelas de símbolos por módulo - o que, aliás, também significa tempos de inicialização do processo muito mais rápidos. E há muitos outros problemas: consulte um StackOverflow que respondi recentemente emhttps://stackoverflow.com/questions/14268736/symbol-visibility-exceptions-runtime-error/14364055#14364055 por exemplo, onde lançamentos de exceção do C ++ são irremediavelmente fundamentalmente interrompidos no ELF.

Último ponto: em relação à interoperabilidade de diferentes STLs, isso é um grande problema para muitos usuários corporativos grandes que tentam misturar bibliotecas de terceiros fortemente integradas a alguma implementação de STL. A única solução é um novo mecanismo para o C ++ lidar com a interoperabilidade STL, e enquanto estiver nisso, você também poderá corrigir a interoperabilidade do compilador para que você possa (por exemplo) misturar arquivos de objetos compilados MSVC, GCC e clang e tudo funcione . Eu assistia ao esforço do C ++ 17 e veria o que acontece lá nos próximos anos - ficaria surpreso se nada acontecer.


Ótima resposta! Só espero que o Clang melhore a compatibilidade do Windows e possa definir um bom compilador padrão. O sistema de inclusão / cabeçalho textual do C ++ é horrível. Estou ansioso pelo dia em que os módulos simplifiquem a organização do código C ++, aceleram infinitamente os tempos de compilação e melhorem a interoperabilidade do compilador com capturas que violam o ODR.
Alessandro Stamatto

3
Pessoalmente, estou realmente esperando um aumento substancial nos tempos de compilação. Atravessar um AST intra-módulo rapidamente é muito difícil, e provavelmente precisaremos de um cache de memória compartilhada na memória. No entanto, quase tudo o que é ruim fica melhor. BTW, os arquivos de cabeçalho estão definitivamente disponíveis, os módulos C ++ atuais têm arquivos de interface mapeados de 1 para 1 para arquivos de cabeçalho. Além disso, os arquivos de interface gerados automaticamente serão em C ++ legal; portanto, um cabeçalho herdado simplesmente filtrará as macros C e cuspirá como arquivos de interface. Nice hein?
Niall Douglas

Legal! Eu tenho muitas dúvidas sobre módulos. O sistema de módulos levará em consideração Inclusão Textual versus Inclusão Simbólica? Com a presente diretiva de inclusão, o compilador precisa recompilar dezenas de milhares de linhas de código repetidamente para cada arquivo de origem. O sistema de módulos permitirá um dia um código sem declarações avançadas? Irá melhorar / facilitar as ferramentas de construção?
Alessandro Stamatto

2
-1 por sugerir que todos os modelos de terceiros são suspeitos. Alterar a configuração é independente de a coisa que está sendo configurada ser um modelo.
DeadMG

1
@Alessandro: Os módulos C ++ propostos desabilitam explicitamente as macros C. Você pode usar modelos ou nowt. As interfaces propostas são C ++ legais, meramente geradas automaticamente e podem opcionalmente ser pré-compiladas para acelerar a correção, ou seja, não espere nenhuma aceleração nos cabeçalhos pré-compilados existentes. As duas últimas perguntas, eu realmente não sei: depende :)
Niall Douglas

8

A especificação nunca teve esse problema. Isso ocorre porque ele possui um conceito chamado "regra de uma definição", que exige que cada símbolo tenha exatamente uma definição no processo em execução.

As DLLs do Windows violam esse requisito. É por isso que existem todos esses problemas. Portanto, é responsabilidade da Microsoft corrigi-lo, não do comitê de padronização do C ++. O Unix nunca teve esse problema, porque as bibliotecas compartilhadas funcionam de maneira diferente lá e, por padrão, estão em conformidade com uma regra de definição (você pode explicitamente quebrá-la, mas obviamente só o faz se souber que pode pagar e precisa extrair os poucos ciclos extras).

As DLLs do Windows violam uma regra de definição porque:

  • Eles codificam a partir da qual biblioteca dinâmica um símbolo será usado durante o tempo de link estático e resolvem símbolos estaticamente na biblioteca que os define. Portanto, se o mesmo símbolo fraco for gerado em várias bibliotecas compartilhadas e nessas bibliotecas do que usado em um único processo, o vinculador dinâmico não terá chance de mesclar esses símbolos. Geralmente esses símbolos são membros estáticos ou impedimentos de classe de instâncias de modelo e causam problemas ao passar instâncias entre códigos em diferentes DLLs.
  • Eles codificam se o símbolo será importado da biblioteca dinâmica já durante a compilação. Portanto, o código vinculado estaticamente a alguma biblioteca é incompatível com o código vinculado dinamicamente à mesma biblioteca.

O Unix usando exportações de formato ELF importa implicitamente todos os símbolos exportados para evitar o primeiro problema e não distingue entre símbolos resolvidos estaticamente e dinamicamente até o tempo de link estático para evitar o segundo.


O outro problema é de sinalizadores do compilador. Esse problema existe para qualquer programa composto de várias unidades de compilação; as bibliotecas dinâmicas não precisam estar envolvidas. No entanto, é muito pior no Windows. No Unix, não importa realmente se você vincula estaticamente ou dinamicamente, ninguém vincula estaticamente o tempo de execução padrão de qualquer maneira (no Linux pode até ser ilegal) e não há nenhum tempo de execução de depuração especial, portanto, uma compilação é boa o suficiente. Mas a maneira como a Microsoft implementou a vinculação estática e dinâmica, o tempo de execução de depuração e liberação e algumas outras opções significa que eles causaram a explosão combinatória das variantes necessárias da biblioteca. Novamente problema de plataforma em vez de problema de linguagem C ++.


2
@DougT .: O GCC não tem nada a ver com isso. A plataforma ABI possui. No ELF, o formato de objeto usado pela maioria dos Unices, as bibliotecas compartilhadas exportam todos os símbolos visíveis e importam todos os símbolos que exportam. Portanto, se algo for gerado em várias bibliotecas, o vinculador dinâmico usará a primeira definição para todos. Simples, elegante e funcional.
: 21712 Jan Hudec

1
@MartinBa: Não há nada para mesclar, mas isso não importa, contanto que seja o mesmo e contanto que não deva ser mesclado em primeiro lugar. Sim, se você usar configurações incompatíveis de compilador em uma plataforma ELF, terá a mesma bagunça que em qualquer lugar e em qualquer lugar. Mesmo se não estiver usando bibliotecas compartilhadas, é um pouco fora de tópico aqui.
Jan Hudec

1
@ Jan - é relevante para a sua resposta. Você escreve: "... uma regra de definição ... As DLLs do Windows violam esse requisito ... as bibliotecas compartilhadas funcionam de maneira diferente [no UNix] ...", mas a pergunta é referente a problemas com coisas std-lib (definidas nos cabeçalhos) e a razão pela qual não há problema no Unix não tem nada a ver com SO vs. DLL, mas com o fato de que no Unix (aparentemente) existe apenas uma versão compatível da biblioteca padrão, enquanto no Windows MS optou por versões incompatíveis (depuração) (com verificação prolongada etc.).
Martin Ba

1
@MartinBa: Não, a principal razão pela qual existe um problema no Windows é que o mecanismo de exportação / importação usado no Windows não pode mesclar adequadamente membros estáticos e impedir a classe de classes de modelo em todos os casos e não pode mesclar símbolos vinculados estaticamente e dinamicamente. Do que é agravado pelas várias variantes da biblioteca, mas o principal problema é que o C ++ precisa de flexibilidade do vinculador que o vinculador dinâmico do Windows não possui.
: 21712 Jan Hudec

4
Eu acho que essa implicação de que a especificação da DLL está quebrada e a demanda correspondente do Msft para 'corrigi-la' são extraviadas. O fato de as DLLs não oferecerem suporte a certos recursos do C ++ não é um defeito da especificação da DLL. As DLLs são um mecanismo de empacotamento com neutralidade de idioma e fornecedor e ABI para expor os pontos de entrada ao código da máquina ('chamadas de função') e blobs de dados. Eles nunca foram criados para oferecer suporte nativo a recursos avançados de qualquer idioma específico. Não é culpa da Msft ou da especificação da DLL que algumas pessoas querem que elas sejam outra coisa.
Euro Micelli

6

Não.

Há muito trabalho em andamento para substituir o sistema de cabeçalho, recurso chamado Módulos e que pode ter um impacto nisso, mas certamente não é grande.


2
Eu não acho que o sistema de cabeçalho teria algum impacto nisso. Os problemas são que as DLLs do Windows violam uma regra de definição (o que significa que elas não seguem as especificações do C ++, portanto o comitê do C ++ não pode fazer nada a respeito) e que existem tantas variantes do tempo de execução padrão no Windows, que o comitê do C ++ pode ' Não faça nada a respeito.
Jan Hudec

1
Não, eles não. Como eles poderiam, a especificação nem sequer menciona algo desse tipo. Fora isso, quando um programa (Windows) está vinculado às DLLs do Windows, o ODR é satisfeito: todos os símbolos visíveis (exportados) devem obedecer ao ODR.
Paul Michalik

O @PaulMichalik C ++ cobre a vinculação (fase 9) e parece-me que pelo menos a vinculação de DLLs / SOs em tempo de carregamento se enquadra na fase 9. Isso significa que os símbolos com vinculação externa (exportada ou não) devem estar vinculados e estar em conformidade com ODR. A vinculação dinâmica com o LoadLibrary / dlopen obviamente não se enquadra nesses requisitos.
bames53

@ bames53: IMHO, as especificações são muito fracas para permitir declarações desse tipo. Um arquivo .dll / .so pode ser visto como um "programa" por si só. Então, as regras foram satisfeitas. Algo como carregar outros "programas" em tempo de execução é tão pouco especificado pelo padrão que qualquer declaração a respeito é bastante arbitrária.
Paul Michalik

@PaulMichalik Se um executável requer vinculação de tempo de carregamento, antes da vinculação de tempo de carregamento, existem entidades externas que não foram resolvidas e faltam as informações necessárias para a execução. LoadLibrary e dlopen estão fora da especificação, mas a carga em tempo ligando muito claramente deve ser parte da fase 9.
bames53
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.