CMake ja C++ – vennad igavesti

CMake ja C++ – vennad igavesti

Arendusprotsessis meeldib mulle vahetada kompilaatorite, kogumise reĆŸiimide, sĂ”ltuvuste versioonide vahel, teha staatilist analĂŒĂŒsi, mÔÔta jĂ”udlust, koguda katvust, genereerida dokumentatsiooni jne. Ja mulle meeldib vĂ€ga CMake, sest see vĂ”imaldab mul teha kĂ”ike, mida ma tahan.

Paljud inimesed kritiseerivad CMake'i ning tihti on see Ă”igustatud, kuid kui asja lĂ€hemalt uurida, pole asi ĂŒldse nii halb, ja viimase ajal on see isegi pĂ€ris hĂ€sti edenenud, ning areng suund on tĂ€iesti positiivne.

Selles mĂ€rkuses soovin rÀÀkida sellest, kuidas on ĂŒsna lihtne organiseerida C++ peaaguplokki CMake sĂŒsteemis, et saavutada jĂ€rgmine funktsionaalsus:

  1. Kogumine;
  2. Automaatne testide kÀivitamine;
  3. Koodikatvuse mÔÔtmine;
  4. Paigaldamine;
  5. Automaatne dokumenteerimine;
  6. Online-keskkonna genereerimine;
  7. Staatiline analĂŒĂŒs.

Kes juba teab Plusidest ja CMake'ist, vÔib lihtsalt alla laadida projekti mall ja hakkata seda kasutama.


Sisukord

  1. Projekt seestpoolt
    1. Projekti struktuur
    2. Peamine CMake-fail (./CMakeLists.txt)
      1. Teave projekti kohta
      2. Projekti valikud
      3. Kompileerimise valikud
      4. Peamine eesmÀrk
      5. Paigaldamine
      6. Testid
      7. Dokumentatsioon
      8. Online-keskkond
    3. Testide skript (test/CMakeLists.txt)
      1. Testimine
      2. Katvus
    4. Dokumentatsiooni skript (doc/CMakeLists.txt)
    5. Online-keskkonna skript (online/CMakeLists.txt)
  2. Projekt vÀljaspool
    1. Kogumine
      1. Genereerimine
      2. Kogumine
    2. Valikud
      1. MYLIB_COVERAGE
      2. MYLIB_TESTING
      3. MYLIB_DOXYGEN_LANGUAGE
    3. Kogumise eesmÀrgid
      1. Vaikimisi
      2. mylib-unit-tests
      3. check
      4. coverage
      5. doc
      6. wandbox
    4. NĂ€ited
  3. Tööriistad
  4. Staatiline analĂŒĂŒs
  5. EessÔna

Projekt seestpoolt

Projekti struktuur

.
├── CMakeLists.txt
├── README.en.md
├── README.md
├── doc
│   ├── CMakeLists.txt
│   └── Doxyfile.in
├── include
│   └── mylib
│       └── myfeature.hpp
├── online
│   ├── CMakeLists.txt
│   ├── mylib-example.cpp
│   └── wandbox.py
└── test
    ├── CMakeLists.txt
    ├── mylib
    │   └── myfeature.cpp
    └── test_main.cpp

PĂ”hiliselt rÀÀgime sellest, kuidas organiseerida CMake skripte, seetĂ”ttu kĂ€sitletakse neid pĂ”hjalikult. ÜlejÀÀnud faile saab iga soovija vaadata otse projekti malli lehelt.

Peamine CMake-fail (./CMakeLists.txt)

Teave projekti kohta

Esiteks tuleb kĂŒsida vajalikku versiooni CMake sĂŒsteemist. CMake areneb, kĂ€skude allkirjad ja kĂ€itumine erinevates tingimustes muutuvad. Et CMake kohe mĂ”istaks, mida me temalt ootame, tuleb kohe fikseerida meie ehk nĂ”udmised.

cmake_minimum_required(VERSION 3.13)

SeejÀrel tÀhistame oma projekti, selle nime, versiooni, kasutatavad keeled ja muud (vt. kÀsku project).

Sel juhul mÀÀrame keele CXX (see tĂ€hendab C++), et CMake ei pingutaks ja ei otsiks C keele kompilaatorit (CMake'is on vaikimisi sisse lĂŒlitatud kaks keelt: C ja C++).

project(Mylib VERSION 1.0 LANGUAGES CXX)

Siin on vÔimalik kohe kontrollida, kas meie projekt on teises projektis alaprojektina kaasatud. See aitab meid tulevikus oluliselt.

get_directory_property(IS_SUBPROJECT PARENT_DIRECTORY)

Projekti valikud

Kaalume kahte valikut.

Esimene valik — MYLIB_TESTING — modulaarsete testide vĂ€ljalĂŒlitamine. See vĂ”ib olla vajalik, kui oleme kindlad, et testidega on kĂ”ik korras, kuid soovime nĂ€iteks oma projekti ainult installida vĂ”i pakkida. VĂ”i on meie projekt kaasatud alaprojektina — sellisel juhul pole meie projekti kasutajale huvi meie teste kĂ€ivitada. Kas te testite sĂ”ltuvusi, mida kasutate?

option(MYLIB_TESTING "Luba modulaarne testimine" ON)

Lisaks teeme eraldi valiku MYLIB_COVERAGE kattuvuse mÔÔtmiseks testidega, kuid see vajab tÀiendavaid tööriistu, seega tuleb see selgelt lubada.

option(MYLIB_COVERAGE "Luba testidega kattuvuse mÔÔtmine" OFF)

Kompileerimise valikud

Muidugi oleme me Ă€gedad C++ programmeerijad ja seetĂ”ttu tahame kompilaatori poolt maksimaalset kompileerimise aja diagnostikat. Ükski hiir ei lipsa lĂ€bi.

add_compile_options(
    -Werror

    -Wall
    -Wextra
    -Wpedantic

    -Wcast-align
    -Wcast-qual
    -Wconversion
    -Wctor-dtor-privacy
    -Wenum-compare
    -Wfloat-equal
    -Wnon-virtual-dtor
    -Wold-style-cast
    -Woverloaded-virtual
    -Wredundant-decls
    -Wsign-conversion
    -Wsign-promo
)

Samuti keelame laiendused, et tÀielikult vastata C++ keele standardile. CMake'is on need vaikimisi lubatud.

if(NOT CMAKE_CXX_EXTENSIONS)
    set(CMAKE_CXX_EXTENSIONS OFF)
endif()

Peamine eesmÀrk

Meie teek koosneb ainult pealkirjafailidest, mistĂ”ttu meil ei ole mingit vĂ€ljundit staatiliste vĂ”i dĂŒnaamiliste teekide nĂ€ol. Teisest kĂŒljest, et meie teeki vĂ€ljastpoolt kasutada, tuleb see installida, et seda saaks sĂŒsteemis avastada ja oma projekti lisada, ning sellega peavad olema koos need sama pealkirjad, samuti vĂ”imalikud tĂ€iendavad omadused.

Selle eesmÀrgi saavutamiseks loome liidese teegi.

add_library(mylib INTERFACE)

Seome pealkirjad meie liidese teegiga.

Kaasaegne, trendikas ja nooruslik CMake'i kasutamine eeldab, et pealkirjad, omadused jne edastatakse lĂ€bi ĂŒheainsa sihtmĂ€rk. target_link_libraries(target PRIVATE dependency), ja kĂ”ik pealkirjad, mis on seotud sihtmĂ€rgiga dependency, on saadaval sihtmĂ€rgi kuuluvatele lĂ€htekoodidele target. Ja ei ole vaja mingit [target_]include_directories. See this demonstrated below during the breakdown CMake script for unit tests.

It is also worth noting the so-called generator expressions: $.

This command associates the necessary headers with our interface library, and if our library is linked to any target within the same CMake hierarchy, it will be associated with headers from the directory ${CMAKE_CURRENT_SOURCE_DIR}/include, and if our library is installed in the system and linked in another project using the command find_package, it will be associated with headers from the directory include relative to the installation directory.

target_include_directories(mylib INTERFACE
    $
    $
)

Set the language standard. Of course, the latest one. Moreover, we not only include the standard but also extend it to those who will use our library. This is achieved by the installed property having the category INTERFACE (vt. the target_compile_features command).

target_compile_features(mylib INTERFACE cxx_std_17)

Create an alias for our library. For aesthetics, it will be in a special "namespace". This will be useful when different modules appear in our library, and we want to connect them independently of each other. As in Boost, for example.

add_library(Mylib::mylib ALIAS mylib)

Paigaldamine

Installing our headers to the system. It's simple. We specify that the folder with all the headers should go to the directory include relative to the installation location.

install(DIRECTORY include/mylib DESTINATION include)

Next, we inform the build system that we want to be able to call the command in external projects find_package(Mylib) and obtain the target Mylib::mylib.

install(TARGETS mylib EXPORT MylibConfig)
install(EXPORT MylibConfig NAMESPACE Mylib:: DESTINATION share/Mylib/cmake)

The next spell should be understood this way. When in an external project we call the command find_package(Mylib 1.2.3 REQUIRED), and the actual version of the installed library turns out to be incompatible with the version 1.2.3, CMake will automatically generate an error. This means there is no need to manually track versions.

include(CMakePackageConfigHelpers)
write_basic_package_version_file("${PROJECT_BINARY_DIR}/MylibConfigVersion.cmake"
    VERSION
        ${PROJECT_VERSION}
    COMPATIBILITY
        AnyNewerVersion
)
install(FILES "${PROJECT_BINARY_DIR}/MylibConfigVersion.cmake" DESTINATION share/Mylib/cmake)

Testid

If the tests are explicitly disabled with the corresponding option vĂ”i meie projekt on alamprojekt, see tĂ€hendab, et see on ĂŒhendatud teise CMake projekti kaudu kĂ€su add_subdirectory, me ei liigu hierarhias edasi ja skript, milles on kirjeldatud kĂ€sud testide genereerimiseks ja kĂ€ivitamiseks, lihtsalt ei kĂ€ivitu.

if(NOT MYLIB_TESTING)
    message(STATUS "Mylibi projekti testimine on keelatud")
elseif(IS_SUBPROJECT)
    message(STATUS "Mylibi ei testita alammodulina")
else()
    add_subdirectory(test)
endif()

Dokumentatsioon

Dokumentatsiooni ei genereerita ka alamprojekti puhul.

if(NOT IS_SUBPROJECT)
    add_subdirectory(doc)
endif()

Online-keskkond

Sarnaselt ei ole alamprojekti juhul ka veebiliivakaste.

if(NOT IS_SUBPROJECT)
    add_subdirectory(online)
endif()

Testide skript (test/CMakeLists.txt)

Testimine

Esiteks otsime paketti vajaliku testimisraamistiku jaoks (asendage oma lemmikuga).

find_package(doctest 2.3.3 REQUIRED)

Loome oma kÀivitatava faili testide jaoks. Tavaline on, et kÀivitatavasse binaari lisan ainult faili, kus on funktsioon main.

add_executable(mylib-unit-tests test_main.cpp)

Ja failid, kus on kirja pandud testid, lisan hiljem. Kuid nii teha ei ole vajalik.

target_sources(mylib-unit-tests PRIVATE mylib/myfeature.cpp)

Seome sĂ”ltuvused. Pange tĂ€hele, et meie binaariga seostasime ainult vajalikud CMake eesmĂ€rgid ega kutsunud ĂŒles kĂ€sku target_include_directories. Testimisraamistiku pealkirjad ja meie Mylib::mylib, samuti kogumise parameetrid (meie juhul on see C++ keele standard) lĂ€ksid koos nende eesmĂ€rkidega lĂ€bi.

target_link_libraries(mylib-unit-tests
    PRIVATE
        Mylib::mylib
        doctest::doctest
)

LÔpuks loome vale eesmÀrgi, mille "kogumine" on vÔrdne testide kÀitamisega, ja lisame selle doelame standardkogumisse (seda juhib atribuut , vÔi). See tÀhendab, et vaikimisi kogumine kÀivitab testide kÀitamist, seega me kunagi ei unusta neid kÀivitada.

add_custom_target(check ALL COMMAND mylib-unit-tests)

Katvus

SeejĂ€rel aktiveerime koodikatvuse mÔÔtmise, kui vastav valik on mÀÀratud. SĂŒgavale detailidesse ei lĂ€he, kuna need kuuluvad rohkem katvuse mÔÔtamisseadmesse kui CMake'ile. Oluline on mĂ€rkida ainult, et tulemuste pĂ”hjal luuakse eesmĂ€rk coverage, millega on mugav kĂ€ivitada katvuse mÔÔtmine.

find_program(GCOVR_EXECUTABLE gcovr)
if(MYLIB_COVERAGE AND GCOVR_EXECUTABLE)
    message(STATUS "Koodikatse katvuse mÔÔtmine on sisse lĂŒlitatud")

    target_compile_options(mylib-unit-tests PRIVATE --coverage)
    target_link_libraries(mylib-unit-tests PRIVATE gcov)

    add_custom_target(coverage
        COMMAND
            ${GCOVR_EXECUTABLE}
                --root=${PROJECT_SOURCE_DIR}\/include\/ 
                --object-directory=${CMAKE_CURRENT_BINARY_DIR}
        DEPENDS
            check
    )
elseif(MYLIB_COVERAGE AND NOT GCOVR_EXECUTABLE)
    set(MYLIB_COVERAGE OFF)
    message(WARNING "Koodikatse katvuse mÔÔtmiseks on vajalik programm gcovr")
endif()

Dokumentatsiooni skript (doc/CMakeLists.txt)

Leitud Doxygen.

find_package(Doxygen)

Edasi kontrollime, kas kasutaja on mÀÀranud keelemuutuja. Kui jah, siis ei puutu sellesse, kui ei, siis vĂ”tame vene. SeejĂ€rel konfigureerime Doxygen sĂŒsteemi failid. KĂ”ik vajalikud muutujad, sealhulgas keel, saadakse konfiguratsiooni kĂ€igus (vt. komando configure_file).

Peale seda loome sihiks doc, mis kĂ€ivitab dokumentatsiooni genereerimise. Kuna dokumentatsiooni genereerimine ei ole arenduse kĂ€igus kĂ”ige tĂ€htsam vajadus, siis ei ole siht vaikimisi sisse lĂŒlitatud, see tuleb kĂ€ivitada selgelt.

if (Doxygen_FOUND)
    if (NOT MYLIB_DOXYGEN_LANGUAGE)
        set(MYLIB_DOXYGEN_LANGUAGE Vene)
    endif()
    message(STATUS "Doxygeni dokumentatsioon genereeritakse keeles ${MYLIB_DOXYGEN_LANGUAGE}")
    configure_file(Doxyfile.in Doxyfile)
    add_custom_target(doc COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}\/Doxyfile)
endif ()

Online-keskkonna skript (online/CMakeLists.txt)

Siin leiame kolmanda Python'i ja loome sihiks wandbox, mis genereerib pÀringu, mis vastab teenuse API-le Wandbox, ja saadab selle. Vastuseks tulevad valmis liivakasti link.

find_program(PYTHON3_EXECUTABLE python3)
if(PYTHON3_EXECUTABLE)
    set(WANDBOX_URL "https:\/\/wandbox.org\/api\/compile.json")

    add_custom_target(wandbox
        COMMAND
            ${PYTHON3_EXECUTABLE} wandbox.py mylib-example.cpp "${PROJECT_SOURCE_DIR}" include |
            curl -H "Content-type: application\/json" -d @- ${WANDBOX_URL}
        WORKING_DIRECTORY
            ${CMAKE_CURRENT_SOURCE_DIR}
        DEPENDS
            mylib-unit-tests
    )
else()
    message(WARNING "Veebiliivakasti loomiseks on vajalik Python 3 interpreteur")
endif()

Projekt vÀljaspool

NĂŒĂŒd vaatame, kuidas seda kĂ”ike kasutada.

Kogumine

Selle projekti koostamine, nagu ka iga teise CMake sĂŒsteemi projekti puhul, koosneb kahest etapist:

Genereerimine

cmake -S tee\/kallid -B tee\/kogumiskohta [valikud ...]

Kui ĂŒlemine kĂ€sk ei toiminud vanema CMake versiooni tĂ”ttu, proovige jĂ€tta vĂ€lja -S:

cmake tee\/kallid -B tee\/kogumiskohta [valikud ...]

Rohkem valikute kohta.

Projekti koostamine

cmake --build tee\/kogumiskohta [--target siht]

Rohkem koostamis eesmÀrkide kohta.

Valikud

MYLIB_COVERAGE

cmake -S ... -B ... -DMYLIB_COVERAGE=ON [teised valikud ...]

LĂŒlitab sihi sisse coverage, mille on vĂ”imalik kĂ€ivitada koodikatvuse mÔÔtmine testide kaudu.

MYLIB_TESTING

cmake -S ... -B ... -DMYLIB_TESTING=OFF [muud seaded ...]

Pakub vĂ”imalusi moodulite testimise ja eesmĂ€rgi vĂ€ljalĂŒlitamiseks. check. Selle tulemusena lĂŒlitatakse koodikatvuse mÔÔtmine testide kaudu vĂ€lja (vt. MYLIB_COVERAGE).

Samuti lĂŒlitatakse testimine automaatselt vĂ€lja, kui projekt lisatakse teise projekti alaprojektina kĂ€su abil add_subdirectory.

MYLIB_DOXYGEN_LANGUAGE

cmake -S ... -B ... -DMYLIB_DOXYGEN_LANGUAGE=English [muud seaded ...]

Vahetab dokumentatsiooni keele, mille genereerib eesmĂ€rk doc mugandatuks. Saadaval olevate keelte loetelu leiate Doxygen sĂŒsteemi veebisaidilt..

Vaikimisi on keel vene.

Kogumise eesmÀrgid

Vaikimisi

cmake --build path/to/build/directory
cmake --build path/to/build/directory --target all

Kui eesmĂ€rki ei ole mÀÀratud (mis on samavÀÀrne eesmĂ€rgiga all), kogub kĂ”ik, mis on vĂ”imalik, ning kutsub ĂŒles eesmĂ€rki. check.

mylib-unit-tests

cmake --build path/to/build/directory --target mylib-unit-tests

Kompileerib moodulitestide. Vaikimisi on see sisse lĂŒlitatud.

check

cmake --build tee/ehituskausta --target check

KĂ€ivitab koostatud (kogub, kui veel mitte) moodulitestid. Vaikimisi on see sisse lĂŒlitatud.

Vaata ka mylib-unit-tests.

coverage

cmake --build tee/ehituskausta --target coverage

AnalĂŒĂŒsib kĂ€ivitatud (kĂ€ivitab, kui veel mitte) moodulitestid koodikatvuse osas testimise ajal programmi gcovr.

Katvuse vÀljund nÀeb vÀlja selline:

------------------------------------------------------------------------------
                           GCC Koodikatvuse Aruanne
Kaust: /path/to/cmakecpptemplate/include/
------------------------------------------------------------------------------
Fail                                       Read       TĂ€itmine  Katvus   Puuduvad
------------------------------------------------------------------------------
mylib/myfeature.hpp                            2       2   100%   
------------------------------------------------------------------------------
TOTAL                                          2       2   100%
------------------------------------------------------------------------------

EesmĂ€rk on saadaval ainult, kui valik on sisse lĂŒlitatud. MYLIB_COVERAGE.

Vaata ka check.

doc

cmake --build tee/ehituskausta --target doc

KĂ€ivitab dokumentatsiooni genereerimise koodi jaoks Doxygen sĂŒsteemi abil. Doxygen.

wandbox

cmake --build tee/ehituskausta --target wandbox

Teenuse vastus nÀeb vÀlja selline:

{
    "permlink" :    "QElvxuMzHgL9fqci",
    "status" :  "0",
    "url" : "https://wandbox.org/permlink/QElvxuMzHgL9fqci"
}

Selleks kasutatakse teenust Wandbox. Ma ei tea, kui paindlikud nende serverid on, kuid ma arvan, et seda vÔimalust ei tasu kuritarvitada.

NĂ€ited

Projekti ĂŒlesehitus tĂ”rkeotsingu reĆŸiimis koodikatvuse mÔÔtmisega.

cmake -S tee/komplekt/dokumendid -B tee/ehituskausta -DCMAKE_BUILD_TYPE=Debug -DMYLIB_COVERAGE=ON
cmake --build tee/ehituskausta --target coverage --parallel 16

Projekti paearendust ja testimist

cmake -S tee/koodifailid -B tee/ehituskaust -DMYLIB_TESTING=OFF -DCMAKE_INSTALL_PREFIX=tee/paigalduskaust
cmake --build tee/ehituskaust --target install

Ehitus vabastamisreĆŸiimis mÀÀratud kompilaatoriga

cmake -S tee/koodifailid -B tee/ehituskaust -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=g++-8 -DCMAKE_PREFIX_PATH=tee/kaust/kuhu/paigaldatud/sÔltuvused
cmake --build tee/ehituskaust --parallel 4

Dokumentatsiooni genereerimine inglise keeles

cmake -S tee/koodifailid -B tee/ehituskaust -DCMAKE_BUILD_TYPE=Release -DMYLIB_DOXYGEN_LANGUAGE=English
cmake --build tee/ehituskaust --target doc

Tööriistad

  1. CMake 3.13

    Tegelikult vajatakse CMake versiooni 3.13 ainult teatud konsolikomandide kĂ€ivitamiseks, mis on kirjeldatud antud juhendis. CMake-skriptide sĂŒntaksiks piisab versioonist 3.8, kui genereerimist kutsuda vĂ€lja muude viiside kaudu.

  2. Testimise raamatukogu doctest

    Testimist saab keelduda (vt. valikut MYLIB_TESTING).

  3. Doxygen

    Dokumentatsioonikeele vahetamiseks on olemas valik MYLIB_DOXYGEN_LANGUAGE.

  4. TÔlkija YP Python 3

    Automaatseks genereerimiseks veebipesakond.

Staatiline analĂŒĂŒs

CMake ja paar head tööriista vĂ”ivad hĂ”lpsasti tagada staatilise analĂŒĂŒsi minimaalse vaevaga.

Cppcheck

CMake'is on sisseehitatud tugi staatilise analĂŒĂŒsi tööriistale Cppcheck.

Selleks tuleb kasutada valikut CMAKE_CXX_CPPCHECK:

cmake -S tee/koodifailid -B tee/ehituskaust -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_CPPCHECK="cppcheck;--enable=all;-Itee/koodifailid/include"

PĂ€rast seda kĂ€ivitatakse staatiline analĂŒĂŒs automaatselt iga kord, kui lĂ€htefaile kompileeritakse ja uuesti kompileeritakse. Ei ole vaja midagi lisada.

Clang

Imekauni tööriista abil scan-build saab samuti staatilist analĂŒĂŒsi kiiresti kĂ€ivitada:

scan-build cmake -S tee/koodifailid -B tee/ehituskaust -DCMAKE_BUILD_TYPE=Debug
scan-build cmake --build tee/ehituskaust

Siin on vastupidiselt Cppcheck'ile vajalik igakordselt kÀivitada ehitus scan-build.

EessÔna

CMake on vĂ€ga vĂ”imas ja paindlik sĂŒsteem, mis vĂ”imaldab realiseerida igasugust funktsionaalsust. Ja kuigi sĂŒntaks jĂ€tab vahel soovida, ei ole see nii hirmus, kui teda maalitakse. Kasutage CMake ehitussĂŒsteemi ĂŒhiskonna hĂŒvanguks ja enda terviseks.

→ Laadi alla projekti mall

Allikas: habr.com

Osta usaldusvÀÀrne veebimajutus DDoS-kaitsega veebisaitidele, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne veebimajutus DDoS-kaitsega veebisaitidele, VPS VDS serverid - ProHoster