Condividi tramite


Guida del manutentore

Questo documento elenca un set di criteri da applicare durante l'aggiunta o l'aggiornamento di una ricetta delle porte. È destinato a svolgere il ruolo di Manuale dei criteri di Debian, Linee guida per i gestori di Homebrew e il cookbook formula di Homebrew.

Obiettivi generali di progettazione del Registro di sistema

Le porte nella baseline corrente devono essere installabili contemporaneamente

Si vuole essere in grado di mostrare agli utenti downstream delle librerie nel Registro di sistema curato che la combinazione di librerie in una determinata baseline pubblicata è stata testata per lavorare insieme in almeno alcune configurazioni. Consentire alle porte di escludersi l'una dall'altra compromette la capacità di testare tali configurazioni, poiché questo fa aumentare il numero di compilazioni necessarie per tali test man mano che 2^number_of_such_cases. Inoltre, l'installazione di dipendenze aggiuntive è sempre considerata "sicura": non esiste alcun modo per una porta o un utente finale di affermare che una dipendenza non è installata nei propri requisiti.

Se si vuole rappresentare una situazione alternativa di questo tipo per gli utenti, valutare la possibilità di descrivere come un utente può creare una porta di sovrapposizione che implementi il modulo alternativo con un commento anziché portfile.cmake provare ad aggiungere porte aggiuntive non compilate nell'integrazione continua del Registro di sistema curato. Ad esempio, vedere glad@0.1.36.

Prima dell'introduzione dei registri, sono state accettate diverse porte non testate come alternative, ad esempio boringssl, che potrebbero semplificare la creazione di porte sovrapposte. Questa operazione non è più accettata perché i registri consentono la pubblicazione di queste porte non con test senza modificare il Registro di sistema curato.

Usare lettere minuscole per le stringhe di cifre esadecimali

Molte delle funzionalità di vcpkg si basano sul confronto di stringhe di cifre esadecimali. Alcuni esempi includono, ad esempio, hash SHA512, ID commit Git e hash degli oggetti albero.

Internamente, vcpkg usa la normalizzazione minuscola per i confronti di tali valori in cui la combinazione di maiuscole e minuscole è irrilevante. Tuttavia, gli strumenti basati sull'infrastruttura di vcpkg potrebbero non fare le stesse considerazioni. Per questo motivo, sono necessarie stringhe esadecimali

per la coerenza negli scenari seguenti:

  • Parametro SHA512 nelle funzioni helper vcpkg.
  • Parametro REF nelle funzioni helper vcpkg, quando il valore è una stringa esadecimale.
  • Oggetto git-tree nei file di database della versione.
  • Oggetto sha512 nel scripts/vcpkg-tools.json file.
  • Altre posizioni in cui la combinazione di maiuscole e minuscole della stringa esadecimale non è importante.

Struttura della richiesta pull

Effettuare richieste pull separate per porta

Quando possibile, separare le modifiche in più richieste pull. Questo li rende notevolmente più facili da esaminare e impedisce problemi con un set di modifiche di mantenere ogni altra modifica.

Evitare modifiche semplici nei file non modificati

Ad esempio, evitare la riformattazione o la ridenominazione delle variabili nei file di porta che altrimenti non hanno alcun motivo di essere modificate per il problema. Tuttavia, se è necessario modificare il file per lo scopo principale della richiesta pull (aggiornamento della libreria), le modifiche ovviamente vantaggiose come la correzione degli errori di digitazioni sono apprezzate!

Confrontare i nomi con altri repository

I nomi dei port devono tentare di essere non ambigui su quale pacchetto viene installato dal port. Idealmente, la ricerca del nome della porta in un motore di ricerca dovrebbe portare rapidamente al progetto corrispondente. Un servizio efficace per controllare molti nomi di pacchetti in più repository simultaneamente è Repology.

I progetti con nomi brevi o denominati dopo parole comuni possono richiedere la disambiguazione, specialmente quando non sono presenti progetti con un'associazione forte alla parola specificata. Ad esempio, una porta con il nome ip non è accettabile perché è probabile che più progetti vengano denominati in modo analogo.

Esempi di buoni ambiguità sono:

  • Nome utente o organizzazione del proprietario del repository: google-cloud-cpp.
  • Il nome di una suite di librerie del progetto fa parte di: boost-dll.

I prefissi e i suffissi comuni usati da C++ e i progetti open source non sono ambiguità validi, alcuni esempi includono, ma non sono limitati a:

  • cpp,
  • free,
  • lib,
  • open,
  • numeri

Ad esempio, quando si confrontano i seguenti nomi di porta: ip-cpp, libip e ip5 e si rimuovono i disambiguatori non validi, tutti vengono ridotti alla stessa radice (ip) e pertanto si considera abbiano lo stesso nome.

Viene fatta un'eccezione a questa linea guida per i nomi fortemente associati a un singolo progetto. Ad esempio: libpnge opensslzlib.

Utilizza le richieste pull di bozza su GitHub

Le richieste pull di GitHub Draft sono un ottimo modo per ottenere feedback ci o umano sul lavoro che non è ancora pronto per l'unione. La maggior parte delle nuove richieste pull devono essere aperte come bozze e convertite in richieste pull normali dopo il superamento dell'integrazione continua.

Per ulteriori informazioni sulle richieste pull di bozza di GitHub, vedere Introduzione alle richieste pull di bozza.

File di porta

Evitare funzioni di supporto deprecate

Al momento, gli helper seguenti sono obsoleti:

Alcune delle funzioni helper sostitutive si trovano nelle "porte degli strumenti software" per permettere agli utenti di fissare il comportamento a versioni specifiche, permettendo il blocco del comportamento degli helper in una versione particolare. Le porte degli strumenti devono essere aggiunte alla porta, "dependencies"come indicato di seguito:

{
  "name": "vcpkg-cmake",
  "host": true
},
{
  "name": "vcpkg-cmake-config",
  "host": true
}

Evita commenti eccessivi nei portfile

Idealmente, i file di porta devono essere brevi, semplici e dichiarativi il più possibile. Rimuovere i commenti della create piastra caldaia introdotti dal comando prima di inviare una richiesta pull.

Le porte non devono essere dipendenti dal percorso

Le porte non devono cambiare comportamento in base a quali porte sono già installate in un modo che alteri i contenuti che quella porta installa. Si consideri ad esempio di avere una situazione simile alla seguente:

> vcpkg install a
> vcpkg install b
> vcpkg remove a

e

> vcpkg install b

I file installati da b devono essere gli stessi, indipendentemente dall'influenza dell'installazione precedente di a. Ciò significa che le porte non devono tentare di rilevare se un elemento viene fornito nell'albero installato da un'altra porta prima di eseguire alcune azioni. Una causa specifica e comune di questo comportamento "dipendente dal percorso" è descritta di seguito in "Quando si definiscono le funzionalità, controllare in modo esplicito le dipendenze".

Regola di attribuzione delle porte univoca

Nell'intero sistema vcpkg, nessuna delle due porte che un utente deve usare contemporaneamente potrebbe fornire lo stesso file. Se una porta tenta di installare un file già fornito da un altro file, l'installazione avrà esito negativo. Se una porta vuole utilizzare un nome estremamente comune per un'intestazione, ad esempio, dovrebbe inserire tali intestazioni in una sottodirectory anziché in include.

Questa proprietà viene controllata regolarmente dalle esecuzioni di integrazione continua che tentano di installare tutte le porte nel Registro di sistema, che avranno esito negativo FILE_CONFLICTS se due porte forniscono lo stesso file.

Aggiungere esportazioni CMake in un namespace non ufficiale

Un core design ideale di vcpkg consiste nel non creare "lock-in" per gli utenti. Nel sistema di compilazione non dovrebbe esserci alcuna differenza tra fare affidamento su una libreria del sistema e fare affidamento su una libreria da vcpkg. A tale scopo, si evita di aggiungere esportazioni o destinazioni CMake alle librerie esistenti con "il nome ovvio", per consentire agli upstream di aggiungere esportazioni CMake ufficiali senza conflitti con vcpkg.

A tale scopo, tutte le configurazioni CMake esportate dalla porta, che non si trovano nella libreria upstream, devono avere unofficial- come prefisso. Eventuali destinazioni aggiuntive devono trovarsi nello spazio dei nomi unofficial::<port>::

Ciò significa che l'utente dovrebbe visualizzare:

  • find_package(unofficial-<port> CONFIG) come modo per ottenere il pacchetto specifico per vcpkg
  • unofficial::<port>::<target> come destinazione esportata da tale porta.

Esempi:

  • brotli crea il unofficial-brotli pacchetto, producendo la destinazione unofficial::brotli::brotli.

Ogni porta deve fornire un file denominato copyright nella cartella ${CURRENT_PACKAGES_DIR}/share/${PORT}. Se il contenuto della licenza di un pacchetto è disponibile all'interno dei file di origine, questo file deve essere creato da una chiamata a vcpkg_install_copyright(). vcpkg_install_copyright aggrega anche più file di copyright, se necessario.

vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE")

Un metodo precedente per creare manualmente questo file è con il comando incorporato file di CMake. Questo è sconsigliato a favore di vcpkg_install_copyright nelle nuove versioni, ma è ancora consentito.

file(INSTALL "${SOURCE_PATH}/LICENSE" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright)

Se il contenuto della licenza nei file di origine upstream non è in formato testo (ad esempio un file PDF), copyright deve contenere una spiegazione su come un utente può trovare i requisiti di licenza. Se possibile, deve includere anche un collegamento ai file di origine originali che indicano questo, in modo che gli utenti possano verificare se è aggiornato.

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
]])

Vincoli di versione nelle porte

I vincoli di versione all'interno dei porti dovrebbero generalmente essere evitati, in quanto possono ostacolare l'evoluzione indipendente dei progetti. L'aggiunta di tali vincoli è consentita solo quando esiste una giustificazione ben documentata, ad esempio incompatibilità comprovata con versioni precedenti specifiche. Questi vincoli non devono essere utilizzati solo per mantenere la parità con i progetti indipendenti.

Le variabili in MAYBE_UNUSED_VARIABLES devono essere applicate ad almeno una configurazione

Quando si aggiunge una nuova variabile a MAYBE_UNUSED_VARIABLES per disattivare un avviso durante il passaggio di configurazione di CMake, è necessario aggiungere un commento che spiega il caso quando si applica la nuova variabile. Se una variabile non si applica in alcuna configurazione, è molto probabile che esista un bug sottostante (ad esempio, un nome di variabile con errori di ortografia) e che l'aggiunta non abbia alcun effetto effettivo sulla compilazione.

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
)

Funzionalità

Non usare le funzionalità per implementare alternative

Le funzionalità devono essere considerate come funzionalità aggiuntive. Se port[featureA] installa e port[featureB] installa, allora port[featureA,featureB] deve essere installato. Inoltre, se una seconda porta dipende da [featureA] e una terza porta dipende da [featureB], l'installazione della seconda e della terza porta deve avere le relative dipendenze soddisfatte.

Le librerie in questa situazione devono scegliere una delle opzioni disponibili espresse in vcpkg, mentre gli utenti che desiderano una configurazione diversa devono utilizzare porte overlay in questo momento.

Gli esempi esistenti non verranno accettati oggi per garantire la compatibilità con le versioni precedenti:

  • libgit2, libzip, open62541 tutte hanno funzionalità per la selezione di un back-end TLS o di crittografia. curl dispone di diverse opzioni back-end di crittografia, ma consente di selezionarle in fase di esecuzione, ovvero la tenet precedente viene mantenuta.
  • darknet dispone di opencv2opencv3 funzionalità per controllare quale versione di OpenCV usare per le relative dipendenze.

Una funzionalità può coinvolgere la funzionalità di anteprima o beta

Nonostante quanto sopra riportato, se è presente un ramo di anteprima o simile in cui la funzionalità di anteprima ha una probabilità elevata di non interrompere la funzionalità non di anteprima (ad esempio, nessuna rimozione di API), una funzionalità è accettabile per modellare questa impostazione.

Esempi:

  • Gli SDK di Azure (nel formato azure-Xxx) hanno una public-preview funzionalità.
  • imgui dispone di una experimental-docking funzionalità che attiva il ramo di ancoraggio di anteprima e utilizza un commit di merge associato a ciascuna delle loro versioni numerate pubbliche.

Le funzionalità predefinite non devono aggiungere API

Le funzionalità predefinite sono destinate a garantire l'installazione di una build ragionevolmente funzionale di una libreria per i clienti che non sanno di utilizzarla. Se non sanno che usano una libreria, non possono sapere di elencare le funzionalità. Ad esempio, libarchive espone funzionalità che consentono algoritmi di compressione a un'interfaccia generica esistente. Se compilata senza tali funzionalità, la libreria potrebbe non avere utilità.

È necessario valutare attentamente se una funzionalità deve essere attivata per impostazione predefinita, perché la disabilitazione delle funzionalità predefinite è complessa.

La disabilitazione di una funzionalità predefinita come consumer "transitivo" richiede:

  • Tutti i clienti disabilitano in modo esplicito le funzionalità predefinite tramite "default-features": false o incluso [core] nell'elenco delle funzionalità nella riga di comando.
  • Definire la dipendenza transitiva nella riga di comando vcpkg install, o come dipendenza diretta nel manifesto di livello superiore.

Nel Registro di sistema curato di vcpkg, se la funzionalità aggiunge API aggiuntive, eseguibili o altri file binari, deve essere disattivata per impostazione predefinita. In caso di dubbi, non contrassegnare una funzionalità come predefinita.

Non usare le funzionalità per controllare le alternative nelle interfacce pubblicate

Se un consumatore di una porta dipende solo dalla funzionalità principale di tale porta, con alta probabilità non devono essere interrotti attivando la funzione. Ciò è ancora più importante quando l'alternativa non è controllata direttamente dal consumer, ma da impostazioni del compilatore come /std:c++17 / -std=c++17.

Gli esempi esistenti non verranno accettati oggi per garantire la compatibilità con le versioni precedenti:

  • redis-plus-plus[cxx17] controlla un polyfill ma non inserisce l'impostazione nell'albero installato.
  • ace[wchar] modifica tutte le API in modo da accettare const wchar_t* anziché const char*.

Una funzionalità può sostituire i polifill con gli alias forniti che la sostituzione viene inserita nell'albero installato

Nonostante quanto sopra riportato, le porte possono rimuovere i polifill con una funzionalità, purché:

  1. L'attivazione della funzionalità modifica i polifill in alias dell'entità polyfilled
  2. Lo stato del polyfill viene inserito nelle intestazioni installate, in modo che gli errori di runtime "impossibile" di ABI non corrispondenti siano improbabili
  3. È possibile che un consumer della porta scriva codice che funziona in entrambe le modalità, ad esempio usando un typedef che è polifillato o meno

Esempio:

  • abseil[cxx17] sostituisce absl::string_view con un'alternativa o std::string_view; la patch implementa il requisito di cottura.

Se è fondamentale esporre le alternative sottostanti, è consigliabile fornire messaggi in fase di compilazione per indicare all'utente come copiare la porta in una sovrimpressione privata:

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")

Tecniche di costruzione

Non usare le dipendenze fornitore

Non usare copie integrate delle librerie. Tutte le dipendenze devono essere suddivise e impacchettate separatamente in modo che possano essere aggiornate e mantenute.

Le dipendenze fornitore presentano diverse sfide che sono in conflitto con gli obiettivi di vcpkg per fornire un sistema di gestione dei pacchetti affidabile, coerente e gestibile:

Difficoltà negli aggiornamenti: le copie incorporate delle librerie rendono più difficile tenere traccia e applicare gli aggiornamenti, incluse le patch di sicurezza, dai progetti upstream. Ciò comporta potenziali rischi per la sicurezza e dipendenze obsolete nell'ecosistema.

Conflitti di simboli: le dipendenze incorporate possono causare conflitti di simboli quando più pacchetti includono versioni diverse della stessa libreria.

Ad esempio: se il pacchetto A fornisce la libreria X (versione 1) e il pacchetto B fornisce la libreria X (versione 2), un'applicazione che collega entrambi i pacchetti potrebbe riscontrare errori di runtime o comportamenti non definiti a causa di simboli in conflitto.

Con la creazione di pacchetti di dipendenze separatamente, vcpkg garantisce l'uso di una singola versione di una libreria in tutti i pacchetti, eliminando tali conflitti.

Conformità delle licenze: le dipendenze fornite da terze parti possono nascondere le licenze delle librerie incorporate, potenzialmente violando i termini o creando problemi di compatibilità.

Aumento del carico di manutenzione: mantenere sincronizzate le dipendenze fornitore con le versioni upstream richiede un impegno manuale significativo e spesso comporta un lavoro duplicato tra pacchetti.

Preferire l'uso di CMake

Quando sono disponibili più sistemi di compilazione, preferire l'uso di CMake. Inoltre, quando appropriato, può essere più semplice e facile da mantenere riscrivere i sistemi di build alternativi in CMake usando direttive file(GLOB).

Esempi: abseil

Scegliere file binari statici o condivisi

Quando si compilano librerie CMake, vcpkg_cmake_configure() passerà il valore corretto per BUILD_SHARED_LIBS in base alla variante richiesta dall'utente.

È possibile calcolare parametri di configurazione alternativi 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 una libreria non offre opzioni di configurazione per selezionare la variante di compilazione, è necessario applicare patch alla compilazione. Quando si esegue l'applicazione di patch a una compilazione, è consigliabile tentare sempre di massimizzare la manutenibilità futura della porta. In genere questo significa ridurre al minimo il numero di righe che devono essere toccate per risolvere il problema.

Esempio: Applicazione di patch a una libreria CMake per evitare la compilazione di varianti indesiderate

Ad esempio, quando si applica una patch a una libreria basata su CMake, può essere sufficiente aggiungere EXCLUDE_FROM_ALL ai target indesiderati e racchiudere la chiamata install(TARGETS ...) in un if(BUILD_SHARED_LIBS). Questo sarà più breve del wrapping o dell'eliminazione di ogni riga che menziona la variante indesiderata.

Per un progetto CMakeLists.txt con il contenuto seguente:

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)

È necessario applicare patch solo alla install(TARGETS) riga.

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)

Quando si definiscono le funzionalità, controllare in modo esplicito le dipendenze

Quando si definisce una funzionalità che acquisisce una dipendenza facoltativa, assicurarsi che la dipendenza non venga usata accidentalmente quando la funzionalità non è abilitata in modo esplicito.

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}
)

Il frammento di codice seguente che usa 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 nel frammento è sensibile alle maiuscole e minuscole. Per ulteriori informazioni, vedere la documentazione CMAKE_DISABLE_FIND_PACKAGE_<PackageName> e CMAKE_REQUIRE_FIND_PACKAGE_<PackageName>.

Una libreria viene considerata in conflitto se esegue una delle operazioni seguenti:

  • Definire main
  • Definisci malloc
  • Definire i simboli dichiarati anche in altre librerie

Le librerie in conflitto sono in genere per progettazione e non sono considerate difetti. Poiché alcuni sistemi di compilazione si collegano a tutti gli elementi nella directory lib, questi devono essere spostati in una sottodirectory denominata manual-link.

Controllo delle versioni

Seguire le convenzioni comuni per il "version" campo

Quando si crea una nuova porta, seguire la convenzione di controllo delle versioni usata dall'autore del pacchetto. Quando si aggiorna la porta, continuare a usare la stessa convenzione, a meno che upstream non dica il contrario. Per una spiegazione completa delle convenzioni, vedere la documentazione sul controllo delle versioni.

Se upstream non ha pubblicato una versione da un po' di tempo, non modificare lo schema di versionamento della porta per ottenere le modifiche più recenti. Questi commit possono includere modifiche non pronte per l'ambiente di produzione. Chiedere invece al repository upstream di pubblicare una nuova versione.

Aggiornare il "port-version" campo nel file manifesto di tutte le porte modificate

vcpkg usa questo campo per determinare se una determinata porta non è aggiornata e deve essere modificata ogni volta che cambia il comportamento della porta.

La convenzione consiste nell'usare il "port-version" campo per le modifiche alla porta che non modificano la versione upstream e per reimpostare il "port-version" valore su zero quando viene eseguito un aggiornamento alla versione upstream.

Ad esempio:

  • La versione del pacchetto di Zlib è attualmente 1.2.1, senza alcun esplicito "port-version" (equivalente a un "port-version" di 0).
  • Hai scoperto che il file di copyright errato è stato distribuito e l'hai corretto nel portfile.
  • È necessario aggiornare il "port-version" campo nel file manifesto in 1.

Per altre informazioni, vedere la documentazione sul controllo delle versioni.

Aggiornare i file di versione in versions/ di tutte le porte modificate

vcpkg usa un set di file di metadati per potenziare la funzionalità di controllo delle versioni. Questi file si trovano nei percorsi seguenti:

  • ${VCPKG_ROOT}/versions/baseline.json, (questo file è comune a tutte le porte) e
  • ${VCPKG_ROOT}/versions/${first-letter-of-portname}-/${portname}.json (uno per porta).

Ad esempio, per zlib i file pertinenti sono:

  • ${VCPKG_ROOT}/versions/baseline.json
  • ${VCPKG_ROOT}/versions/z-/zlib.json

Ci aspettiamo che ogni volta che si aggiorna una porta, si aggiornano anche i file di versione.

Il metodo consigliato per aggiornare questi file consiste nell'eseguire il x-add-version comando, ad esempio:

vcpkg x-add-version zlib

Se si aggiornano più porte contemporaneamente, è possibile eseguire:

vcpkg x-add-version --all

per aggiornare i file per tutte le porte modificate contemporaneamente.

Per ulteriori informazioni, consultare gli articoli di riferimento sul controllo delle versioni e registri .

Applicazione di patch

vcpkg è una soluzione di creazione di pacchetti, non i proprietari finali dei componenti distribuiti. In alcuni casi è necessario applicare patch per migliorare la compatibilità dei componenti con le piattaforme o la compatibilità dei componenti tra loro.

  • Si vogliono evitare patch che:
    • upstream non sarebbe d'accordo con
    • causare instabilità o crash
    • non è possibile gestire gli aggiornamenti delle versioni upstream
    • sono sufficientemente grandi da causare l'entanglement delle licenze con il repository vcpkg stesso

Inviare una notifica ai responsabili delle patch rilevanti a monte

Se una patch potrebbe essere utile da upstream, upstream deve ricevere una notifica del contenuto della patch. Le patch che applicano comportamenti specifici di vcpkg non correlati a upstream, come la de-vendorizzazione di una dipendenza, non richiedono una notifica.

Per evitare situazioni in cui upstream non è d'accordo con la patch, attenderemo almeno 30 giorni per applicare tali patch.

Questo periodo di attesa verrà ignorato se si ha una maggiore probabilità che la modifica sia corretta. Esempi di patch ad alta attendibilità includono, ad esempio:

  • L'accettazione di upstream come patch (ad esempio, il backporting di una modifica specifica da una richiesta pull che upstream ha unito).
  • Aggiunta di #include mancanti.
  • Correzioni di codice prodotto piccole e ovvie (ad esempio, inizializzazione di una variabile non inizializzata).
  • Disabilitazione di componenti irrilevanti in-vcpkg della compilazione, ad esempio test o esempi.

Preferire le opzioni rispetto all'applicazione di patch

È preferibile impostare le opzioni in una chiamata a vcpkg_configure_xyz() piuttosto che modificare direttamente le impostazioni.

Opzioni comuni che consentono di evitare l'applicazione di patch:

  • [MSBUILD] <PropertyGroup> è possibile eseguire l'override delle impostazioni all'interno del file di progetto tramite /p: parametri
  • [CMAKE] Le chiamate a find_package(XYz) negli script CMake possono essere disabilitate tramite -DCMAKE_DISABLE_FIND_PACKAGE_XYz=ON
  • [CMAKE] Le variabili della cache (dichiarate come set(VAR "value" CACHE STRING "Documentation") o option(VAR "Documentation" "Default Value")) possono essere sottoposte a override semplicemente passandole nella riga di comando come -DVAR:STRING=Foo. Un'eccezione rilevante è se il FORCE parametro viene passato a set(). Per altre informazioni, vedere la documentazione di CMake set

Preferisce scaricare le patch approvate per controllarle nella porta

Se un file patch approvato o unito può essere ottenuto da upstream, le porte devono provare a scaricarle e applicarle anziché inserirle come parte dei file di porta. Questo processo è preferibile perché:

  • Conferma che upstream ha accettato le modifiche della patch
  • Semplifica il processo di revisione spostando l'upstream onus
  • Riduce le dimensioni del repository vcpkg per gli utenti che non usano la patch
  • Evitare conflitti di licenza con il repository vcpkg

Le patch devono essere scaricate da un endpoint stabile per evitare conflitti SHA. Quando si scaricano i file patch da una richiesta pull o si esegue il commit da GitHub e GitLab, il ?full_index=1 parametro deve essere aggiunto all'URL di download.

Esempi:

  • 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

Preferire l'applicazione di patch rispetto all'override dei VCPKG_<VARIABLE> valori

Alcune variabili precedute da VCPKG_<VARIABLE> hanno un equivalente CMAKE_<VARIABLE>. Tuttavia, non tutti vengono passati alla compilazione interna del pacchetto (vedere implementazione: Toolchain di Windows).

Si consideri l'esempio seguente:

set(VCPKG_C_FLAGS "-O2 ${VCPKG_C_FLAGS}")
set(VCPKG_CXX_FLAGS "-O2 ${VCPKG_CXX_FLAGS}")

L'uso delle vcpkg toolchain predefinite funziona perché il valore di VCPKG_<LANG>_FLAGS viene inoltrato alla variabile CMAKE_LANG_FLAGS appropriata. Tuttavia, una toolchain personalizzata che non riconosce le variabili di vcpkg non le inoltra.

Per questo motivo, è preferibile applicare patch direttamente al sistema di compilazione quando si imposta CMAKE_<LANG>_FLAGS.

Ridurre al minimo le patch

Quando si apportano modifiche a una libreria, cercare di ridurre al minimo il diff finale. Ciò significa che non è consigliabile riformattare il codice sorgente upstream quando si apportano modifiche che interessano un'area. Quando si disabilita un'istruzione condizionale, è preferibile aggiungere un AND FALSE o un && 0 alla condizione piuttosto che eliminare ogni riga del condizionale. Se è necessario disabilitare un'area di grandi dimensioni, è più breve aggiungere un if(0) o un #if 0 attorno all'area anziché eliminare ogni riga nella patch.

Non aggiungere patch se la porta è obsoleta e l'aggiornamento della porta a una versione rilasciata più recente risolverebbe lo stesso problema. vcpkg preferisce aggiornare le porte rispetto all'applicazione di patch alle versioni obsolete.

Ciò consente di mantenere le dimensioni del repository vcpkg inattivo, nonché di migliorare la probabilità che la patch venga applicata alle versioni di codice future.

Non implementare funzionalità nelle patch

Lo scopo dell'applicazione di patch in vcpkg è abilitare la compatibilità con compilatori, librerie e piattaforme. Non serve ad implementare nuove funzionalità anziché seguire le corrette procedure di Open Source (invio di un Issue/PR/ecc.).

Non creare test/documentazione/esempi per impostazione predefinita

Quando si invia una nuova porta, verificare la presenza di opzioni come BUILD_TESTS o o WITH_TESTSPOCO_ENABLE_SAMPLES e assicurarsi che i file binari aggiuntivi siano disabilitati. Ciò riduce al minimo i tempi di compilazione e le dipendenze per l'utente medio.

Facoltativamente, è possibile aggiungere una test funzionalità che consente di compilare i test, ma non deve essere presente nell'elenco Default-Features .

Consentire agli utenti esistenti della libreria di passare a vcpkg

Non aggiungere CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS

A meno che l'autore della libreria non lo usi già, non è consigliabile usare questa funzionalità di CMake perché interagisce male con i modelli C++ e interrompe determinate funzionalità del compilatore. Le librerie che non forniscono un file con estensione def e non usano dichiarazioni __declspec() semplicemente non supportano le compilazioni condivise per Windows e devono essere contrassegnate come tali:

if(VCPKG_TARGET_IS_WINDOWS)
    vcpkg_check_linkage(ONLY_STATIC_LIBRARY)
endif()

Non rinominare i file binari all'esterno dei nomi forniti da upstream

Ciò significa che se la libreria upstream ha nomi diversi nella versione e nel debug (libx e libxd), la libreria di debug non deve essere rinominata in libx. Viceversa, se la libreria upstream ha lo stesso nome nel rilascio e nel debug, non è consigliabile introdurre un nuovo nome.

Avvertenza importante:

  • Le varianti statiche e condivise spesso devono essere rinominate in uno schema comune. In questo modo i consumer possono usare un nome comune ed essere ignoranti del collegamento downstream. Questo è sicuro perché ne facciamo una sola alla volta disponibile.

Se una libreria genera file di integrazione CMake (foo-config.cmake), la ridenominazione deve essere effettuata applicando patch direttamente alla build di CMake, invece di limitarsi a eseguire file(RENAME) semplicemente sugli archivi/LIB di output.

Infine, i file DLL in Windows non devono mai essere rinominati dopo la compilazione perché interrompe i DATABASE generati.

Manifesti

È necessario che il file manifesto sia formattato. Usare il comando seguente per formattare tutti i file manifesto:

> vcpkg format-manifest --all

Trigemini

Attualmente non si accettano richieste di aggiunta di triplette non della community. L'innalzamento di livello dalla community allo stato di triplette completo si basa principalmente sul budget per l'hardware necessario a testare tali componenti tripli e sarà guidato dalle metriche inviate da vcpkg per massimizzare la probabilità che ciò che le persone effettivamente usano sia completamente testato.

Si aggiungeranno triplette della community se:

  • Si è dimostrato che le persone utilizzeranno effettivamente quel gruppo della comunità; e
  • non sappiamo che una tripletta sia rotta.

Ad esempio, non è stato aggiunto un terzetto in https://github.com/microsoft/vcpkg/pull/29034 perché l'autore stava solo cercando di "completare il set" anziché indicare che avrebbero effettivamente utilizzato un elemento del genere e non è stato aggiunto linux-dynamic fino a quando non è stata creata la soluzione patchelf per rendere i risultati rilocabili.

Note utili sull'implementazione

I file porta vengono eseguiti in modalità script

Mentre portfile.cmake e CMakeLists.txt condividono una sintassi comune e i costrutti fondamentali del linguaggio CMake (aka "Comandi di scripting"), i portfile (file di porta) vengono eseguiti in "Modalità script", mentre i file CMakeLists.txt vengono eseguiti in "Modalità progetto". La differenza più importante tra queste due modalità è che "Modalità script" non ha i concetti di "Toolchain", "Language" e "Target". Eventuali comportamenti, inclusi i comandi di scripting, che dipendono da questi costrutti (ad esempio CMAKE_CXX_COMPILER, CMAKE_EXECUTABLE_SUFFIX, ) CMAKE_SYSTEM_NAMEnon saranno corretti.

I Portfile hanno accesso diretto alle variabili impostate nel file triplet, ma CMakeLists.txt non ce l'hanno (anche se spesso avviene una traduzione -- VCPKG_LIBRARY_LINKAGE rispetto a BUILD_SHARED_LIBS).

I file di porta e le compilazioni di Project richiamati dai file di porta vengono eseguiti in processi diversi. Concettualmente:

+----------------------------+       +------------------------------------+
| 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)     |
+----------------------------+       +------------------------------------+

Per determinare l'host in un file di porta, le variabili CMake standard sono appropriate (CMAKE_HOST_WIN32).

Per determinare la destinazione in un file di porta, è necessario usare le variabili triplet vcpkg (VCPKG_CMAKE_SYSTEM_NAME).

Per un'enumerazione completa delle possibili impostazioni, vedere anche la documentazione del triplet.