Versione minima
Ecco la prima linea di ogni CMakeLists.txt
, che è il nome richiesto del file che CMake cerca:
cmake_minimum_required(VERSION 3.1)
Citiamo un po’ di sintassi di CMake. Il nome del comandocmake_minimum_required
è insensibile alle maiuscole, quindi la pratica comune è quella di usare le minuscole. 1 Il VERSION
è una parola chiave speciale per questa funzione. E il valore della versione segue la parola chiave. Come ovunque in questo libro, basta cliccare sul nome del comando per vedere la documentazione ufficiale, e usare il menu a tendina per cambiare la documentazione tra le versioni di CMake.
Questa linea è speciale! 2 La versione di CMake detterà anche le politiche, che definiscono i cambiamenti di comportamento. Quindi, se imposti minimum_required
a VERSION2.8
, otterrai il comportamento di collegamento sbagliato su macOS, per esempio, anche nelle versioni più recenti di CMake. Se lo impostate a 3.3 o meno, otterrete il comportamento sbagliato dei simboli nascosti, ecc. Una lista di policy e versioni è disponibile apolicies.
A partire da CMake 3.12, questo supporta un range, come VERSION 3.1...3.15
; questo significa che supporta fino alla 3.1 ma l’ha anche testato con le impostazioni newpolicy fino alla 3.15. Questo è molto più carino per gli utenti che hanno bisogno delle impostazioni migliori, e a causa di un trucco nella sintassi, è retrocompatibile con le vecchie versioni di CMake (anche se in realtà l’esecuzione di CMake 3.1-3.11 imposterà solo la versione 3.1 delle policy in questo esempio, poiché quelle versioni non trattano questo in modo particolare). Le nuove versioni delle policy tendono ad essere più importanti per gli utenti macOS e Windows, che di solito hanno anche una versione molto recente di CMake.
Questo è ciò che i nuovi progetti dovrebbero fare:
cmake_minimum_required(VERSION 3.7...3.20)if(${CMAKE_VERSION} VERSION_LESS 3.12) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})endif()
Se la versione di CMake è inferiore alla 3.12, il blocco if sarà vero, e la policy sarà impostata alla versione corrente di CMake. Se CMake è 3.12 o superiore, il blocco if sarà falso, ma la nuova sintassi in cmake_minimum_required
sarà rispettata e questo continuerà a funzionare correttamente!
AVVERTENZA: la modalità server CMake di MSVC originariamente aveva un problema nella lettura di questo formato, quindi se hai bisogno di supportare builds Windows senza linea di comando per vecchie versioni di MSVC, vorrai invece fare così:
cmake_minimum_required(VERSION 3.7)if(${CMAKE_VERSION} VERSION_LESS 3.20) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})else() cmake_policy(VERSION 3.20)endif()
Se hai davvero bisogno di impostare un valore basso qui, puoi usarecmake_policy
per aumentare condizionatamente il livello di policy o impostare una policy specifica. Per favore fai almeno questo per i tuoi utenti macOS!
Impostare un progetto
Ora, ogni file CMake di primo livello avrà la prossima linea:
project(MyProject VERSION 1.0 DESCRIPTION "Very nice project" LANGUAGES CXX)
Ora vediamo ancora più sintassi. Le stringhe sono quotate, gli spazi bianchi non hanno importanza, e il nome del progetto è il primo argomento (posizionale). Tutti gli argomenti delle parole chiave qui sono opzionali. La versione imposta un mucchio di variabili, comeMyProject_VERSION
e PROJECT_VERSION
. Le lingue sono C
, CXX
,Fortran
, ASM
, CUDA
(CMake 3.8+), CSharp
(3.8+), e SWIFT
(CMake3.15+ experimental). C CXX
è il valore predefinito. In CMake 3.9, è stato aggiunto DESCRIPTION
per impostare anche una descrizione del progetto. La documentazione perproject
può essere utile.
Puoi aggiungere commenti con il carattere #
. CMake ha anche una sintassi in linea per i commenti, ma è usata raramente.
Non c’è niente di speciale nel nome del progetto. Nessun target viene aggiunto a questo punto.
Fare un eseguibile
Anche se le librerie sono molto più interessanti, e passeremo la maggior parte del nostro tempo con loro, iniziamo con un semplice eseguibile.
add_executable(one two.cpp three.h)
Ci sono diverse cose da spacchettare qui. one
è sia il nome del file eseguibile generato, sia il nome del target CMake creato (sentirete presto molto di più sui target, lo prometto). L’elenco dei file sorgente viene dopo, e puoi elencare tutti quelli che vuoi. CMake è intelligente, e compilerà solo le estensioni dei file sorgente. Gli header saranno, per la maggior parte degli intenti e degli scopi, ignorati; l’unica ragione per elencarli è per farli apparire negli IDE. I target appaiono come cartelle in molti IDE. Maggiori informazioni sul sistema di compilazione generale e sui target sono disponibili su buildsystem.
Fare una libreria
Fare una libreria si fa con add_library
, ed è altrettanto semplice:
add_library(one STATIC two.cpp three.h)
Puoi scegliere un tipo di libreria, STATIC, SHARED o MODULE. Se lasciate questa scelta disattivata, il valore di BUILD_SHARED_LIBS
sarà usato per scegliere tra STATIC e SHARED.
Come vedrete nelle sezioni seguenti, spesso avrete bisogno di fare un target fittizio, cioè uno in cui nulla deve essere compilato, per esempio, per una libreria solo header. Questa è chiamata una libreria INTERFACE, ed è un’altra scelta; l’unica differenza è che non può essere seguita da nomi di file.
Puoi anche fare una libreria ALIAS
con una libreria esistente, che ti dà semplicemente un nuovo nome per un target. L’unico vantaggio è che puoi creare librerie con ::
nel nome (che vedrai più avanti). 3
I target sono tuoi amici
Ora che abbiamo specificato un target, come possiamo aggiungere informazioni su di esso? Per esempio, forse ha bisogno di una directory di inclusione:
target_include_directories(one PUBLIC include)
target_include_directories
aggiunge una directory di inclusione a un obiettivo. PUBLIC
non significa molto per un eseguibile; per una libreria fa sapere a CMake che ogni target che si collega a questo target deve avere anche bisogno di quella include directory. Altre opzioni sono PRIVATE
(influenza solo il target corrente, non le dipendenze), e INTERFACE
(necessario solo per le dipendenze).
Possiamo quindi concatenare i target:
add_library(another STATIC another.cpp another.h)target_link_libraries(another PUBLIC one)
target_link_libraries
è probabilmente il comando più utile e confuso in CMake. Prende un target (another
) e aggiunge una dipendenza se viene dato un target. Se non esiste un target con quel nome (one
), allora aggiunge un link ad una libreria chiamata one
sul tuo percorso (da cui il nome del comando). Oppure puoi dargli un percorso completo di una libreria. O un flag del linker. Solo per aggiungere un ultimo po’ di confusione, CMake classico ti permetteva di saltare la selezione delle parole chiave PUBLIC
, ecc. Se questo è stato fatto su un target, otterrai un errore se provi a mescolare gli stili più in basso nella catena.
Concentrati sull’uso di target ovunque, e di parole chiave ovunque, e andrai bene.
I target possono avere directory include, librerie collegate (o target collegati), opzioni di compilazione, definizioni di compilazione, caratteristiche di compilazione (vedi il capitolo C++11), e altro. Come vedrete nei due capitoli sui progetti inclusi, potete spesso ottenere target (e fare sempre target) per rappresentare tutte le librerie che usate. Anche cose che non sono vere librerie, come OpenMP, possono essere rappresentate con dei target. Questo è il motivo per cui Modern CMake è grande!
Tuffati
Vedi se riesci a seguire il seguente file. Crea una semplice libreria C++11 e un programma che la usa. Nessuna dipendenza. Discuterò altre opzioni standard C++ più avanti, usando il sistema CMake 3.8 per ora.
cmake_minimum_required(VERSION 3.8)project(Calculator LANGUAGES CXX)add_library(calclib STATIC src/calclib.cpp include/calc/lib.hpp)target_include_directories(calclib PUBLIC include)target_compile_features(calclib PUBLIC cxx_std_11)add_executable(calc apps/calc.cpp)target_link_libraries(calc PUBLIC calclib)
1. In questo libro, eviterò per lo più di mostrarvi il modo sbagliato di fare le cose; potete trovare molti esempi online. Menzionerò occasionalmente delle alternative, ma queste non sono raccomandate a meno che non siano assolutamente necessarie; spesso sono solo lì per aiutarti a leggere il vecchio codice CMake.
2. A volte vedrai
FATAL_ERROR
qui, che era necessario per supportare simpatici fallimenti quando si eseguiva questo in CMake <2.6, che non dovrebbe essere più un problema.
3. La sintassi
::
era originariamente intesa per leINTERFACE IMPORTED
librerie, che dovevano esplicitamente essere librerie definite fuori dal progetto corrente. Ma, a causa di questo, la maggior parte dei comanditarget_*
non funzionano sulle librerieIMPORTED
, rendendole difficili da impostare da soli. Quindi non usare la parola chiaveIMPORTED
per ora, e usa invece un targetALIAS
; andrà bene finché non inizierai a esportare i target. Questa limitazione è stata risolta in CMake 3.11.
.