Guia do mantenedor
Este documento lista um conjunto de políticas que você deve aplicar ao adicionar ou atualizar uma receita de porta. Destina-se a servir o papel do Manual de Políticas do Debian, das Diretrizes do Mantenedor do Homebrewe do Livro de Receitas de Fórmulas do Homebrew.
Objetivos gerais de conceção do registo
As portas na linha de base atual devem ser instaláveis simultaneamente
Desejamos poder mostrar aos utilizadores finais das bibliotecas no registo curado que a combinação de bibliotecas em qualquer versão base que publicamos foi testada para funcionar em conjunto em pelo menos algumas configurações. Permitir que as portas se excluam quebra a capacidade de testar tais configurações, já que o número de compilações necessárias para tais testes cresceria à medida que 2^number_of_such_cases
. Além disso, a instalação de dependências adicionais é sempre considerada "segura": não há como uma porta ou usuário final afirmar que uma dependência não está instalada em seus requisitos.
Se pretender representar tal situação alternativa para os utilizadores, considere descrever como alguém pode criar uma porta de sobreposição para, implementando o formulário alternativo com um comentário em portfile.cmake
, em vez de tentar adicionar portas adicionais nunca construídas na integração contínua do registo curado. Por exemplo, ver glad@0.1.36.
Antes da introdução de registros, aceitamos várias portas não testadas como alternativas, como boringssl
, que poderiam 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 selecionado.
Estrutura de Relações Públicas
Faça solicitações pull separadas por porta
Sempre que possível, separe as alterações em várias PRs. Isso facilita significativamente a revisão e evita que problemas com um conjunto de alterações atrasem todas as outras.
Evite alterações triviais em arquivos intocados
Por exemplo, evite reformatar ou renomear variáveis em portfiles que, de outra forma, não têm motivo para serem modificados para o problema em questão. No entanto, se você precisar modificar o arquivo para o objetivo principal do PR (atualizar a biblioteca), então, obviamente, mudanças benéficas, como a correção de erros de digitação, são apreciadas!
Verificar nomes em relação a outros repositórios
Os nomes das portas devem tentar ser inequívocos sobre qual pacote a porta instala. Idealmente, pesquisar o nome do porto em um mecanismo de busca 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 é Repology.
Projetos com nomes curtos ou com nomes de palavras comuns podem exigir desambiguação, especialmente quando não há projetos com uma forte associação à palavra dada. Por exemplo, uma porta com o nome ip
não é aceitável, pois é provável que vários projetos sejam nomeados de forma semelhante.
Exemplos de bons desambiguadores sã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 porta: ip-cpp
, libip
e ip5
e remover os desambiguadores inválidos, todos eles são reduzidos à mesma haste (ip
) e, portanto, são considerados como tendo o mesmo nome.
Uma exceção a esta diretriz é feita para nomes que estão fortemente associados a um único projeto. Por exemplo: libpng
, openssl
e zlib
.
Usar RPs de rascunho do GitHub
Os Rascunhos de PR do GitHub são uma ótima maneira de obter feedback humano ou de CI sobre o trabalho que ainda não está pronto para ser integrado. A maioria das novas RP deve ser aberta como rascunho e convertida em RP normal assim que a IC for aprovada.
Para obter mais informações sobre PRs de rascunho do GitHub, consulte Introducing draft pull requests.
Portfiles
Evite funções auxiliares preteridas
Neste momento, os seguintes auxiliares são 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()
semARCHIVE
deve ser substituída pela sobrecarga suportada comARCHIVE
. -
vcpkg_apply_patches()
deve ser substituído pelos argumentosPATCHES
para as funções auxiliares de "extrair" (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 bloquear o comportamento dos auxiliares em uma versão específica. As portas de ferramentas precisam ser adicionadas 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 portfiles devem ser curtos, simples e o mais declarativos possível.
Remova todos os comentários padrão introduzidos pelo comando create
antes de enviar um PR.
As portas não devem depender do caminho
As portas não devem alterar seu comportamento com base em quais portas já estão instaladas em um formato que alteraria o conteúdo que a porta instala. Por exemplo, dado:
> vcpkg install a
> vcpkg install b
> vcpkg remove a
e ainda
> vcpkg install b
Os arquivos instalados por b
devem ser os mesmos, independentemente da influência da instalação anterior do a
. Isso significa que as portas não devem tentar detetar se algo é fornecido na árvore instalada por outra porta antes de tomar qualquer ação. Uma causa específica e comum desse comportamento "dependente de caminho" é descrita abaixo em "Ao definir recursos, controle explicitamente as dependências".
Regra de atribuição de porta exclusiva
Em todo o sistema vcpkg, duas portas que um utilizador possa querer usar ao mesmo tempo não devem fornecer o mesmo ficheiro. Se uma porta tentar instalar um arquivo já fornecido por outro arquivo, a instalação falhará. Se uma porta quiser usar um nome extremamente comum para um cabeçalho, por exemplo, ela deve colocar esses cabeçalhos em um subdiretório em vez de em include
.
Esta propriedade é verificada regularmente por execuções de integração contínua que tentam instalar todas as portas no registro, que falhará com FILE_CONFLICTS
se duas portas fornecerem o mesmo arquivo.
Adicionar exportações 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 às 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 que a porta exporta, que não estão na biblioteca de origem, devem ter unofficial-
como um prefixo. Quaisquer destinos adicionais devem estar no espaço de nomes unofficial::<port>::
.
Isso significa que o usuário deve ver:
-
find_package(unofficial-<port> CONFIG)
é o método para obter o pacote exclusivo do vcpkg -
unofficial::<port>::<target>
como um destino exportado dessa porta.
Exemplos:
-
brotli
cria o pacoteunofficial-brotli
, produzindo o destinounofficial::brotli::brotli
.
Instalar arquivo de direitos autorais
Cada porta tem que fornecer um arquivo chamado 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 file
interno do CMake. Isso é desencorajado em favor de vcpkg_install_copyright
em 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 sobre 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 ele 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
As restrições de versão dentro dos portos devem geralmente ser evitadas, pois podem dificultar a evolução independente dos projetos. A adição de tais restrições só é permitida quando existe uma justificação bem documentada, como a incompatibilidade comprovada com versões anteriores específicas. Estas restrições não devem ser utilizadas apenas para manter a paridade com projetos independentes.
Caraterísticas
Não use recursos para implementar alternativas
Os recursos devem ser tratados como funcionalidade aditiva. Se port[featureA]
instala e port[featureB]
instala, então port[featureA,featureB]
deve instalar. Além disso, se uma segunda porta depende de [featureA]
e uma terceira porta depende de [featureB]
, a instalação da segunda e 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 serão mantidos para compatibilidade retroativa.
-
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 ativar a funcionalidade de visualização ou beta
Não obstante o acima, se houver uma ramificação de visualização ou similar 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 é aceitável para modelar essa configuração.
Exemplos:
- Os SDKs do Azure (do formato
azure-Xxx
) têm um recursopublic-preview
. -
imgui
tem um recurso deexperimental-docking
que envolve sua ramificação de encaixe de visualização que usa uma confirmação de mesclagem anexada a cada uma de suas versões públicas numeradas.
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 estão usando-a. Se eles não sabem que estão usando uma biblioteca, eles não podem saber listar recursos. Por exemplo, libarchive
expõe recursos que permitem algoritmos de compactação a uma interface genérica existente; Se construído sem qualquer um 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.
A desativação de um recurso padrão como consumidor "transitivo" exige:
- Todos os clientes que desativam explicitamente os recursos padrão via
"default-features": false
ou incluem[core]
na lista de recursos através da linha de comando. - Nomeando a dependência transitiva na linha de comando
vcpkg install
ou como uma dependência direta no manifesto de nível superior
No registro curado 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 depende apenas da funcionalidade principal dessa porta, há uma alta probabilidade de que eles não serão afetados ao ativar a funcionalidade. Isso é ainda mais importante quando a alternativa não é controlada diretamente pelo consumidor, mas por configurações de compilador como /std:c++17
/ -std=c++17
.
Exemplos existentes que não aceitaríamos hoje, mas que foram mantidos para compatibilidade retroativa.
-
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 esteja incorporada na árvore instalada.
Tendo em conta o exposto acima, as portas podem remover polyfills com uma característica, desde que:
- Ativar o recurso altera os polyfills para aliases da entidade polyfilled
- O estado do polyfill é incorporado nos cabeçalhos instalados, de modo que se tornem improváveis os erros "impossíveis" de incompatibilidade ABI em tempo de execução.
- É possível para um consumidor da porta escrever código que funciona em ambos os modos, por exemplo, usando um typedef que é polipreenchido ou não
Exemplo:
-
abseil[cxx17]
alteraabsl::string_view
a uma substituição oustd::string_view
; o patch implementa o requisito de cozedura.
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 fornecedores
Não utilize 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 de fornecedores apresentam vários desafios que entram em conflito com os objetivos do vcpkg de fornecer um sistema de gerenciamento de pacotes confiável, consistente e sustentável:
Dificuldade em atualizações: cópias incorporadas de bibliotecas dificultam o rastreamento e a aplicação de atualizações, incluindo patches de segurança, dos projetos upstream. Esta situação conduz a potenciais riscos de segurança e a dependências desatualizadas no ecossistema.
Conflitos de símbolos: dependências externas podem causar conflitos de símbolos quando vários pacotes incluem versões diferentes da mesma biblioteca.
Por exemplo: Se o Pacote A incorpora a Biblioteca X (versão 1) e o Pacote B incorpora a Biblioteca X (versão 2), um aplicativo que vincula ambos os pacotes pode enfrentar erros de tempo de execução ou comportamento indefinido devido a símbolos em conflito.
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: dependências de fornecedores podem obscurecer o licenciamento das bibliotecas incorporadas, potencialmente violando seus termos ou criando problemas de compatibilidade.
Maior carga de manutenção: Manter as dependências do fornecedor sincronizadas com suas versões upstream requer um esforço manual significativo e muitas vezes leva a trabalho duplicado entre pacotes.
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 simples e mais fácil de manter reescrever os sistemas de compilação alternativos em CMake usando diretivas file(GLOB)
.
Exemplos: abseil
Escolha binários estáticos ou compartilhados
Ao criar bibliotecas CMake, vcpkg_cmake_configure()
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 aplicar patches em uma compilação, você deve sempre tentar maximizar a capacidade de manutenção futura da porta. Normalmente, isso significa minimizar o número de linhas que precisam ser alteradas para corrigir o problema em questão.
Exemplo: Aplicar patches em uma biblioteca CMake para evitar a criação de variantes indesejadas
Por exemplo, ao aplicar patches numa biblioteca com base em CMake, pode ser o suficiente adicionar EXCLUDE_FROM_ALL
a destinos indesejados e envolver a chamada install(TARGETS ...)
num 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 o seguinte conteúdo:
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 linha install(TARGETS)
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 trecho 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 diretório manual-link
Uma lib é considerada conflitante se fizer qualquer um dos seguintes:
- Definir
main
- Definição de malloc
- Definir símbolos que também são declarados em outras bibliotecas
Libs conflitantes são tipicamente por design e não são considerados um defeito. Como alguns sistemas de compilação se conectam a tudo no diretório lib, eles devem ser movidos para um subdiretório chamado manual-link
.
Versionamento
Siga as convenções comuns para o campo "version"
Ao criar uma nova porta, siga a convenção de controle de versão usada pelo autor do pacote. Ao atualizar a porta, 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 publicar uma versão há algum tempo, não altere o esquema de versionamento da porta para version-date
para obter as alterações mais recentes. Esses compromissos podem incluir alterações que não estão prontas para produção. Em vez disso, solicite ao repositório de origem que publique uma nova versão.
Atualize o campo "port-version"
no arquivo de manifesto de todas as portas modificadas
O VCPKG usa esse campo para determinar se uma determinada porta está desatualizada e deve ser alterada sempre que o comportamento da porta mudar.
Nossa convenção é usar o campo "port-version"
para alterações na porta que não alterem a versão upstream e redefinir o "port-version"
de volta a zero quando uma atualização para a versão upstream for feita.
Por exemplo:
- A versão do pacote Zlib está atualmente
1.2.1
, sem"port-version"
explícito (equivalente a um"port-version"
de0
). - Você descobriu que o arquivo de direitos autorais errado foi implantado e corrigiu isso no portfile.
- Você deve atualizar o campo
"port-version"
no arquivo de manifesto para1
.
Consulte a documentação de controlo de versão para obter mais informações.
Atualize os arquivos de versão em versions/
de quaisquer portas modificadas
O VCPKG usa um conjunto de arquivos de metadados para potencializar seu recurso de controle de versão. Esses arquivos estão localizados nos seguintes locais:
-
${VCPKG_ROOT}/versions/baseline.json
, (este ficheiro é comum a todas as portas) e -
${VCPKG_ROOT}/versions/${first-letter-of-portname}-/${portname}.json
(uma por porta).
Por exemplo, para zlib
os ficheiros relevantes são:
${VCPKG_ROOT}/versions/baseline.json
${VCPKG_ROOT}/versions/z-/zlib.json
Esperamos que cada vez que você atualiza uma porta, você também atualiza seus arquivos de versão.
O método recomendado para atualizar esses arquivos é executar o comando x-add-version
, 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. A razão é que o Git SHA do diretório port é necessário nesses arquivos de versão. Mas não se preocupe, o comando x-add-version
irá avisá-lo se você tiver alterações locais que não foram confirmadas.
Para obter mais informações, consulte o de referência de controle de versão e artigos Registros.
Aplicação de patches
VCPKG é uma solução de embalagem, não os proprietários finais dos componentes que implantamos. Precisamos aplicar patches em alguns casos para melhorar a compatibilidade de componentes com plataformas, ou compatibilidade de componentes entre si.
- Queremos evitar patches que:
- a entidade superior discordaria
- causar vulnerabilidades ou falhas
- somos incapazes de manter atualizações de versão upstream
- são grandes o suficiente para causar complicações de licença com o repositório vcpkg em si próprio
Notificar os responsáveis upstream para patches upstream relevantes
Se um patch puder ser útil a montante, o upstream deve ser notificado do conteúdo do patch. (Patches que aplicam comportamento específico do vcpkg não relacionado ao upstream, como a desvendorização de uma dependência, não exigem notificação.)
Para evitar situações em que o upstream discorde do patch, vamos esperar no mínimo 30 dias para aplicar tais patches.
Ignoraremos este período de espera se tivermos grande confiança de que a mudança está correta. Exemplos de patches de alta confiança incluem, mas não estão limitados a:
- Aceitação do upstream como um patch (por exemplo, retroportação de uma alteração específica de uma solicitação de pull que foi mesclada upstream).
- Adicionando
#include
ausentes. - Correções de código de produto pequenas e óbvias (por exemplo, inicializando uma variável não inicializada).
- Desativando componentes da compilação irrelevantes no vcpkg, como testes ou exemplos.
Prefira opções em vez de aplicar patches
É preferível definir opções em uma chamada para vcpkg_configure_xyz()
em vez de corrigir as configurações diretamente.
Opções comuns que permitem evitar a aplicação de patches:
- [MSBUILD]
<PropertyGroup>
configurações dentro do arquivo de projeto podem ser substituídas através de parâmetros/p:
- [CMAKE] As chamadas para
find_package(XYz)
nos scripts do CMake podem ser desativadas via-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 o parâmetroFORCE
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, 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 upstream aceitou as alterações no patch
- Simplifica o processo de revisão, transferindo o ónus para a etapa anterior
- 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 ponto final estável para evitar conflitos de SHA.
Ao baixar arquivos de patch de uma solicitação pull ou commit do GitHub e do GitLab, o parâmetro ?full_index=1
deve ser anexado ao 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 a aplicação de patches em vez da substituição de valores de VCPKG_<VARIABLE>
Algumas variáveis prefixadas com VCPKG_<VARIABLE>
têm um CMAKE_<VARIABLE>
equivalente.
No entanto, nem todos eles são passados para a compilação do pacote interno (veja a implementação: ferramenta 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 internas do vcpkg
, isto funciona, porque o valor de VCPKG_<LANG>_FLAGS
é encaminhado para a variável CMAKE_LANG_FLAGS
correspondente. Mas, uma cadeia de ferramentas personalizada que não reconhece as variáveis do vcpkg
não as encaminhará.
Por causa disso, é preferível corrigir o buildsystem diretamente ao definir CMAKE_<LANG>_FLAGS
.
Minimizar correções
Ao fazer alterações numa biblioteca, procure 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 desativar um condicional, é melhor adicionar um AND FALSE
ou && 0
à condição do que excluir todas as linhas do condicional. Se uma região grande precisar ser desativada, é mais simples adicionar if(0)
ou #if 0
ao redor da região em vez de excluir todas as linhas do patch.
Não adicione patches se a porta estiver desatualizada e atualizar a porta para uma versão mais recente resolveria o mesmo problema. vcpkg prefere atualizar portas 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 se aplique a versões futuras do código.
Não implementar recursos em patches
O objetivo do patching no vcpkg é permitir a compatibilidade com compiladores, bibliotecas e plataformas. Não se deve implementar novas funcionalidades em detrimento de seguir corretamente o processo de Código Aberto, como submeter um problema ou Pull Request (PR), entre outros.
Não crie testes/docs/exemplos por padrão
Ao enviar uma nova porta, verifique se há opções como BUILD_TESTS
ou WITH_TESTS
ou POCO_ENABLE_SAMPLES
e verifique se os binários adicionais estão desativados. Isso minimiza os tempos de compilação e as dependências para o usuário médio.
Opcionalmente, você pode adicionar um recurso de test
que permite a criação dos testes, no entanto, isso não deve estar na lista de Default-Features
.
Permitir que os usuários existentes da biblioteca alternem para vcpkg
Não adicionar CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS
A menos que o autor da biblioteca já esteja usando, não devemos usar essa funcionalidade CMake porque ela interage mal com modelos C++ e quebra 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.
Ressalva importante:
- Variantes estáticas e compartilhadas muitas vezes devem ser renomeadas para um esquema comum. Isto permite que os consumidores utilizem um nome comum e ignorem a ligação a jusante. Isto é seguro porque só disponibilizamos um de cada vez.
Se uma biblioteca gera ficheiros de integração do CMake (foo-config.cmake
), a renomeação deve ser feita através da modificação direta da compilação do CMake em vez de simplesmente executar file(RENAME)
sobre os ficheiros de saída/LIBs.
Finalmente, os arquivos DLL no Windows nunca devem ser renomeados pós-compilação porque quebra 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 pedidos para adicionar trigêmeos não comunitários no momento. A promoção da comunidade para o status de triplete completo baseia-se principalmente no orçamento para o hardware necessário para testar esses tripletes e será impulsionada por métricas enviadas pelo vcpkg para maximizar a probabilidade de que o que as pessoas realmente usam seja totalmente testado.
Adicionaremos trigêmeos comunitários se:
- Está demonstrado que as pessoas vão realmente usar esse trio comunitário; e,
- não sabemos que tal trio está quebrado.
Por exemplo, não adicionamos um trio em https://github.com/microsoft/vcpkg/pull/29034 porque o autor estava apenas tentando "completar o conjunto" em vez de indicar que eles realmente usariam tal coisa, e não adicionamos linux-dynamic até que a solução patchelf para tornar os resultados relocáveis fosse criada.
Notas de implementação úteis
Portfiles são executados no modo de script
Enquanto portfile.cmake
e CMakeLists.txt
compartilham uma sintaxe comum e construções principais da linguagem CMake (também conhecidas como "Comandos de Script"), os portfiles são executados em "Modo de Script", enquanto os arquivos CMakeLists.txt
são executados em "Modo de Projeto". A diferença mais importante entre estes dois modos é que o "Modo Script" não tem 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 tríptico, mas CMakeLists.txt
não têm (embora frequentemente ocorra uma tradução -- VCPKG_LIBRARY_LINKAGE
versus BUILD_SHARED_LIBS
).
Portfiles e compilações de projeto invocadas por portfiles são executadas em processos diferentes. Conceptualmente:
+----------------------------+ +------------------------------------+
| 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 portfile, as variáveis CMake padrão são boas (CMAKE_HOST_WIN32
).
Para determinar o destino em um portfile, as variáveis triplete vcpkg devem ser usadas (VCPKG_CMAKE_SYSTEM_NAME
).
Consulte a nossa documentação do triplet ,, para uma enumeração completa das configurações possíveis.