Minimum version
Her er den første linje i hver CMakeLists.txt
, som er det krævede navn på den fil CMake leder efter:
cmake_minimum_required(VERSION 3.1)
Lad os nævne en smule CMake-syntaks. Kommandonavnetcmake_minimum_required
er ufølsomt over for store og små bogstaver, så den almindelige praksis er at bruge små bogstaver. 1 VERSION
er et særligt nøgleord for denne funktion. Og værdien af versionen følger efter nøgleordet. Som alle andre steder i denne bog skal du blot klikke på kommandonavnet for at se den officielle dokumentation,og bruge rullemenuen til at skifte dokumentation mellem CMake-versioner.
Denne linje er speciel! 2 Versionen af CMake vil også diktere politikkerne,som definerer adfærdsændringer. Så hvis du sætter minimum_required
til VERSION2.8
, vil du f.eks. få den forkerte linkadfærd på macOS, selv i de nyeste CMake-versioner. Hvis du indstiller den til 3.3 eller mindre, får du den forkerte adfærd med skjulte symboler osv. En liste over politikker og versioner er tilgængelig påpolicies.
Dette understøtter fra CMake 3.12 et interval, f.eks. VERSION 3.1...3.15
;det betyder at du understøtter helt ned til 3.1, men har også testet det med de nyepolicy-indstillinger op til 3.15. Dette er meget pænere for brugere, der har brug for de bedre indstillinger, og på grund af et trick i syntaksen er det bagudkompatibelt med ældreversioner af CMake (selvom det faktisk kun vil sætte 3.1versionen af politikkerne i dette eksempel, hvis man kører CMake 3.1-3.11, da disse versioner ikke behandlede dette specielt). Nye versioner af politikker har tendens til at være vigtigst for macOS- ogWindows-brugere, som også normalt har en meget nyere version af CMake.
Dette er, hvad nye projekter bør gøre:
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()
Hvis CMake-versionen er mindre end 3.12, vil if-blokken være sand, og politikken vil blive sat til den aktuelle CMake-version. Hvis CMake er 3.12 eller højere, vil if-blokken være falsk, men den nye syntaks i cmake_minimum_required
vil blive respekteret, og dette vil fortsat fungere korrekt!
VARNELSE: MSVC’s CMake-servertilstand havde oprindeligt problemer med at læse dette format, så hvis du skal understøtte Windows-builds uden kommandolinje for ældre MSVC-versioner, skal du gøre dette i stedet:
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()
Hvis du virkelig har brug for at indstille til en lav værdi her, kan du brugecmake_policy
til betinget at øge politikniveauet eller indstille en specifik politik. Gør i det mindste dette for dine macOS-brugere!
Sæt et projekt
Nu vil hver CMake-fil på øverste niveau have den næste linje:
project(MyProject VERSION 1.0 DESCRIPTION "Very nice project" LANGUAGES CXX)
Nu ser vi endnu mere syntaks. Strings er anførselstegn, whitespace er ligegyldigt, og navnet på projektet er det første argument (positionelt). Alle nøgleordsargumenter her er valgfrie. Versionen indstiller en masse variabler, somMyProject_VERSION
og PROJECT_VERSION
. Sprogene er C
, CXX
,Fortran
, ASM
, CUDA
(CMake 3.8+), CSharp
(3.8+) og SWIFT
(CMake3.15+ experimental). C CXX
er standard. I CMake 3.9 blev DESCRIPTION
også tilføjet for at indstille en projektbeskrivelse. Dokumentationen forproject
kan være nyttig.
Du kan tilføjekommentarermedtegnet #
. CMake har også en inline-syntaks for kommentarer, men den bruges sjældent.
Der er egentlig ikke noget særligt ved projektnavnet. Der er ikke tilføjet nogen mål på dette tidspunkt.
Oprettelse af en eksekverbar fil
Men selv om biblioteker er meget mere interessante, og vi vil bruge det meste af vores tid med dem, så lad os starte med en simpel eksekverbar fil.
add_executable(one two.cpp three.h)
Der er flere ting at pakke ud her. one
er både navnet på den genererede eksekverbare fil og navnet på det oprettede CMake-mål (du kommer snart til at høre meget mere om mål, det lover jeg). Herefter kommer listen over kildefilerne, og du kan liste så mange som du vil. CMake er smart, og vil kun kompilere kildefiludvidelser. Headerne vil for de fleste formål blive ignoreret; den eneste grund til at liste dem er at få dem til at dukke op i IDE’er. Targets vises som mapper i mange IDE’er. Mere om det generelle buildsystem og targets kan findes på buildsystem.
Makning af et bibliotek
Makning af et bibliotek sker med add_library
, og er næsten lige så simpelt:
add_library(one STATIC two.cpp three.h)
Du får mulighed for at vælge en type bibliotek, STATIC, SHARED eller MODULE. Hvis du udelader dette valg, vil værdien af BUILD_SHARED_LIBS
blive brugt til at vælge mellem STATIC og SHARED.
Som du vil se i de følgende afsnit, vil du ofte have brug for at lave et fiktivt mål, dvs. et hvor intet skal kompileres, f.eks. for et bibliotek, der kun indeholder en header. Det kaldes et INTERFACE-bibliotek og er et andet valg; den eneste forskel er, at det ikke kan efterfølges af filnavne.
Du kan også lave et ALIAS
bibliotek med et eksisterende bibliotek, hvilket blot giver dig et nyt navn til et mål. Den eneste fordel ved dette er, at du kan lave biblioteker med ::
i navnet (hvilket du vil se senere). 3
Mål er din ven
Nu har vi angivet et mål, hvordan tilføjer vi oplysninger om det? Måske har den f.eks. brug for en include-mappe:
target_include_directories(one PUBLIC include)
target_include_directories
tilføjer en include-mappe til et mål. PUBLIC
betyder ikke meget for en eksekverbar fil; for et bibliotek lader det CMake vide, at alle mål, der linker til dette mål, også skal have brug for denne include-mappe. Andre muligheder er PRIVATE
(påvirker kun det aktuelle target, ikke afhængigheder) og INTERFACE
(kun nødvendigt for afhængigheder).
Vi kan derefter kæde targets:
add_library(another STATIC another.cpp another.h)target_link_libraries(another PUBLIC one)
target_link_libraries
er nok den mest nyttige og forvirrende kommando i CMake. Den tager et target (another
) og tilføjer en afhængighed, hvis der er angivet et target. Hvis der ikke findes noget mål med dette navn (one
), tilføjer den et link til et bibliotek ved navn one
på din sti (deraf navnet på kommandoen). Eller du kan give den en fuld sti til et bibliotek. Eller et linker-flag. Bare for at tilføje en sidste smule forvirring, så gav det klassiske CMake dig mulighed for at springe over nøgleordsvalget af PUBLIC
osv. Hvis dette blev gjort på et target, får du en fejl, hvis du forsøger at blande stilarter længere nede i kæden.
Fokuser på at bruge targets overalt og nøgleord overalt, så skal du nok klare dig.
Targets kan have include-mapper, linkede biblioteker (eller linkede targets), kompileringsindstillinger, kompileringsdefinitioner, kompileringsfunktioner (se kapitlet om C++11) og meget mere. Som du vil se i de to kapitler om inklusive projekter, kan du ofte få targets (og altid lave targets) til at repræsentere alle de biblioteker, du bruger. Selv ting, der ikke er egentlige biblioteker, som OpenMP, kan repræsenteres med targets. Det er derfor Modern CMake er fantastisk!
Dyk ned i
Se om du kan følge med i følgende fil. Den laver et simpelt C++11-bibliotek og et program, der bruger det. Ingen afhængigheder. Jeg vil diskutere flere C++-standardindstillinger senere, idet jeg indtil videre bruger CMake 3.8-systemet.
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. I denne bog vil jeg for det meste undgå at vise dig den forkerte måde at gøre tingene på; du kan finde masser af eksempler på det på nettet. Jeg vil lejlighedsvis nævne alternativer, men disse anbefales ikke, medmindre de er absolut nødvendige; ofte er de blot til for at hjælpe dig med at læse ældre CMake-kode.
2. Du vil nogle gange se
FATAL_ERROR
her, det var nødvendigt for at understøtte pæne fejl, når man kørte dette i CMake <2.6, hvilket ikke burde være et problem længere.
3.
::
-syntaksen var oprindeligt beregnet tilINTERFACE IMPORTED
-biblioteker, som udtrykkeligt skulle være biblioteker, der var defineret uden for det aktuelle projekt. Men på grund af dette virker de fleste aftarget_*
-kommandoerne ikke påIMPORTED
-biblioteker, hvilket gør dem svære at opsætte selv. Så lad være med at bruge nøgleordetIMPORTED
indtil videre, og brug etALIAS
-mål i stedet; det vil være fint, indtil du begynder at eksportere mål. Denne begrænsning blev rettet i CMake 3.11.