Tijdens de ontwikkeling houd ik ervan om compilers te veranderen, modi te bouwen, afhankelijkheidsversies te maken, statische analyses uit te voeren, prestaties te meten, dekking te verzamelen, documentatie te genereren, enz. En ik hou echt van CMake omdat ik hiermee alles kan doen wat ik wil.
Veel mensen bekritiseren CMake, en vaak terecht, maar als je ernaar kijkt, is niet alles zo slecht, en recentelijk helemaal niet slecht, en de richting van de ontwikkeling is vrij positief.
In deze notitie wil ik je vertellen hoe je eenvoudigweg een headerbibliotheek in C++ in het CMake-systeem kunt organiseren om de volgende functionaliteit te krijgen:
Montage;
Autorun-tests;
Meting van codedekking;
Installatie;
Automatische documentatie;
Online sandbox-generatie;
Statische analyse.
Iedereen die de voordelen en C-make al begrijpt, kan dat gewoon doen projectsjabloon downloaden en begin het te gebruiken.
We zullen vooral praten over het organiseren van CMake-scripts, dus ze zullen in detail worden besproken. Iedereen kan de rest van de bestanden direct bekijken op de sjabloonprojectpagina.
Allereerst moet u de vereiste versie van het CMake-systeem aanvragen. CMake evolueert, commandohandtekeningen en gedrag onder verschillende omstandigheden veranderen. Om ervoor te zorgen dat CMake onmiddellijk begrijpt wat we ervan willen, moeten we onmiddellijk onze vereisten ervoor vastleggen.
cmake_minimum_required(VERSION 3.13)
Vervolgens zullen we ons project, de naam, de versie, de gebruikte talen, enz. aanduiden (zie. ΠΊΠΎΠΌΠ°Π½Π΄Ρ project).
In dit geval geven we de taal aan CXX (en dit betekent C++), zodat CMake niet hoeft te zoeken naar een C-taalcompiler (standaard bevat CMake twee talen: C en C++).
project(Mylib VERSION 1.0 LANGUAGES CXX)
Hier kunt u direct controleren of ons project als deelproject is opgenomen in een ander project. Dit zal in de toekomst veel helpen.
De eerste optie is MYLIB_TESTING β om unit-tests uit te schakelen. Dit kan nodig zijn als we er zeker van zijn dat alles in orde is met de tests, maar we bijvoorbeeld alleen ons project willen installeren of verpakken. Of ons project is opgenomen als subproject - in dit geval is de gebruiker van ons project niet geΓ―nteresseerd in het uitvoeren van onze tests. Je test de afhankelijkheden die je gebruikt toch niet?
Daarnaast maken wij een aparte optie MYLIB_COVERAGE voor het meten van de codedekking door middel van tests, maar hiervoor zijn extra tools nodig, dus het moet expliciet worden ingeschakeld.
Natuurlijk zijn we coole plus-programmeurs, dus we willen het maximale niveau van diagnostiek tijdens het compileren van de compiler. Geen enkele muis zal er doorheen glippen.
Onze bibliotheek bestaat alleen uit headerbestanden, wat betekent dat we geen uitputting hebben in de vorm van statische of dynamische bibliotheken. Aan de andere kant, om onze bibliotheek extern te kunnen gebruiken, moet deze geΓ―nstalleerd zijn, detecteerbaar zijn in het systeem en verbonden zijn met uw project, en tegelijkertijd moeten dezelfde headers, en mogelijk enkele extra, zijn aan de eigenschappen verbonden.
Voor dit doel creΓ«ren we een interfacebibliotheek.
Deze opdracht koppelt de headers die we nodig hebben aan onze interfacebibliotheek, en als onze bibliotheek is verbonden met een doel binnen dezelfde CMake-hiΓ«rarchie, worden de headers uit de map eraan gekoppeld ${CMAKE_CURRENT_SOURCE_DIR}/include, en of onze bibliotheek op het systeem is geΓ―nstalleerd en met een ander project is verbonden met behulp van de opdracht find_package, dan worden er headers uit de map aan gekoppeld include relatief ten opzichte van de installatiemap.
Laten we een taalstandaard instellen. Uiteraard de allerlaatste. Tegelijkertijd nemen we niet alleen de standaard op, maar breiden we deze ook uit naar degenen die onze bibliotheek gaan gebruiken. Dit wordt bereikt doordat de set-eigenschap een categorie heeft INTERFACE (Zie. target_compile_features-opdracht).
Laten we een alias maken voor onze bibliotheek. Bovendien zal het voor schoonheid in een speciale "naamruimte" staan. Dit zal handig zijn als er verschillende modules in onze bibliotheek verschijnen en we ze onafhankelijk van elkaar gaan verbinden. Zoals bijvoorbeeld in Busta.
Onze headers in het systeem installeren. Alles is hier eenvoudig. We zeggen dat de map met alle headers in de map moet komen include ten opzichte van de installatielocatie.
Vervolgens informeren we het bouwsysteem dat we de opdracht willen kunnen aanroepen in projecten van derden find_package(Mylib) en een doelpunt krijgen Mylib::mylib.
De volgende spreuk moet op deze manier worden begrepen. In een project van derden roepen we de opdracht aan find_package(Mylib 1.2.3 REQUIRED), en de echte versie van de geΓ―nstalleerde bibliotheek zal incompatibel zijn met de versie 1.2.3CMake genereert automatisch een fout. Dat wil zeggen dat u versies niet handmatig hoeft bij te houden.
Als tests expliciet worden uitgeschakeld met behulp van overeenkomstige optie of ons project is een subproject, dat wil zeggen dat het met behulp van de opdracht is verbonden met een ander CMake-project add_subdirectory, we gaan niet verder in de hiΓ«rarchie, en het script, dat de opdrachten beschrijft voor het genereren en uitvoeren van tests, werkt eenvoudigweg niet.
Allereerst vinden we een pakket met het vereiste testframework (vervangen door uw favoriete).
find_package(doctest 2.3.3 REQUIRED)
Laten we ons uitvoerbare bestand met tests maken. Meestal voeg ik rechtstreeks aan het uitvoerbare binaire bestand alleen het bestand toe dat de functie zal bevatten main.
add_executable(mylib-unit-tests test_main.cpp)
En ik voeg bestanden toe waarin de tests zelf later worden beschreven. Maar dat hoef je niet te doen.
Wij verbinden afhankelijkheden. Houd er rekening mee dat we alleen de CMake-doelen die we nodig hadden aan ons binaire bestand hebben gekoppeld en de opdracht niet hebben aangeroepen target_include_directories. Titels uit het testframework en uit het onze Mylib::mylib, evenals build-parameters (in ons geval is dit de C++-taalstandaard) kwamen samen met deze doelen tot stand.
Ten slotte maken we een dummydoel, waarvan de βbuildβ gelijk is aan het uitvoeren van tests, en voegen we dit doel toe aan de standaardbuild (het attribuut is verantwoordelijk voor deze ALL). Dit betekent dat de standaardbuild ervoor zorgt dat de tests worden uitgevoerd, wat betekent dat we nooit zullen vergeten ze uit te voeren.
add_custom_target(check ALL COMMAND mylib-unit-tests)
Vervolgens schakelen we het meten van de codedekking in als de juiste optie is opgegeven. Ik zal niet in details treden, omdat ze meer betrekking hebben op een tool voor het meten van de dekking dan op CMake. Het is alleen belangrijk om op te merken dat op basis van de resultaten een doel zal worden gecreΓ«erd coverage, waarmee het handig is om de dekking te gaan meten.
Vervolgens controleren we of de gebruiker de taalvariabele heeft ingesteld. Zo ja, dan raken we het niet aan, zo niet, dan nemen we Russisch. Vervolgens configureren we de Doxygen-systeembestanden. Alle noodzakelijke variabelen, inclusief de taal, gaan daar naartoe tijdens het configuratieproces (zie. ΠΊΠΎΠΌΠ°Π½Π΄Ρ configure_file).
Dan maken we een doel doc, waarmee documentatie wordt gegenereerd. Omdat het genereren van documentatie niet de grootste behoefte is in het ontwikkelingsproces, zal het doel niet standaard ingeschakeld zijn; het zal expliciet moeten worden gelanceerd.
if (Doxygen_FOUND)
if (NOT MYLIB_DOXYGEN_LANGUAGE)
set(MYLIB_DOXYGEN_LANGUAGE Russian)
endif()
message(STATUS "Doxygen documentation will be generated in ${MYLIB_DOXYGEN_LANGUAGE}")
configure_file(Doxyfile.in Doxyfile)
add_custom_target(doc COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
endif ()
Hier vinden we de derde Python en creΓ«ren we een doelwit wandbox, dat een verzoek genereert dat overeenkomt met de service-API Wanddoos, en stuurt hem weg. Het antwoord wordt geleverd met een link naar de voltooide sandbox.
Biedt de mogelijkheid om het bouwen en richten van unittests uit te schakelen check. Als gevolg hiervan wordt het meten van codedekking door tests uitgeschakeld (zie. MYLIB_COVERAGE).
Het testen wordt ook automatisch uitgeschakeld als het project met behulp van het commando als subproject aan een ander project wordt gekoppeld add_subdirectory.
Hiervoor wordt gebruik gemaakt van de dienst Wanddoos. Ik weet niet hoe flexibel hun servers zijn, maar ik denk dat deze mogelijkheid niet mag worden misbruikt.
In feite is CMake versie 3.13 alleen nodig om enkele van de consoleopdrachten uit te voeren die in deze help worden beschreven. Vanuit het oogpunt van de syntaxis van CMake-scripts is versie 3.8 voldoende als generatie op andere manieren wordt aangeroepen.
Hierna wordt de statische analyse automatisch gestart telkens wanneer de broncode wordt gecompileerd en opnieuw gecompileerd. Het is niet nodig om iets extra's te doen.
kletteren
Met behulp van een prachtig hulpmiddel scan-build U kunt ook in een handomdraai een statische analyse uitvoeren:
CMake is een zeer krachtig en flexibel systeem waarmee u functionaliteit voor elke smaak en kleur kunt implementeren. En hoewel de syntaxis soms veel te wensen overlaat, is de duivel nog steeds niet zo verschrikkelijk als hij wordt geschilderd. Gebruik het CMake-bouwsysteem ten behoeve van de samenleving en de gezondheid.