Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Este documento lista um conjunto de políticas que você deve aplicar ao adicionar ou atualizar uma receita de port. Destina-se a servir o papel do Manual de Políticas do Debian, das Diretrizes de Mantenedor do Homebrew e do Livro de Receitas da Fórmula do Homebrew.
Objetivos gerais do design do registro
É necessário que as portas na linha de base atual sejam instaláveis simultaneamente
Queremos ser capazes de mostrar aos usuários downstream de bibliotecas no registro curado que a combinação de bibliotecas em qualquer linha de base que publicamos foi testada para funcionar em conjunto pelo menos em algumas configurações. Permitir que as portas se excluam umas às outras interrompe a capacidade de testar essas configurações, pois o número de compilações necessárias para tais testes aumentaria conforme 2^number_of_such_cases. Além disso, a instalação de dependências adicionais é sempre considerada "segura": não há como um port ou usuário final afirmar que uma dependência não está instalada em seus requisitos.
Caso você queira representar essa situação alternativa para os usuários, considere descrever como alguém pode criar uma porta de sobreposição implementando o formulário alternativo com um comentário em portfile.cmake em vez de tentar adicionar portas extras nunca criadas na integração contínua do registro selecionado. Por exemplo, ver glad@0.1.36.
Antes da introdução dos registros, aceitamos várias portas não testadas como alternativas, como boringssl, o que poderia facilitar a criação de portas de overlay. Isso não é mais aceito porque os repositórios permitem a publicação dessas portas não testadas sem modificar o registro curado.
Usar letras minúsculas para números hexadecimais
Muitos dos recursos em vcpkg dependem da comparação de cadeias de caracteres de dígitos hexadecimal. Alguns exemplos incluem, entre outros, hashes SHA512, IDs de confirmação do Git e hashes de objeto de árvore.
Internamente, o vcpkg usa a normalização em letras minúsculas para comparações desses valores em que a maiúscula é irrelevante. No entanto, as ferramentas criadas com base na infraestrutura do vcpkg podem não fazer as mesmas considerações. Por esse motivo, precisamos de cadeias de caracteres hexadecimal
a ser reduzido para consistência nos cenários a seguir:
- O parâmetro
SHA512nas funções auxiliares do vcpkg. - O parâmetro
REFnas funções auxiliares do vcpkg, quando o valor é uma cadeia de caracteres hexadecimal. - O objeto
git-treenos arquivos de versão do banco de dados. - O objeto
sha512no arquivoscripts/vcpkg-tools.json. - Outros lugares onde a capitalização de caracteres hexadecimal não é importante.
Estrutura de relações públicas
Fazer solicitações de pull separadas por porta
Sempre que possível, separe as alterações em várias PRs. Isso os torna significativamente mais fáceis de revisar e evita que problemas com um conjunto de alterações atrasem todas as outras alterações.
Evite alterações triviais em arquivos intocados
Por exemplo, evite reformatar ou renomear variáveis em arquivos de porta que, de outra forma, não teriam motivo para serem modificados para o problema em questão. No entanto, se você precisar modificar o arquivo para o propósito principal do PR (atualizar a biblioteca), obviamente mudanças benéficas, como corrigir erros de digitação, são apreciadas!
Verificar nomes em relação a outros repositórios
Os nomes dos ports devem tentar ser inequívocos sobre qual pacote o port instala. Idealmente, pesquisar o nome da porta em um mecanismo de pesquisa deve levá-lo rapidamente ao projeto correspondente. Um bom serviço para verificar muitos nomes de pacotes em vários repositórios ao mesmo tempo é o Repology.
Projetos com nomes curtos ou nomeados com nomes de palavras comuns podem exigir desambiguação, especialmente quando não há projetos com uma forte associação com a palavra dada. Por exemplo, uma porta com o nome ip não é aceitável, pois é provável que vários projetos tenham nomes semelhantes.
Exemplos de bons desambiguadores são:
- O nome de usuário ou organização do proprietário do repositório:
google-cloud-cpp. - O nome de um conjunto de bibliotecas do qual o projeto faz parte:
boost-dll.
Prefixos e sufixos comuns usados por C++ e projetos de código aberto não são desambiguadores válidos, alguns exemplos incluem, mas não estão limitados a:
-
cpp, -
free, -
lib, -
open, - Números
Por exemplo, ao comparar os seguintes nomes de portas: ip-cpp, libip e ip5, e ao remover os desambiguadores inválidos, todos eles são reduzidos ao mesmo prefixo (ip) e, portanto, são considerados como tendo o mesmo nome.
Uma exceção a esta diretriz é feita para nomes fortemente associados a um único projeto. Por exemplo: libpng, openssl e zlib.
Para evitar confusão para os usuários, podemos limitar a frequência em que uma porta pode ser renomeada depois de adicionada ao registro público. Nossa política atual é não permitir mais de uma renomeação por ano.
Usar PRs de rascunho do GitHub
As PRs de rascunho do GitHub são uma ótima maneira de obter CI ou feedback humano sobre o trabalho que ainda não está pronto para mesclagem. A maioria das novas PRs deve ser aberta como rascunhos e convertida em PRs normais assim que o CI for aprovado.
Para mais informações sobre solicitações de pull de rascunho do GitHub, consulte Introdução às solicitações de pull de rascunho.
A equipe vcpkg pode converter seu PR em rascunho durante o processo de revisão. Normalmente, com uma solicitação para fazer alterações no código ou comentários indicando quando marcar a PR como Pronta para Revisão.
Fechar PRs inativas
Para evitar a acumulação de PRs obsoletas, a equipe vcpkg pode fechar PRs que estão aguardando a ação do colaborador há mais de 60 dias. Essa contagem regressiva começa da última vez que um mantenedor vcpkg faz uma solicitação de alterações ou comentários, se nenhuma atividade for observada dentro de 60 dias, a PR será considerada obsoleta e poderá ser fechada a critério da equipe do vcpkg.
Arquivos de porta
Evitar funções auxiliares preteridas
No momento, os seguintes auxiliares foram preteridos:
-
vcpkg_extract_source_archive_ex()deve ser substituído pela sobrecarga suportada devcpkg_extract_source_archive()(comARCHIVE) - A sobrecarga obsoleta de
vcpkg_extract_source_archive()semARCHIVEdeve ser substituída pela sobrecarga suportada comARCHIVE. -
vcpkg_apply_patches()deve ser substituído pelosPATCHESargumentos para os auxiliares de "extração" (por exemplo,vcpkg_from_github()) -
vcpkg_build_msbuild()deve ser substituído porvcpkg_install_msbuild() -
vcpkg_copy_tool_dependencies()deve ser substituído porvcpkg_copy_tools() -
vcpkg_configure_cmakedeve ser substituído porvcpkg_cmake_configure()após a remoçãoPREFER_NINJA -
vcpkg_build_cmakedeve ser substituído porvcpkg_cmake_build() -
vcpkg_install_cmakedeve ser substituído porvcpkg_cmake_install() -
vcpkg_fixup_cmake_targetsdeve ser substituído porvcpkg_cmake_config_fixup
Algumas das funções auxiliares de substituição estão em "portas de ferramentas" para permitir que os consumidores fixem seu comportamento em versões específicas e permitir o bloqueio do comportamento dos auxiliares em uma versão específica. É necessário adicionar as portas de ferramentas ao "dependencies" da sua porta, da seguinte forma:
{
"name": "vcpkg-cmake",
"host": true
},
{
"name": "vcpkg-cmake-config",
"host": true
}
Evite comentários excessivos em portfiles
Idealmente, os arquivos de porta devem ser curtos, simples e o mais declarativos possível.
Remova todos os comentários genéricos introduzidos pelo comando create antes de enviar um PR.
As portas não devem ser dependentes de rotas
As portas não devem alterar seu comportamento com base em quais portas já estão instaladas de uma forma que altere o conteúdo que a porta instala. Por exemplo, considerando que:
> vcpkg install a
> vcpkg install b
> vcpkg remove a
e
> vcpkg install b
Os arquivos instalados pelo b devem ser os mesmos, independentemente da influência da instalação anterior do a. Isso significa que os sistemas de portas não devem tentar verificar se algo é disponibilizado na árvore instalada por outro sistema de portas antes de executar alguma ação. Uma causa específica e comum desse comportamento "dependente do caminho" é descrita abaixo em "Ao definir recursos, controle explicitamente as dependências".
Regra de atribuição de porta exclusiva
Em todo o sistema vcpkg, não é esperado que dois ports usados simultaneamente por um usuário forneçam o mesmo arquivo. Se um port tentar instalar um arquivo já fornecido por outro arquivo, a instalação falhará. Se um port quiser usar um nome extremamente comum para um cabeçalho, por exemplo, ele deve colocar esses cabeçalhos em um subdiretório em vez de em include.
Essa propriedade é verificada regularmente por execuções de integração contínua que tentam instalar todas as portas no registro, o que falhará se FILE_CONFLICTS duas portas fornecerem o mesmo arquivo.
Adicionar exportações do CMake em um namespace não oficial-
Um ideal de design central do vcpkg é não criar "lock-in" para os usuários. No sistema de compilação, não deve haver diferença entre depender de uma biblioteca do sistema e depender de uma biblioteca do vcpkg. Para esse fim, evitamos adicionar exportações ou destinos do CMake a bibliotecas existentes com "o nome óbvio", para permitir que os upstreams adicionem suas próprias exportações oficiais do CMake sem entrar em conflito com o vcpkg.
Para esse fim, todas as configurações do CMake exportadas pela porta, que não estão na biblioteca upstream, devem ter unofficial- como prefixo. Todos os destinos adicionais devem estar no unofficial::<port>:: namespace.
Isso significa que o usuário deve ver:
-
find_package(unofficial-<port> CONFIG)como a maneira de obter o pacote exclusivo para vcpkg -
unofficial::<port>::<target>como um destino exportado dessa porta.
Exemplos:
-
brotlicria ounofficial-brotlipacote, produzindo o destinounofficial::brotli::brotli.
Instalar arquivo de direitos autorais
Cada porta deve fornecer um arquivo nomeado copyright na pasta ${CURRENT_PACKAGES_DIR}/share/${PORT}. Se o conteúdo da licença de um pacote estiver disponível em seus arquivos de origem, esse arquivo deverá ser criado por uma chamada para vcpkg_install_copyright().
vcpkg_install_copyright também agrupa vários arquivos de direitos autorais, se necessário.
vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE")
Um método mais antigo para criar manualmente esse arquivo é com o comando integrado file do CMake. Isso é desencorajado em favor de vcpkg_install_copyright em novos portas, mas ainda é permitido.
file(INSTALL "${SOURCE_PATH}/LICENSE" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright)
Se o conteúdo da licença nos arquivos de origem upstream não estiver em forma de texto (por exemplo, um arquivo PDF), copyright deve conter uma explicação de como um usuário pode encontrar os requisitos de licença. Se possível, ele também deve incluir um link para os arquivos de origem originais indicando isso, para que os usuários possam verificar se está atualizado.
file(WRITE "${CURRENT_PACKAGES_DIR}/share/${PORT}/copyright" [[As of 2023-07-25, according to
https://github.com/GPUOpen-LibrariesAndSDKs/display-library/blob/master/Public-Documents/README.md#end-user-license-agreement
this software is bound by the "SOFTWARE DEVELOPMENT KIT LICENSE AGREEMENT" PDF located at
https://github.com/GPUOpen-LibrariesAndSDKs/display-library/blob/master/Public-Documents/ADL%20SDK%20EULA.pdf
]])
Restrições de versão em portas
Restrições de versão dentro dos ports geralmente devem ser evitadas, pois podem impedir a evolução independente dos projetos. A adição de tais restrições só é permitida quando há uma justificativa bem documentada, como incompatibilidade comprovada com versões anteriores específicas. Essas restrições não devem ser usadas apenas para manter a paridade com projetos independentes.
As variáveis em MAYBE_UNUSED_VARIABLES devem ser aplicadas a pelo menos uma configuração
Ao adicionar uma nova variável a MAYBE_UNUSED_VARIABLES a fim de silenciar um aviso durante a etapa de configuração do CMake, você deve adicionar um comentário explicando o caso em que a nova variável se aplica. Se uma variável não se aplicar em nenhuma configuração, é muito provável que exista um bug subjacente (por exemplo, um nome de variável com ortografia incorreta) e adicioná-lo não terá nenhum efeito real no build.
vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS
FEATURES
windowsfeature WINDOWS_OPTION
)
vcpkg_configure_cmake(
SOURCE_PATH "${SOURCE_PATH}"
OPTIONS
${FEATURE_OPTIONS}
MAYBE_UNUSED_VARIABLES
# Applies only on Windows
WINDOWS_OPTION
)
Recursos
Não use recursos para implementar alternativas
Os recursos devem ser tratados como funcionalidade aditiva. Se port[featureA] estiver instalado e port[featureB] estiver instalado, então port[featureA,featureB] precisa ser instalado. Além disso, se uma segunda porta depender de [featureA] e uma terceira porta depender de [featureB], é necessário satisfazer as dependências da instalação da segunda e da terceira portas.
As bibliotecas nessa situação devem escolher uma das opções disponíveis, conforme expresso em vcpkg, e os usuários que desejam uma configuração diferente devem usar portas de sobreposição neste momento.
Exemplos existentes que não aceitaríamos hoje retidos para retrocompatibilidade:
-
libgit2,libzip,open62541todos têm recursos para selecionar um back-end TLS ou cripto.curltem diferentes opções de back-end de criptografia, mas permite selecionar entre elas em tempo de execução, o que significa que o princípio acima é mantido. -
darknettemopencv2,opencv3, recursos para controlar qual versão do opencv deve ser usada para suas dependências.
Um recurso pode ativar a funcionalidade de prévia ou beta.
Não obstante o acima, se houver uma ramificação de visualização ou semelhante em que a funcionalidade de visualização tenha uma alta probabilidade de não interromper a funcionalidade de não visualização (por exemplo, sem remoções de API), um recurso será aceitável para modelar essa configuração.
Exemplos:
- Os SDKs do Azure (do formulário
azure-Xxx) têm umpublic-previewrecurso. -
imguipossui um recursoexperimental-dockingque ativa sua ramificação de versão prévia, utilizando um commit de mesclagem anexado a cada uma de suas versões numeradas públicas.
Os recursos padrão não devem adicionar APIs
Observação
Um recurso habilitado por padrão pelo sistema de build upstream não implica que o recurso deve ser adicionado às default-features entradas. Como a finalidade pretendida de default-features não é modelar as decisões tomadas pelo upstream, mas sim fornecer conveniência aos usuários do modo clássico.
Os recursos padrão destinam-se a garantir que uma compilação razoavelmente funcional de uma biblioteca seja instalada para clientes que não sabem que a estão usando. Se eles não sabem que estão usando uma biblioteca, eles não podem saber como listar recursos. Por exemplo, libarchive expõe recursos que permitem algoritmos de compactação a uma interface genérica existente; se construída sem nenhum desses recursos, a biblioteca pode não ter utilidade.
Deve-se considerar cuidadosamente se um recurso deve estar ativado por padrão, porque desabilitar recursos padrão é complexo.
Desativar uma funcionalidade padrão como 'consumidor transitivo' requer:
- Todos os clientes desabilitam explicitamente os recursos padrão por meio de
"default-features": falseou incluindo[core]na lista de recursos na linha de comando. - Nomeando a dependência transitiva na
vcpkg installlinha de comando ou como uma dependência direta no manifesto de nível superior
No registro coletado do vcpkg, se o recurso adicionar APIs, executáveis ou outros binários adicionais, ele deverá estar desativado por padrão. Em caso de dúvida, não marque um recurso como padrão.
Não use recursos para controlar alternativas em interfaces publicadas
Se um consumidor de uma porta depender apenas da funcionalidade essencial dessa porta, é muito provável que ele não seja prejudicado pela ativação do recurso. Isso é ainda mais importante quando a alternativa não é controlada diretamente pelo consumidor, mas por configurações do compilador como /std:c++17 / -std=c++17.
Exemplos existentes que não aceitaríamos hoje retidos para retrocompatibilidade:
-
redis-plus-plus[cxx17]controla um polyfill, mas não integra a configuração na árvore instalada. -
ace[wchar]altera todas as APIs para aceitarconst wchar_t*em vez deconst char*.
Um recurso pode substituir polyfills por aliases, desde que a substituição seja incorporada à árvore instalada
Não obstante o acima, as portas podem remover polyfills com um recurso, desde que:
- Ativar o recurso altera os polyfills para sinônimos da entidade polyfilled
- O estado do polyfill é incorporado aos cabeçalhos instalados, reduzindo a probabilidade de erros "impossíveis" de não correspondência de ABI de runtime.
- É possível que um consumidor da porta escreva código que funcione em ambos os modos, por exemplo, usando um typedef que tem pollyfill ou não
Exemplo:
-
abseil[cxx17]mudaabsl::string_viewpara uma substituição oustd::string_view; o patch implementa o requisito de geração.
Soluções recomendadas
Se for crítico expor as alternativas subjacentes, recomendamos fornecer mensagens no momento da compilação para instruir o usuário sobre como copiar a porta em uma sobreposição privada:
set(USING_DOG 0)
message(STATUS "This version of LibContoso uses the Kittens backend. To use the Dog backend instead, create an overlay port of this with USING_DOG set to 1 and the `kittens` dependency replaced with `dog`.")
message(STATUS "This recipe is at ${CMAKE_CURRENT_LIST_DIR}")
message(STATUS "See the overlay ports documentation at https://github.com/microsoft/vcpkg/blob/master/docs/specifications/ports-overlay.md")
Técnicas de construção
Não use dependências de fornecedor
Não use cópias incorporadas de bibliotecas. Todas as dependências devem ser divididas e empacotadas separadamente para que possam ser atualizadas e mantidas.
As dependências incorporadas introduzem vários desafios que entram em conflito com as metas do vcpkg de fornecer um sistema de gerenciamento de pacotes confiável, consistente e manutenível.
Dificuldade em Atualizações: cópias inseridas de bibliotecas dificultam o acompanhamento e a aplicação de atualizações, incluindo patches de segurança, dos projetos de origem. Isso leva a possíveis riscos de segurança e dependências desatualizadas no ecossistema.
Conflitos de Símbolo: as dependências fornecedoras podem causar conflitos de símbolo quando vários pacotes incluem versões diferentes da mesma biblioteca.
Por exemplo: Se o Pacote A inclui a Biblioteca X (versão 1) e o Pacote B inclui a Biblioteca X (versão 2), um aplicativo que vincula ambos os pacotes pode apresentar erros de tempo de execução ou comportamento indefinido devido a símbolos conflitantes.
Ao empacotar dependências separadamente, o vcpkg garante que uma única versão de uma biblioteca seja usada em todos os pacotes, eliminando esses conflitos.
Conformidade de Licenciamento: as dependências incluídas podem obscurecer o licenciamento das bibliotecas inseridas, potencialmente violando seus termos ou resultando em problemas de compatibilidade.
Aumento da carga de manutenção: manter as dependências fornecedoras em sincronia com suas versões upstream requer um esforço manual significativo e geralmente leva a trabalho duplicado entre pacotes.
Dê preferência ao CMake
Quando vários sistemas de compilação estiverem disponíveis, prefira usar o CMake.
Além disso, quando apropriado, pode ser mais simples e fácil de manter reescrever sistemas de build alternativos no CMake usando diretivas file(GLOB).
Exemplos: abseil
Escolher binários estáticos ou compartilhados
Ao criar bibliotecas do CMake, vcpkg_cmake_configure() o passará o valor correto para BUILD_SHARED_LIBS com base na variante solicitada pelo usuário.
Você pode calcular parâmetros de configuração alternativos usando string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" ...).
# portfile.cmake
string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "static" KEYSTONE_BUILD_STATIC)
string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "dynamic" KEYSTONE_BUILD_SHARED)
vcpkg_cmake_configure(
SOURCE_PATH ${SOURCE_PATH}
OPTIONS
-DKEYSTONE_BUILD_STATIC=${KEYSTONE_BUILD_STATIC}
-DKEYSTONE_BUILD_SHARED=${KEYSTONE_BUILD_SHARED}
)
Se uma biblioteca não oferecer opções de configuração para selecionar a variante de compilação, a compilação deverá ser corrigida. Ao corrigir uma compilação, você deve sempre tentar maximizar a capacidade de manutenção futura do port. Normalmente, isso significa minimizar o número de linhas que precisam ser alteradas para corrigir o problema em questão.
Exemplo: aplicação de patch em uma biblioteca do CMake para evitar a criação de variantes indesejadas
Por exemplo, ao corrigir uma biblioteca baseada em CMake, pode ser suficiente adicionar EXCLUDE_FROM_ALL a destinos indesejados e encapsular a chamada install(TARGETS ...) em um if(BUILD_SHARED_LIBS). Isso será mais curto do que quebrar ou excluir todas as linhas que mencionam a variante indesejada.
Para um projeto CMakeLists.txt com os seguintes conteúdos:
add_library(contoso SHARED contoso.c)
add_library(contoso_static STATIC contoso.c)
install(TARGETS contoso contoso_static EXPORT ContosoTargets)
install(EXPORT ContosoTargets
FILE ContosoTargets
NAMESPACE contoso::
DESTINATION share/contoso)
Apenas a install(TARGETS) linha precisa ser corrigida.
add_library(contoso SHARED contoso.c)
add_library(contoso_static STATIC contoso.c)
if(BUILD_SHARED_LIBS)
set_target_properties(contoso_static PROPERTIES EXCLUDE_FROM_ALL 1)
install(TARGETS contoso EXPORT ContosoTargets)
else()
set_target_properties(contoso PROPERTIES EXCLUDE_FROM_ALL 1)
install(TARGETS contoso_static EXPORT ContosoTargets)
endif()
install(EXPORT ContosoTargets
FILE ContosoTargets
NAMESPACE contoso::
DESTINATION share/contoso)
Ao definir recursos, controle explicitamente as dependências
Ao definir um recurso que captura uma dependência opcional, certifique-se de que a dependência não será usada acidentalmente quando o recurso não estiver explicitamente habilitado.
set(CMAKE_DISABLE_FIND_PACKAGE_ZLIB ON)
set(CMAKE_REQUIRE_FIND_PACKAGE_ZLIB OFF)
if ("zlib" IN_LIST FEATURES)
set(CMAKE_DISABLE_FIND_PACKAGE_ZLIB OFF)
set(CMAKE_REQUIRE_FIND_PACKAGE_ZLIB ON)
endif()
vcpkg_cmake_configure(
SOURCE_PATH ${SOURCE_PATH}
OPTIONS
-DCMAKE_DISABLE_FIND_PACKAGE_ZLIB=${CMAKE_DISABLE_FIND_PACKAGE_ZLIB}
-DCMAKE_REQUIRE_FIND_PACKAGE_ZLIB=${CMAKE_REQUIRE_FIND_PACKAGE_ZLIB}
)
O snippet abaixo usando vcpkg_check_features() é equivalente.
vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS
FEATURES
"zlib" CMAKE_REQUIRE_FIND_PACKAGE_ZLIB
INVERTED_FEATURES
"zlib" CMAKE_DISABLE_FIND_PACKAGE_ZLIB
)
vcpkg_cmake_configure(
SOURCE_PATH ${SOURCE_PATH}
OPTIONS
${FEATURE_OPTIONS}
)
ZLIB no trecho diferencia maiúsculas de minúsculas. Para obter mais informações, consulte a documentação CMAKE_DISABLE_FIND_PACKAGE_<PackageName> e CMAKE_REQUIRE_FIND_PACKAGE_<PackageName>.
Colocar libs conflitantes em um manual-link diretório
Uma lib é considerada conflitante se fizer o seguinte:
- Definir
main - Defina malloc
- Definir símbolos que também são declarados em outras bibliotecas
Libs conflitantes são geralmente intencionais e não são consideradas um defeito. Como alguns sistemas de compilação se vinculam a tudo no diretório lib, eles devem ser movidos para um subdiretório chamado manual-link.
Instalando binários pré-compilados
As portas que instalam artefatos predefinidos (somente binários) são permitidas, mas altamente desencorajadas, desde que não bloqueiem efetivamente a alteração das versões de outras portas. A compilação a partir do código fonte é preferida porque respeita todas as configurações do vcpkg que alteram o compilador ou sinalizadores.
Rejeitaremos portas que atendam a todas as seguintes condições:
- Instalar binários pré-compilados em vez de criar a partir do código fonte e
- Esses binários têm (ou exigem em runtime) dependências fornecidas por outras portas no registro coletado e
- Os artefatos instalados passam a fazer parte do domínio de links públicos do vcpkg – ou seja, eles mesmos instalam bibliotecas/cabeçalhos/CMake ou metadados pkg-config, aos quais portas dependentes ou projetos de usuários devem se vincular.
Racionalidade: essa combinação bloqueia efetivamente a ABI do grafo de dependência para as versões usadas quando o upstream predefinido foi produzido. O vcpkg não pode atualizar com segurança (por exemplo) zlib, openssl ou dependências semelhantes sem arriscar sutis quebras de ODR/ABI para usuários que se vinculam à biblioteca já construída, além de os usuários poderem perder patches de segurança críticos.
"Insere o domínio de link publicado" normalmente significa qualquer um dos:
- Instalação
.lib,.a,.so,.dylibou importação de bibliotecas destinadas aos consumidores para vinculação. - Cabeçalhos de envio que fazem referência (diretamente ou por meio de código embutido/modelo) símbolos, tipos ou macros de outras portas vcpkg.
- Instalando arquivos de configuração do CMake/pkg-config que invocam
find_dependency()/Requires:em outras portas do vcpkg.
Cenários permitidos (mas ainda desencorajados):
- Ferramentas auxiliares apenas para host (executáveis) usadas no tempo de construção cujas saídas são consumidas, mas que não são vinculadas por portos dependentes, desde que agrupem dependências privadas ou dependam apenas de bibliotecas de tempo de execução onipresentes do sistema.
- Bibliotecas predefinidas totalmente autocontidas que vinculam estaticamente todas as dependências de OSS E não expõem seus símbolos ou tipos por meio de cabeçalhos instalados ou interfaces exportadas (os consumidores não podem observar ou depender da ABI transitiva).
- Pacotes somente de dados, firmware ou ativos não vinculados ao código do usuário.
Exemplos proibidos:
- Um
libfoopré-construído que instalalib/libfoo.libmais cabeçalhos, incluindo<zlib.h>e foi compilado contra uma versão específicazlib; os consumidores então vinculam contralibfooesperando compatibilidade. - Um SDK pré-definido que instala um arquivo de pacote do CMake chamando
find_dependency(OpenSSL)enquanto o binário foi compilado contra uma versão mais antiga do OpenSSL.
Mitigações/alternativas:
- Forneça uma compilação de origem usando scripts upstream ou adicione uma camada fina CMake.
- Peça ao repositório upstream para publicar um lançamento baseado em código-fonte ou instruções de compilação reproduzíveis; referencie o problema ou PR do upstream em um comentário em
portfile.cmakeouvcpkg.json. - Use uma porta de overlay ou um registro privado para componentes pré-construídos específicos da organização que não podem satisfazer essas regras.
Controle de versão
Siga as convenções comuns para o "version" campo
Ao criar um novo port, siga a convenção de controle de versão usada pelo autor do pacote. Ao atualizar o port, continue a usar a mesma convenção, a menos que o upstream diga o contrário. Para obter uma explicação completa de nossas convenções, consulte nossa documentação de controle de versão.
Se o upstream não publica uma versão há algum tempo, não altere o esquema de controle de versão do port para version-date para obter as alterações mais recentes. Esses commits podem incluir alterações que não estão prontas para produção. Em vez disso, peça ao repositório upstream para publicar uma nova versão.
Atualize o "port-version" campo no arquivo de manifesto de todas as portas modificadas
vcpkg usa esse campo para determinar se uma determinada porta está desatualizada e deve ser alterada sempre que o comportamento da porta for alterado.
Nossa convenção é usar o campo "port-version" para alterações na porta que não alteram a versão original e redefinir o "port-version" para zero quando uma atualização para a versão original for feita.
Por exemplo:
- A versão do pacote do Zlib é atualmente
1.2.1, sem um"port-version"explícito (equivalente a um"port-version"de0). - Você descobriu que o arquivo de copyright errado foi implantado e corrigiu isso no portfile.
- Você deve atualizar o
"port-version"campo no arquivo de manifesto para1.
Consulte a documentação de controle de versão para obter mais informações.
Atualizar os arquivos de versão em versions/ de qualquer porta modificada
O vcpkg usa um conjunto de arquivos de metadados para alimentar seu recurso de controle de versão. Esses arquivos estão localizados nos seguintes locais:
-
${VCPKG_ROOT}/versions/baseline.json, (este arquivo é comum a todos os ports) e -
${VCPKG_ROOT}/versions/${first-letter-of-portname}-/${portname}.json(um por porta).
Por exemplo, para zlib os arquivos relevantes são:
${VCPKG_ROOT}/versions/baseline.json${VCPKG_ROOT}/versions/z-/zlib.json
Esperamos que cada vez que você atualizar um port, você também atualize seus arquivos de versão.
O método recomendado para atualizar esses arquivos é executar o x-add-version comando, por exemplo:
vcpkg x-add-version zlib
Se você estiver atualizando várias portas ao mesmo tempo, em vez disso, poderá executar:
vcpkg x-add-version --all
para atualizar os arquivos de todas as portas modificadas de uma só vez.
Para obter mais informações, consulte os artigos Referência de controle de versão e Registros.
Aplicação de patch
O vcpkg é uma solução de empacotamento, não os proprietários finais dos componentes que implantamos. Precisamos aplicar patches em alguns casos para melhorar a compatibilidade dos componentes com as plataformas ou a compatibilidade dos componentes entre si.
- Queremos evitar patches que:
- o upstream discordaria
- Causar vulnerabilidades ou travamentos
- não seja possível manter as atualizações de versão upstream
- sejam grandes o suficiente para causar complicações de licença com o repositório vcpkg em si
Notifique os proprietários upstream sobre patches upstream relevantes
Se um patch puder ser útil para o upstream, o upstream deve ser informado sobre o conteúdo do patch. (Patches que aplicam comportamento específico do vcpkg não relacionado ao upstream, como remover uma dependência vendorizada, não requerem notificação.)
Para evitar situações em que o upstream discorde do patch, esperaremos pelo menos 30 dias para aplicar esses patches.
Ignoraremos esse período de espera se tivermos alta confiança de que a alteração está correta. Exemplos de patches de alta confiança incluem, mas não estão limitados a:
- A aceitação do upstream como um patch (por exemplo, o backport de uma alteração específica de uma solicitação de pull upstream foi mesclado).
- Adicionar
#includes ausentes. - Correções de código de produto pequenas e óbvias (por exemplo, inicializar uma variável não inicializada).
- Desativar os componentes irrelevantes no vcpkg do build, como testes ou exemplos.
Dê preferência a opções em vez de correções
É preferível definir opções em uma chamada para vcpkg_configure_xyz() do que modificar as configurações diretamente.
Opções comuns que permitem evitar patches:
- [MSBUILD]
<PropertyGroup>As configurações dentro do arquivo de projeto podem ser substituídas por/p:parâmetros - [CMAKE] As chamadas para
find_package(XYz)em scripts CMake podem ser desativadas por meio de-DCMAKE_DISABLE_FIND_PACKAGE_XYz=ON - [CMAKE] As variáveis de cache (declaradas como
set(VAR "value" CACHE STRING "Documentation")ouoption(VAR "Documentation" "Default Value")) podem ser substituídas apenas passando-as na linha de comando como-DVAR:STRING=Foo. Uma exceção notável é se oFORCEparâmetro for passado paraset(). Para obter mais informações, consulte a documentação do CMakeset
Dê preferência a baixar patches aprovados em vez de verificá-los na porta
Se um arquivo de patch aprovado ou mesclado puder ser obtido do upstream, as portas devem tentar baixá-los e aplicá-los em vez de tê-los como parte dos arquivos de porta. Este processo é preferido porque:
- Confirma que o upstream aceitou as modificações do patch
- Simplifica o processo de revisão, transferindo o ônus para cima
- Reduz o tamanho do repositório vcpkg para usuários que não estão usando o patch
- Evita conflitos de licença com o repositório vcpkg
Os patches devem ser baixados de um endpoint estável para evitar conflitos de SHA.
Ao baixar arquivos de patch de uma solicitação de pull ou commit do GitHub e do GitLab, o ?full_index=1 parâmetro deve ser anexado à URL de download.
Exemplos:
https://github.com/google/farmhash/pull/40.diff?full_index=1https://github.com/linux-audit/audit-userspace/commit/f8e9bc5914d715cdacb2edc938ab339d5094d017.patch?full_index=1https://gitlab.kitware.com/paraview/paraview/-/merge_requests/6375.diff?full_index=1
Dê preferência a aplicar patches em vez de substituir valores de VCPKG_<VARIABLE>
Algumas variáveis prefixadas com VCPKG_<VARIABLE> têm um equivalente CMAKE_<VARIABLE>.
No entanto, nem todos eles são passados para o build do pacote interno (consulte implementação: cadeia de ferramentas do Windows).
Considere o seguinte exemplo:
set(VCPKG_C_FLAGS "-O2 ${VCPKG_C_FLAGS}")
set(VCPKG_CXX_FLAGS "-O2 ${VCPKG_CXX_FLAGS}")
Usando as cadeias de ferramentas integradas de vcpkg, isso funciona, porque o valor de VCPKG_<LANG>_FLAGS é encaminhado para a variável apropriada CMAKE_LANG_FLAGS. No entanto, um conjunto de ferramentas personalizado que não esteja ciente das variáveis de vcpkg não as encaminhará.
Por causa disso, é preferível corrigir o sistema de compilação diretamente ao definir CMAKE_<LANG>_FLAGS.
Minimizar patches
Ao fazer alterações em uma biblioteca, esforce-se para minimizar a diferença final. Isso significa que você não deve reformatar o código-fonte upstream ao fazer alterações que afetem uma região. Ao desabilitar uma condicional, é melhor adicionar um AND FALSE ou && 0 à condição do que excluir todas as linhas da condicional. Se uma região grande precisar ser desabilitada, é mais curto adicionar um if(0) ou #if 0 em volta da região em vez de excluir todas as linhas do patch.
Não adicione patches se o port estiver desatualizado e atualizar o port para uma versão mais recente resolveria o mesmo problema. O vcpkg prefere atualizar os ports em vez de corrigir versões desatualizadas.
Isso ajuda a manter o tamanho do repositório vcpkg baixo, bem como melhora a probabilidade de que o patch seja aplicado a versões futuras do código.
Não implementar recursos em patches
O objetivo da aplicação de patch no vcpkg é habilitar a compatibilidade com compiladores, bibliotecas e plataformas. Não é para implementar novos recursos em vez de seguir o procedimento adequado de código aberto (enviar um problema / PR / etc).
Não crie testes/documentos/exemplos por padrão
Ao enviar uma nova porta, verifique se há opções como BUILD_TESTS ou ou WITH_TESTS e POCO_ENABLE_SAMPLES certifique-se de que os binários adicionais estejam desativados. Isso minimiza os tempos de compilação e as dependências para o usuário médio.
Opcionalmente, você pode adicionar um test recurso que permite a construção dos testes, no entanto, isso não deve estar na Default-Features lista.
Permitir que os usuários existentes da biblioteca mudem para vcpkg
Não adicione CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS
A menos que o autor da biblioteca já a esteja usando, não devemos usar essa funcionalidade do CMake porque ela interage mal com modelos C++ e interrompe certos recursos do compilador. Bibliotecas que não fornecem um arquivo .def e não usam declarações __declspec() simplesmente não dão suporte a builds compartilhados para Windows e devem ser marcadas como tal:
if(VCPKG_TARGET_IS_WINDOWS)
vcpkg_check_linkage(ONLY_STATIC_LIBRARY)
endif()
Não renomeie binários fora dos nomes fornecidos pelo upstream
Isso significa que, se a biblioteca upstream tiver nomes diferentes em release e debug (libx versus libxd), a biblioteca de depuração não deverá ser renomeada para libx. Vice-versa, se a biblioteca upstream tiver o mesmo nome em release e debug, não devemos introduzir um novo nome.
Advertência importante:
- Variantes estáticas e compartilhadas geralmente devem ser renomeadas para um esquema comum. Isso permite que os consumidores usem um nome comum e ignorem a ligação a jusante. Isso é seguro porque disponibilizamos apenas um de cada vez.
Se uma biblioteca gerar arquivos de integração do CMake (foo-config.cmake), a renomeação deverá ser feita aplicando patch na própria construção do CMake, em vez de simplesmente executar file(RENAME) nos arquivos de saída/LIBs.
Por fim, os arquivos DLL no Windows nunca devem ser renomeados após a compilação porque quebram as LIBs geradas.
Manifestos
Exigimos que o arquivo de manifesto seja formatado. Use o seguinte comando para formatar todos os arquivos de manifesto:
> vcpkg format-manifest --all
Trigêmeos
Não estamos aceitando solicitações para adicionar trigêmeos fora da comunidade no momento. A promoção de um status comunitário para um status de tripleto completo é baseada principalmente no orçamento disponível para adquirir hardware para testar esses tripletos e será impulsionada por métricas enviadas pelo vcpkg, a fim de maximizar a probabilidade de que o que as pessoas realmente utilizam seja totalmente testado.
Adicionaremos tripletos da comunidade se:
- É demonstrado que as pessoas realmente usarão esse conjunto tripleto da comunidade; e
- não sabemos que tal tripleto está quebrado.
Por exemplo, não adicionamos um tripleto https://github.com/microsoft/vcpkg/pull/29034 porque o autor estava apenas tentando "completar o conjunto" em vez de indicar que realmente usaria isso, e não adicionamos linux-dynamic até que a solução patchelf para tornar os resultados relocáveis fosse criada.
Notas úteis de implementação
Os arquivos de porta são executados no modo de script
Enquanto portfile.cmake's e CMakeLists.txt's compartilham uma sintaxe comum e as construções principais da linguagem CMake (também conhecidas como "Comandos de Script"), os portfiles rodam no "Modo Script", enquanto os CMakeLists.txt arquivos rodam no "Modo Projeto". A diferença mais importante entre esses dois modos é que o "Modo Script" não possui os conceitos de "Toolchain", "Language" e "Target". Quaisquer comportamentos, incluindo comandos de script, que dependem dessas construções (por exemplo CMAKE_CXX_COMPILER, , CMAKE_EXECUTABLE_SUFFIX, CMAKE_SYSTEM_NAME) não estarão corretos.
Portfiles têm acesso direto às variáveis definidas no arquivo tripleto, mas os CMakeLists.txts não têm (embora muitas vezes ocorra uma tradução que acontece -- VCPKG_LIBRARY_LINKAGE versus BUILD_SHARED_LIBS).
Portfiles e compilações de projeto invocadas por portfiles são executados em processos diferentes. Conceitualmente:
+----------------------------+ +------------------------------------+
| CMake.exe | | CMake.exe |
+----------------------------+ +------------------------------------+
| Triplet file | ====> | Toolchain file |
| (x64-windows.cmake) | | (scripts/buildsystems/vcpkg.cmake) |
+----------------------------+ +------------------------------------+
| Portfile | ====> | CMakeLists.txt |
| (ports/foo/portfile.cmake) | | (buildtrees/../CMakeLists.txt) |
+----------------------------+ +------------------------------------+
Para determinar o host em um arquivo de porta, as variáveis padrão do CMake são boas (CMAKE_HOST_WIN32).
Para determinar o destino em um arquivo de porta, as variáveis do tripleto do vcpkg devem ser usadas (VCPKG_CMAKE_SYSTEM_NAME).
Consulte também nossa documentação de triplet para obter uma enumeração completa das configurações possíveis.