Minimum Versie
Hier is de eerste lijn van elke CMakeLists.txt
, die de vereiste naam is van het bestand waar CMake naar zoekt:
cmake_minimum_required(VERSION 3.1)
Laten we een beetje CMake syntaxis noemen. De naam van het commandocmake_minimum_required
is niet hoofdlettergevoelig, dus het is gebruikelijk om kleine letters te gebruiken. 1 De VERSION
is een speciaal sleutelwoord voor deze functie. En de waarde van de versie volgt op het sleutelwoord. Zoals overal in dit boek, klik op de naam van het commando om de officiële documentatie te zien, en gebruik de dropdown om van documentatie te wisselen tussen CMake versies.
Deze regel is speciaal! 2 De versie van CMake zal ook de beleidsregels dicteren, die gedragsveranderingen definiëren. Dus, als je minimum_required
op VERSION2.8
zet, krijg je het verkeerde linking gedrag op macOS, bijvoorbeeld, zelfs in de nieuwste CMake versies. Als je het instelt op 3.3 of lager, krijg je het verkeerde gedrag bij verborgen symbolen, enz. Een lijst van policies en versies is beschikbaar oppolicies.
Beginnend in CMake 3.12, ondersteunt dit een bereik, zoals VERSION 3.1...3.15
;dit betekent dat je zo laag als 3.1 ondersteunt, maar het ook hebt getest met de nieuwepolicy instellingen tot 3.15. Dit is veel prettiger voor gebruikers die de betere instellingen nodig hebben, en door een truc in de syntaxis is het achterwaarts compatibel met oudere versies van CMake (hoewel het draaien van CMake 3.1-3.11 eigenlijk alleen de 3.1 versie van de policies in dit voorbeeld zal instellen, omdat die versies dit niet speciaal behandelden). Nieuwe versies van policies zijn meestal het belangrijkst voor macOS en Windows gebruikers, die ook meestal een zeer recente versie van CMake hebben.
Dit is wat nieuwe projecten zouden moeten doen:
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()
Als CMake versie minder is dan 3.12, zal het if blok waar zijn, en de policy zal worden ingesteld op de huidige CMake versie. Als CMake versie 3.12 of hoger is, zal het if-blok false zijn, maar de nieuwe syntax in cmake_minimum_required
zal worden gerespecteerd en dit zal goed blijven werken!
WAARSCHUWING: MSVC’s CMake server mode had oorspronkelijk een fout bij het lezen van dit formaat, dus als je niet-command line Windows builds wilt ondersteunen voor oudere MSVC versies, dan kun je het beste dit doen:
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()
Als je hier echt een lage waarde moet instellen, kun jecmake_policy
gebruiken om het policy level conditioneel te verhogen of een specifieke policy in te stellen. Doe dit in ieder geval voor uw macOS gebruikers!
Instellen van een project
Nu zal ieder CMake bestand op het hoogste niveau de volgende regel hebben:
project(MyProject VERSION 1.0 DESCRIPTION "Very nice project" LANGUAGES CXX)
Nu zien we nog meer syntaxis. Teksten zijn geciteerd, spaties doen er niet toe, en de naam van het project is het eerste argument (positioneel). Alle keywordargumenten hier zijn optioneel. De versie stelt een hoop variabelen in, zoalsMyProject_VERSION
en PROJECT_VERSION
. De talen zijn C
, CXX
,Fortran
, ASM
, CUDA
(CMake 3.8+), CSharp
(3.8+), en SWIFT
(CMake3.15+ experimenteel). C CXX
is de standaardinstelling. In CMake 3.9 is DESCRIPTION
toegevoegd om ook een project beschrijving in te stellen. De documentatie voorproject
kan nuttig zijn.
Je kunt opmerkingen toevoegen met het #
karakter. CMake heeft ook een inline syntax voor commentaar, maar het wordt zelden gebruikt.
Er is eigenlijk niets speciaals aan de projectnaam. Er worden geen targets toegevoegd.
Een executable maken
Hoewel libraries veel interessanter zijn, en we er de meeste tijd aan zullen besteden, beginnen we met een eenvoudige executable.
add_executable(one two.cpp three.h)
Er zijn verschillende dingen om hier uit te pakken. one
is zowel de naam van het gegenereerde uitvoerbare bestand, als de naam van het gemaakte CMake target (je zult binnenkort veel meer horen over targets, dat beloof ik). De lijst met bronbestanden komt daarna, en je kunt er zoveel opnoemen als je wilt. CMake is slim, en zal alleen bronbestand extensies compileren. De headers worden, voor de meeste doeleinden, genegeerd; de enige reden om ze op te sommen is om ze in IDE’s te laten verschijnen. Targets verschijnen als mappen in veel IDE’s. Meer over het algemene build systeem en targets is beschikbaar op buildsystem.
Een library
Een library maken wordt gedaan met add_library
, en is ongeveer net zo eenvoudig:
add_library(one STATIC two.cpp three.h)
U kunt een type library kiezen, STATIC, SHARED, of MODULE. Als u deze keuze weglaat, zal de waarde van BUILD_SHARED_LIBS
worden gebruikt om te kiezen tussen STATIC en SHARED.
Zoals u in de volgende secties zult zien, zult u vaak een fictief doel moeten maken, dat wil zeggen, een doel waar niets hoeft te worden gecompileerd, bijvoorbeeld voor een header-only bibliotheek. Dat heet een INTERFACE library, en is een andere keuze; het enige verschil is dat het niet gevolgd kan worden door bestandsnamen.
Je kunt ook een ALIAS
library maken met een bestaande library, wat je gewoon een nieuwe naam geeft voor een target. Het enige voordeel hiervan is dat je bibliotheken kunt maken met ::
in de naam (wat je later zult zien). 3
Targets zijn je vriend
Nu we een target hebben gespecificeerd, hoe voegen we er informatie over toe? Bijvoorbeeld, misschien heeft het een include directory nodig:
target_include_directories(one PUBLIC include)
target_include_directories
voegt een include directory toe aan een target. PUBLIC
betekent niet veel voor een uitvoerbaar bestand; voor een bibliotheek laat het CMake weten dat alle targets die naar dit target linken ook die include directory nodig hebben. Andere opties zijn PRIVATE
(heeft alleen invloed op de huidige target, niet op dependencies), en INTERFACE
(alleen nodig voor dependencies).
We kunnen dan targets ketenen:
add_library(another STATIC another.cpp another.h)target_link_libraries(another PUBLIC one)
target_link_libraries
is waarschijnlijk het meest nuttige en verwarrende commando in CMake. Het neemt een target (another
) en voegt een dependency toe als er een target is gegeven. Als er geen target met die naam (one
) bestaat, dan voegt het een link toe naar een bibliotheek genaamd one
op je pad (vandaar de naam van het commando). Of je kunt het een volledig pad naar een bibliotheek geven. Of een linker vlag. Om nog een laatste beetje verwarring toe te voegen, klassieke CMake stond je toe om de keyword selectie van PUBLIC
, etc. over te slaan. Als dit op een target is gedaan, krijg je een foutmelding als je verderop in de keten stijlen probeert te mixen.
Focus je op het gebruik van targets overal, en keywords overal, en het komt goed.
Targets kunnen include directories hebben, gelinkte libraries (of gelinkte targets), compileer opties, compileer definities, compileer eigenschappen (zie het C++11 hoofdstuk), en meer. Zoals je zult zien in de twee inclusief projecten hoofdstukken, kun je vaak targets krijgen (en altijd targets maken) om alle bibliotheken die je gebruikt te representeren. Zelfs dingen die geen echte bibliotheken zijn, zoals OpenMP, kunnen worden gerepresenteerd met targets. Dit is waarom Modern CMake geweldig is!
Duik erin
Zie of je het volgende bestand kunt volgen. Het maakt een eenvoudige C++11 bibliotheek en een programma dat het gebruikt. Geen afhankelijkheden. Ik zal later meer C++ standaard opties bespreken, voor nu gebruikmakend van het CMake 3.8 systeem.
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 dit boek zal ik vooral vermijden om u de verkeerde manier te laten zien om dingen te doen; u kunt daar genoeg voorbeelden van vinden online. Ik zal af en toe alternatieven noemen, maar deze worden niet aangeraden tenzij ze absoluut noodzakelijk zijn; vaak zijn ze er alleen om je te helpen oudere CMake code te lezen.
2. Je zult hier soms
FATAL_ERROR
zien, dat was nodig om mooie fouten te ondersteunen wanneer je dit in CMake <2.6 draaide, wat nu geen probleem meer zou moeten zijn.
3. De
::
syntax was oorspronkelijk bedoeld voorINTERFACE IMPORTED
bibliotheken, die expliciet geacht werden bibliotheken te zijn die buiten het huidige project gedefinieerd waren. Maar hierdoor werken de meestetarget_*
commando’s niet opIMPORTED
bibliotheken, waardoor ze moeilijk zelf in te stellen zijn. Dus gebruik hetIMPORTED
sleutelwoord voorlopig niet, en gebruik in plaats daarvan eenALIAS
target; het zal goed gaan totdat je begint met het exporteren van targets. Deze beperking is opgelost in CMake 3.11.