Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
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
nelscripts/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: libpng
e openssl
zlib
.
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:
-
vcpkg_extract_source_archive_ex()
dovrebbe essere sostituito con l'overload appropriato divcpkg_extract_source_archive()
(utilizzandoARCHIVE
) - L'overload deprecato di
vcpkg_extract_source_archive()
senzaARCHIVE
deve essere sostituito dall'overload supportato conARCHIVE
. -
vcpkg_apply_patches()
deve essere sostituito dagliPATCHES
argomenti degli helper "extract" (ad esempiovcpkg_from_github()
) -
vcpkg_build_msbuild()
deve essere sostituito davcpkg_install_msbuild()
-
vcpkg_copy_tool_dependencies()
deve essere sostituito davcpkg_copy_tools()
-
vcpkg_configure_cmake
deve essere sostituito davcpkg_cmake_configure()
dopo la rimozionePREFER_NINJA
-
vcpkg_build_cmake
deve essere sostituito davcpkg_cmake_build()
-
vcpkg_install_cmake
deve essere sostituito davcpkg_cmake_install()
-
vcpkg_fixup_cmake_targets
deve essere sostituito davcpkg_cmake_config_fixup
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 ilunofficial-brotli
pacchetto, producendo la destinazioneunofficial::brotli::brotli
.
Installare il file di copyright
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 diopencv2
opencv3
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 unapublic-preview
funzionalità. -
imgui
dispone di unaexperimental-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 accettareconst 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é:
- L'attivazione della funzionalità modifica i polifill in alias dell'entità polyfilled
- Lo stato del polyfill viene inserito nelle intestazioni installate, in modo che gli errori di runtime "impossibile" di ABI non corrispondenti siano improbabili
- È 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]
sostituisceabsl::string_view
con un'alternativa ostd::string_view
; la patch implementa il requisito di cottura.
Soluzioni consigliate
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>
.
Collocare librerie in conflitto in una cartella manual-link
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"
di0
). - 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 in1
.
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")
ooption(VAR "Documentation" "Default Value")
) possono essere sottoposte a override semplicemente passandole nella riga di comando come-DVAR:STRING=Foo
. Un'eccezione rilevante è se ilFORCE
parametro viene passato aset()
. Per altre informazioni, vedere la documentazione di CMakeset
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_TESTS
POCO_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_NAME
non 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.