Guia do mantenedor
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
As portas na linha de base atual devem ser instaláveis simultaneamente
Desejamos 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 em pelo menos algumas configurações. Permitir que as portas se excluam interrompe a capacidade de testar essas configurações, pois o número de compilações necessárias para esses testes aumentaria à medida 2^number_of_such_cases
que o . 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.
Se você deseja 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
vez de tentar adicionar portas adicionais 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 sobreposição. Isso não é mais aceito porque os registros permitem a publicação dessas portas não testadas sem modificar o registro coletado.
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
,- numbers
Por exemplo, ao comparar os seguintes nomes de portas: ip-cpp
, libip
e ip5
remover os desambiguadores inválidos, todos eles são reduzidos ao mesmo radical (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
.
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 dos novos PRs deve ser aberta como rascunhos e convertida em PRs normais assim que o CI for aprovado.
Para obter mais informações sobre PRs de rascunho do GitHub, consulte Introdução a solicitações de pull de rascunho.
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 preterida de without
ARCHIVE
deve ser substituída pela sobrecarga suportadavcpkg_extract_source_archive()
porARCHIVE
. vcpkg_apply_patches()
deve ser substituído pelosPATCHES
argumentos 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_cmake
deve ser substituído porvcpkg_cmake_configure()
após a remoçãoPREFER_NINJA
vcpkg_build_cmake
deve ser substituído porvcpkg_cmake_build()
vcpkg_install_cmake
deve ser substituído porvcpkg_cmake_install()
vcpkg_fixup_cmake_targets
deve 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, para permitir o bloqueio do comportamento dos auxiliares em uma versão específica. As portas de ferramentas precisam ser adicionadas às portas do seu port "dependencies"
, assim:
{
"name": "vcpkg-cmake",
"host": true
},
{
"name": "vcpkg-cmake-config",
"host": true
}
Evite comentários excessivos em arquivos de porta
Idealmente, os arquivos de porta devem ser curtos, simples e o mais declarativos possível.
Remova todos os comentários clichês introduzidos pelo comando antes de create
enviar uma PR.
As portas não devem ser dependentes do caminho
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 ports não devem tentar detectar se algo é fornecido na árvore instalada por outro port antes de tomar 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 há duas portas que um usuário use simultaneamente para fornecer 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 vcpkgunofficial::<port>::<target>
como um destino exportado dessa porta.
Exemplos:
brotli
cria ounofficial-brotli
pacote, 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
novos portos, 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.
Recursos
Não use recursos para implementar alternativas
Os recursos devem ser tratados como funcionalidade aditiva. Se port[featureA]
instalar e port[featureB]
instalar, então port[featureA,featureB]
deve instalar. Além disso, se uma segunda porta depender e [featureA]
uma terceira porta depender do [featureB]
, a instalação da segunda e da terceira portas deve ter suas dependências satisfeitas.
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 compatibilidade com versões anteriores:
libgit2
,libzip
,open62541
todos têm recursos para selecionar um back-end TLS ou cripto.curl
tem 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.darknet
temopencv2
,opencv3
, recursos para controlar qual versão do opencv usar para suas dependências.
Um recurso pode envolver a funcionalidade de visualização 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-preview
recurso. imgui
tem umexperimental-docking
recurso que envolve sua ramificação de encaixe de visualização que usa um commit de mesclagem anexado a cada uma de suas versões numeradas públicas.
Os recursos padrão não devem adicionar APIs
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.
Desabilitar um recurso padrão como um consumidor 'transitivo' requer:
- Todos os clientes desabilitam explicitamente os recursos padrão por meio
"default-features": false
ou incluindo[core]
na lista de recursos na linha de comando. - Nomeando a dependência transitiva na
vcpkg install
linha 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 principal dessa porta, com alta probabilidade ele não deverá ser interrompido ativando o 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 compatibilidade com versões anteriores:
redis-plus-plus[cxx17]
Controla um polyfill, mas não incorpora 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, os ports podem remover polyfills com um recurso, desde que:
- Ativar o recurso altera os polyfills para aliases da entidade polyfilled
- O estado do polyfill é incorporado aos cabeçalhos instalados, de modo que erros de tempo de execução "impossíveis" de incompatibilidade de ABI sejam improváveis
- É possível que um consumidor do port escreva código que funcione em ambos os modos, por exemplo, usando um typedef que é polipreenchido ou não
Exemplo:
abseil[cxx17]
mudaabsl::string_view
para uma substituição oustd::string_view
; o patch implementa o requisito de cozimento.
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.
Prefira usar o CMake
Quando vários sistemas de compilação estiverem disponíveis, prefira usar o CMake.
Além disso, quando apropriado, pode ser mais fácil e fácil de manter reescrever sistemas de compilação alternativos no CMake usando file(GLOB)
diretivas.
Exemplos: rapel
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 tocadas 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 aplicar patches em uma biblioteca baseada em CMake, pode ser suficiente adicionar EXCLUDE_FROM_ALL
a destinos indesejados e encapsular a install(TARGETS ...)
chamada em um if(BUILD_SHARED_LIBS)
arquivo . 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 using 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 snippet diferencia maiúsculas de minúsculas. Para obter mais informações, consulte a CMAKE_DISABLE_FIND_PACKAGE_<PackageName>
documentação 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
- Definir malloc
- Definir símbolos que também são declarados em outras bibliotecas
Libs conflitantes são normalmente por design 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
.
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
obter as alterações mais recentes. Essas confirmações 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 "port-version"
campo para alterações na porta que não alteram a versão upstream e redefinir o "port-version"
de volta para zero quando uma atualização para a versão upstream for feita.
Por exemplo:
- A versão do pacote do Zlib é atualmente
1.2.1
, sem explícito"port-version"
(equivalente a um"port-version"
de0
). - Você descobriu que o arquivo de direitos autorais errado foi implantado e corrigiu isso no arquivo de port.
- 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 de versions/
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.
Observação
Esses comandos exigem que você tenha confirmado suas alterações nas portas antes de executá-las. O motivo é que o Git SHA do diretório de porta é necessário nesses arquivos de versão. Mas não se preocupe, o x-add-version
comando irá avisá-lo se você tiver alterações locais que não foram confirmadas.
Para obter mais informações, consulte a referência de controle de versão e Criando 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:
- upstream discordaria de
- Causar vulnerabilidades ou travamentos
- somos incapazes de manter as atualizações de versão upstream
- são grandes o suficiente para causar emaranhamento de licença com o próprio repositório vcpkg
Notifique os proprietários upstream para patches relevantes upstream
Se um patch puder ser útil pelo upstream, o upstream deverá ser notificado sobre o conteúdo do patch. (Patches que aplicam comportamento específico do vcpkg não relacionado ao upstream, como o desvendor de uma dependência, não exigem 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).
- Adicionando s ausentes
#include
. - Correções de código de produto pequenas e óbvias (por exemplo, inicializar uma variável não inicializada).
- Desabilitar componentes irrelevantes no vcpkg da compilação, como testes ou exemplos.
Prefira opções em vez de patches
É preferível definir opções em uma chamada para vcpkg_configure_xyz()
corrigir 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 meio/p:
de 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 oFORCE
parâmetro for passado paraset()
. Para obter mais informações, consulte a documentação do CMakeset
Prefira baixar patches aprovados em vez de verificá-los na porta
Se um arquivo de patch aprovado ou mesclado puder ser obtido do upstream, os ports devem tentar baixá-los e aplicá-los em vez de tê-los como parte dos arquivos de port. Este processo é preferido porque:
- Confirma que o upstream aceitou as alterações de 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=1
https://github.com/linux-audit/audit-userspace/commit/f8e9bc5914d715cdacb2edc938ab339d5094d017.patch?full_index=1
https://gitlab.kitware.com/paraview/paraview/-/merge_requests/6375.diff?full_index=1
Prefira corrigir em vez de substituir VCPKG_<VARIABLE>
valores
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 vcpkg
as cadeias de ferramentas integradas do , 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 vcpkg
variáveis do não as encaminhará.
Por causa disso, é preferível corrigir o sistema de compilação diretamente ao definir CMAKE_<LANG>_FLAGS
.
Minimize os 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
ao redor 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. As bibliotecas que não fornecem um arquivo .def e não usam declarações __declspec() simplesmente não oferecem suporte a compilações compartilhadas para Windows e devem ser marcadas como tal com vcpkg_check_linkage(ONLY_STATIC_LIBRARY)
.
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 por meio da aplicação de patch da própria compilação do CMake, em vez de simplesmente chamar file(RENAME)
os arquivos/LIBs de saída.
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 da comunidade para o status de trigêmeo completo é baseada principalmente no orçamento do hardware para testar esses trigêmeos e será impulsionada por métricas enviadas pelo vcpkg para maximizar a probabilidade de o que as pessoas realmente usam ser totalmente testado.
Adicionaremos trigêmeos da comunidade se:
- Está demonstrado que as pessoas realmente usarão esse trigêmeo da comunidade; e
- não sabemos se esse trigêmeo está quebrado.
Por exemplo, não adicionamos um trigêmeo https://github.com/microsoft/vcpkg/pull/29034 porque o autor estava apenas tentando "completar o conjunto" em vez de indicar que realmente usaria tal coisa, 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 construções principais da linguagem CMake (também conhecidas como "Comandos de Script"), os arquivos de porta são executados no "Modo Script", enquanto CMakeLists.txt
os arquivos são executados 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.
Os arquivos de porta têm acesso direto às variáveis definidas no arquivo tripleto, mas CMakeLists.txt
s não (embora muitas vezes haja 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 triplas vcpkg devem ser usadas (VCPKG_CMAKE_SYSTEM_NAME
).
Consulte também nossa documentação de trigêmeos para obter uma enumeração completa das configurações possíveis.