Versiunea minimă
Iată prima linie din fiecare CMakeLists.txt
, care este numele necesar al fișierului pe care CMake îl caută:
cmake_minimum_required(VERSION 3.1)
Să menționăm un pic de sintaxă CMake. Numele comenziicmake_minimum_required
este insensibil la majuscule și minuscule, așa că practica obișnuită este de a folosi minuscule. 1 VERSION
este un cuvânt cheie special pentru această funcție. Iar valoarea versiunii urmează cuvântul cheie. Ca peste tot în această carte, faceți clic pe numele comenzii pentru a vedea documentația oficială,și folosiți meniul derulant pentru a schimba documentația între versiunile CMake.
Această linie este specială! 2 Versiunea lui CMake va dicta, de asemenea, politicile,care definesc schimbările de comportament. Astfel, dacă setați minimum_required
la VERSION2.8
, veți obține un comportament de legătură greșit pe macOS, de exemplu, chiar și în cele mai noi versiuni CMake. Dacă îl setați la 3.3 sau mai puțin, veți obține un comportament greșit al simbolurilor ascunse, etc. O listă de politici și versiuni este disponibilă lapolicies.
Începând cu CMake 3.12, aceasta suportă un interval, cum ar fi VERSION 3.1...3.15
;aceasta înseamnă că suportați până la 3.1, dar ați testat-o și cu noile setări de politici până la 3.15. Acest lucru este mult mai plăcut pentru utilizatorii care au nevoie de cele mai bune setări și, datorită unui truc în sintaxă, este compatibil cu versiunile mai vechi ale CMake (deși, de fapt, rularea CMake 3.1-3.11 va seta doar versiunea 3.1 a politicilor din acest exemplu, deoarece acele versiuni nu au tratat acest lucru în mod special). Noile versiuni ale politicilor tind să fie cele mai importante pentru utilizatorii de macOS șiWindows, care, de asemenea, au de obicei o versiune foarte recentă de CMake.
Aceasta este ceea ce ar trebui să facă proiectele noi:
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()
Dacă versiunea CMake este mai mică de 3.12, blocul if va fi adevărat, iar politica va fi setată la versiunea curentă de CMake. Dacă CMake este 3.12 sau mai mare, blocul if va fi fals, dar noua sintaxă din cmake_minimum_required
va fi respectată și aceasta va continua să funcționeze corect!
Atenție: Modul server CMake al MSVC a avut inițial o problemă în citirea acestui format, așa că, dacă aveți nevoie să suportați compilări Windows fără linie de comandă pentru versiuni mai vechi ale MSVC,veți dori să faceți acest lucru în schimb:
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()
Dacă chiar aveți nevoie să setați la o valoare mică aici, puteți folosicmake_policy
pentru a crește condiționat nivelul politicii sau pentru a seta o politică specifică. Vă rugăm să faceți acest lucru cel puțin pentru utilizatorii de macOS!
Stabilirea unui proiect
Acum, fiecare fișier CMake de nivel superior va avea următoarea linie:
project(MyProject VERSION 1.0 DESCRIPTION "Very nice project" LANGUAGES CXX)
Acum vedem și mai multă sintaxă. Șirurile de caractere sunt cotate, spațiile albe nu contează, iar numele proiectului este primul argument (pozițional). Toate cuvintele cheieargumente de aici sunt opționale. Versiunea stabilește o serie de variabile, cum ar fiMyProject_VERSION
și PROJECT_VERSION
. Limbajele sunt C
, CXX
,Fortran
, ASM
, CUDA
(CMake 3.8+), CSharp
(3.8+), și SWIFT
(CMake3.15+ experimental). C CXX
este valoarea implicită. În CMake 3.9, DESCRIPTION
a fost adăugat pentru a seta o descriere a proiectului, de asemenea. Documentația pentruproject
poate fi utilă.
Puteți adăuga comentarii cu caracterul #
. CMake are și o sintaxă inline pentru comentarii, dareste rar folosită.
Nu este nimic special în legătură cu numele proiectului. Nu sunt adăugate ținte în acest moment.
Facerea unui executabil
Deși bibliotecile sunt mult mai interesante și ne vom petrece cea mai mare parte a timpului cu ele, să începem cu un simplu executabil.
add_executable(one two.cpp three.h)
Există mai multe lucruri de despachetat aici. one
este atât numele fișierului executabil generat, cât și numele țintei CMake create (veți auzi mult mai multe despre ținte în curând, promit). Lista de fișiere sursă vine în continuare și puteți lista câte doriți. CMake este inteligent și va compila doar extensiile fișierelor sursă. Anteturile vor fi, în cele mai multe scopuri, ignorate; singurul motiv pentru a le lista este pentru a le face să apară în IDE-uri. Țintele apar ca dosare în multe IDE-uri. Mai multe despre sistemul general de compilare și ținte sunt disponibile la buildsystem.
Facerea unei biblioteci
Facerea unei biblioteci se face cu add_library
, și este la fel de simplă:
add_library(one STATIC two.cpp three.h)
Puteți alege un tip de bibliotecă, STATIC, SHARED sau MODULE. Dacă lăsați această alegere dezactivată, valoarea lui BUILD_SHARED_LIBS
va fi folosită pentru a alege între STATIC și SHARED.
După cum veți vedea în secțiunile următoare, de multe ori va trebui să faceți o țintă fictivă, adică una în care nu trebuie compilat nimic, de exemplu, pentru o bibliotecă doar de antet. Aceasta se numește o bibliotecă INTERFACE și este o altă alegere; singura diferență este că nu poate fi urmată de nume de fișiere.
De asemenea, puteți face o bibliotecă ALIAS
cu o bibliotecă existentă, ceea ce vă oferă pur și simplu un nou nume pentru o țintă. Singurul beneficiu al acestui lucru este că puteți face biblioteci cu ::
în nume (ceea ce veți vedea mai târziu). 3
Targets are your friend
Acum am specificat o țintă, cum adăugăm informații despre aceasta? De exemplu, poate că are nevoie de un director de includere:
target_include_directories(one PUBLIC include)
target_include_directories
adaugă un director de includere la o țintă. PUBLIC
nu înseamnă prea mult pentru un executabil; pentru o bibliotecă îi permite lui CMake să știe că toate țintele care se leagă la această țintă trebuie să aibă nevoie și de acel director de includere. Alte opțiuni sunt PRIVATE
(afectează doar ținta curentă, nu și dependențele), și INTERFACE
(necesară doar pentru dependențe).
Potem apoi să înlănțuim țintele:
add_library(another STATIC another.cpp another.h)target_link_libraries(another PUBLIC one)
target_link_libraries
este probabil cea mai utilă și confuză comandă din CMake. Aceasta ia o țintă (another
) și adaugă o dependență dacă este dată o țintă. Dacă nu există o țintă cu acest nume (one
), atunci adaugă o legătură către o bibliotecă numită one
pe calea dumneavoastră (de aici și numele comenzii). Sau îi puteți da o cale completă către o bibliotecă. Sau un indicator al linkerului. Doar pentru a adăuga un ultim strop de confuzie, CMake clasic vă permitea să săriți peste selecția cuvintelor cheie PUBLIC
, etc. Dacă acest lucru a fost făcut pe o țintă, veți primi o eroare dacă veți încerca să amestecați stiluri mai jos în lanț.
Concentrați-vă pe folosirea țintelor peste tot și a cuvintelor cheie peste tot și veți fi bine.
Țintele pot avea directoare de includere, biblioteci legate (sau ținte legate), opțiuni de compilare, definiții de compilare, caracteristici de compilare (vezi capitolul C++11) și multe altele. După cum veți vedea în cele două capitole de includere a proiectelor, puteți obține adesea ținte (și faceți întotdeauna ținte) pentru a reprezenta toate bibliotecile pe care le utilizați. Chiar și lucrurile care nu sunt adevărate biblioteci, cum ar fi OpenMP, pot fi reprezentate cu target-uri. Acesta este motivul pentru care Modern CMake este grozav!
Dive in
Vezi dacă poți urmări următorul fișier. Acesta realizează o bibliotecă simplă C++11 și un program care o folosește. Nu are dependențe. Voi discuta mai multe opțiuni standard C++ mai târziu, folosind deocamdată sistemul CMake 3.8.
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. În această carte, voi evita în mare parte să vă arăt modul greșit de a face lucrurile; puteți găsi o mulțime de exemple în acest sens pe internet. Voi menționa ocazional alternative, dar acestea nu sunt recomandate decât dacă sunt absolut necesare; de multe ori sunt acolo doar pentru a vă ajuta să citiți codul CMake mai vechi.
2. Veți vedea uneori
FATAL_ERROR
aici, care era necesar pentru a suporta eșecuri frumoase atunci când se executa acest lucru în CMake <2.6, ceea ce nu ar trebui să mai fie o problemă.
3. Sintaxa
::
a fost inițial destinată bibliotecilorINTERFACE IMPORTED
, care trebuiau în mod explicit să fie biblioteci definite în afara proiectului curent. Dar, din această cauză, majoritatea comenzilortarget_*
nu funcționează pe bibliotecileIMPORTED
, ceea ce le face greu de configurat de unul singur. Așadar, nu folosiți deocamdată cuvântul cheieIMPORTED
și folosiți în schimb o țintăALIAS
; va fi bine până când veți începe să exportați ținte. Această limitare a fost corectată în CMake 3.11.