CMake og C++ eru bræður að eilífu

CMake og C++ eru bræður að eilífu

Á meðan á þróun stendur finnst mér gaman að breyta þýðendum, smíða stillingar, ósjálfstæðisútgáfur, framkvæma kyrrstöðugreiningar, mæla frammistöðu, safna umfangi, búa til skjöl osfrv. Og ég elska virkilega CMake vegna þess að það gerir mér kleift að gera allt sem ég vil.

Margir gagnrýna CMake, og oft verðskuldað, en ef þú horfir á það er ekki allt svo slæmt, og nýlega alls ekki slæmt, og þróunarstefnan er nokkuð jákvæð.

Í þessari athugasemd vil ég segja þér hvernig á að skipuleggja hausbókasafn í C++ í CMake kerfinu til að fá eftirfarandi virkni:

  1. Samkoma;
  2. Sjálfvirk próf;
  3. Kóðaþekjumæling;
  4. Uppsetning;
  5. Sjálfvirk skjöl;
  6. Sandkassa kynslóð á netinu;
  7. Statísk greining.

Allir sem þegar skilja kosti og C-gerð geta einfaldlega Sækja sniðmát fyrir verkefni og byrjaðu að nota það.


efni

  1. Verkefni innan frá
    1. Uppbygging verkefnis
    2. Aðal CMake skrá (./CMakeLists.txt)
      1. Upplýsingar um verkefni
      2. Verkefnavalkostir
      3. Safnvalkostir
      4. Megintilgangur
      5. Uppsetning
      6. Próf
      7. Skjöl
      8. Sandkassi á netinu
    3. Prófunarforskrift (test/CMakeLists.txt)
      1. Prófun
      2. Umfjöllun
    4. Forskrift fyrir skjöl (doc/CMakeLists.txt)
    5. Forskrift fyrir sandkassa á netinu (online/CMakeLists.txt)
  2. Verkefni úti
    1. Þing
      1. Kynslóð
      2. Þing
    2. Valkostir
      1. MYLIB_COVERAGE
      2. MYLIB_TESTING
      3. MYLIB_DOXYGEN_LANGUAGE
    3. Samkoma markmið
      1. Sjálfgefið
      2. mylib-einingapróf
      3. athuga
      4. umfjöllun
      5. doc
      6. sprotabox
    4. dæmi
  3. Verkfæri
  4. Statísk greining
  5. Eftirsögn

Verkefni innan frá

Uppbygging verkefnis

.
├── 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

Við munum aðallega tala um hvernig á að skipuleggja CMake forskriftir, svo þau verða rædd ítarlega. Hver sem er getur skoðað restina af skránum beint á sniðmátsverkefnissíðunni.

Aðal CMake skrá (./CMakeLists.txt)

Upplýsingar um verkefni

Fyrst af öllu þarftu að biðja um nauðsynlega útgáfu af CMake kerfinu. CMake er að þróast, skipanaundirskriftir og hegðun við mismunandi aðstæður eru að breytast. Til þess að CMake skilji strax hvað við viljum fá úr því þurfum við strax að skrá kröfur okkar um það.

cmake_minimum_required(VERSION 3.13)

Síðan munum við tilnefna verkefnið okkar, nafn þess, útgáfu, tungumál sem notuð eru osfrv. (sjá. команду project).

Í þessu tilviki tilgreinum við tungumálið CXX (og þetta þýðir C++) þannig að CMake þvingar ekki og leitar að C tungumálaþýðanda (sjálfgefið inniheldur CMake tvö tungumál: C og C++).

project(Mylib VERSION 1.0 LANGUAGES CXX)

Hér getur þú strax athugað hvort verkefnið okkar sé innifalið í öðru verkefni sem undirverkefni. Þetta mun hjálpa mikið í framtíðinni.

get_directory_property(IS_SUBPROJECT PARENT_DIRECTORY)

Verkefnavalkostir

Við munum bjóða upp á tvo valkosti.

Fyrsti kosturinn er MYLIB_TESTING — til að slökkva á einingaprófum. Þetta gæti verið nauðsynlegt ef við erum viss um að allt sé í lagi með prófunum, en við viljum td aðeins setja upp eða pakka verkefninu okkar. Eða verkefnið okkar er innifalið sem undirverkefni - í þessu tilviki hefur notandi verkefnisins ekki áhuga á að keyra prófin okkar. Þú prófar ekki ósjálfstæðin sem þú notar, er það?

option(MYLIB_TESTING "Включить модульное тестирование" ON)

Að auki munum við gera sérstakan valkost MYLIB_COVERAGE til að mæla umfang kóða með prófum, en það mun krefjast viðbótarverkfæra, svo það verður að vera virkt sérstaklega.

option(MYLIB_COVERAGE "Включить измерение покрытия кода тестами" OFF)

Safnvalkostir

Auðvitað erum við flottir plús forritarar, svo við viljum fá hámarksstig greiningatíma greiningar frá þýðandanum. Ekki ein einasta mús mun renna í gegn.

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
)

Við munum einnig gera viðbætur óvirkar til að uppfylla C++ tungumálastaðalinn að fullu. Þeir eru sjálfgefið virkir í CMake.

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

Megintilgangur

Bókasafnið okkar samanstendur aðeins af hausskrám, sem þýðir að við erum ekki með neinn útblástur í formi kyrrstæðra eða kraftmikilla bókasöfna. Á hinn bóginn, til þess að geta notað bókasafnið okkar utanaðkomandi, þarf að setja það upp, það þarf að vera greinanlegt í kerfinu og tengt við verkefnið þitt, og á sama tíma þessir sömu hausar, sem og hugsanlega einhverjir til viðbótar, fylgja því eignir.

Í þessu skyni búum við til viðmótasafn.

add_library(mylib INTERFACE)

Við bindum hausa við viðmótasafnið okkar.

Nútímaleg, smart notkun ungmenna á CMake felur í sér að hausar, eiginleikar osfrv. send í gegnum eitt skotmark. Svo það er nóg að segja target_link_libraries(target PRIVATE dependency), og allir hausar sem tengjast markinu dependency, verður aðgengilegt fyrir heimildir sem tilheyra skotmarkinu target. Og þú þarft enga [target_]include_directories. Þetta verður sýnt hér að neðan í greiningunni CGerðu handrit fyrir einingapróf.

Það er líka þess virði að borga eftirtekt til svokallaða. выражения-генераторы: $<...>.

Þessi skipun tengir hausana sem við þurfum við viðmótasafnið okkar og ef bókasafnið okkar er tengt einhverju skotmarki innan sama CMake stigveldis, þá verða hausarnir úr möppunni tengdir því ${CMAKE_CURRENT_SOURCE_DIR}/include, og ef bókasafnið okkar er uppsett á kerfinu og tengt öðru verkefni með skipuninni find_package, þá verða hausar úr möppunni tengdir henni include miðað við uppsetningarskrána.

target_include_directories(mylib INTERFACE
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>
)

Setjum tungumálastaðal. Auðvitað sá allra síðasti. Á sama tíma látum við ekki aðeins staðalinn fylgja með heldur víkjum hann einnig út til þeirra sem munu nota bókasafnið okkar. Þetta er náð vegna þess að fasteignin hefur flokk INTERFACE (sjá target_compile_features skipun).

target_compile_features(mylib INTERFACE cxx_std_17)

Við skulum búa til samnefni fyrir bókasafnið okkar. Þar að auki, fyrir fegurð, verður það í sérstöku „nafnarými“. Þetta mun vera gagnlegt þegar mismunandi einingar birtast í bókasafninu okkar og við förum að tengja þær óháð hvor annarri. Eins og til dæmis í Busta.

add_library(Mylib::mylib ALIAS mylib)

Uppsetning

Að setja hausana okkar inn í kerfið. Hér er allt einfalt. Við segjum að mappan með öllum hausunum ætti að fara inn í möppuna include miðað við uppsetningarstaðinn.

install(DIRECTORY include/mylib DESTINATION include)

Næst tilkynnum við byggingarkerfinu að við viljum geta kallað skipunina í verkefnum þriðja aðila find_package(Mylib) og ná í mark Mylib::mylib.

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

Næsta álög ætti að skilja þannig. Þegar við erum í þriðja aðila verkefni köllum við skipunina find_package(Mylib 1.2.3 REQUIRED), og raunveruleg útgáfa af uppsettu bókasafni mun vera ósamrýmanleg útgáfunni 1.2.3CMake mun sjálfkrafa búa til villu. Það er, þú þarft ekki að fylgjast með útgáfum handvirkt.

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)

Próf

Ef próf eru slökkt sérstaklega með því að nota samsvarandi valmöguleika eða verkefnið okkar er undirverkefni, það er, það er tengt öðru CMake verkefni með skipuninni add_subdirectory, við förum ekki lengra eftir stigveldinu og skriftin, sem lýsir skipunum til að búa til og keyra próf, keyrir einfaldlega ekki.

if(NOT MYLIB_TESTING)
    message(STATUS "Тестирование проекта Mylib выключено")
elseif(IS_SUBPROJECT)
    message(STATUS "Mylib не тестируется в режиме подмодуля")
else()
    add_subdirectory(test)
endif()

Skjöl

Gögn verða heldur ekki til þegar um undirverkefni er að ræða.

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

Sandkassi á netinu

Sömuleiðis mun undirverkefnið ekki hafa sandkassa á netinu heldur.

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

Prófunarforskrift (test/CMakeLists.txt)

Prófun

Fyrst af öllu finnum við pakka með nauðsynlegum prófunarramma (skipta út fyrir uppáhalds þinn).

find_package(doctest 2.3.3 REQUIRED)

Við skulum búa til keyrsluskrána okkar með prófum. Venjulega bæti ég beint við executable binary aðeins skránni sem mun innihalda aðgerðina main.

add_executable(mylib-unit-tests test_main.cpp)

Og ég bæti við skrám þar sem prófunum sjálfum er lýst síðar. En þú þarft ekki að gera þetta.

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

Við tengjum ósjálfstæði. Vinsamlegast athugaðu að við tengdum aðeins CMake markmiðin sem við þurftum við tvöfaldan okkar og kölluðum ekki skipunina target_include_directories. Fyrirsagnir úr prófunarrammanum og frá okkar Mylib::mylib, sem og byggingarfæribreytur (í okkar tilfelli er þetta C++ tungumálastaðallinn) komust í gegn með þessum markmiðum.

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

Að lokum búum við til dummy-markmið þar sem „byggingin“ jafngildir því að keyra prófanir, og bætum þessu markmiði við sjálfgefna smíðina (eigindið er ábyrgt fyrir þessu ALL). Þetta þýðir að sjálfgefna byggingin kveikir á prófunum til að keyra, sem þýðir að við munum aldrei gleyma að keyra þau.

add_custom_target(check ALL COMMAND mylib-unit-tests)

Umfjöllun

Næst virkjum við kóðaþekjumælingu ef viðeigandi valkostur er tilgreindur. Ég mun ekki fara út í smáatriði vegna þess að þau tengjast meira tæki til að mæla umfang en CMake. Það er aðeins mikilvægt að hafa í huga að miðað við niðurstöðurnar verður markmið búið til coverage, sem þægilegt er að byrja að mæla þekju með.

find_program(GCOVR_EXECUTABLE gcovr)
if(MYLIB_COVERAGE AND GCOVR_EXECUTABLE)
    message(STATUS "Измерение покрытия кода тестами включено")

    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 "Для замеров покрытия кода тестами требуется программа gcovr")
endif()

Forskrift fyrir skjöl (doc/CMakeLists.txt)

Fann Doxygen.

find_package(Doxygen)

Næst athugum við hvort notandinn hafi stillt tungumálabreytuna. Ef já, þá snertum við það ekki, ef ekki, þá tökum við rússnesku. Síðan stillum við Doxygen kerfisskrárnar. Allar nauðsynlegar breytur, þar á meðal tungumálið, fara þangað meðan á stillingarferlinu stendur (sjá. команду configure_file).

Þá sköpum við okkur markmið doc, sem mun byrja að búa til skjöl. Þar sem að búa til skjöl er ekki stærsta þörfin í þróunarferlinu verður markmiðið ekki sjálfgefið virkt; það verður að vera ræst sérstaklega.

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 ()

Forskrift fyrir sandkassa á netinu (online/CMakeLists.txt)

Hér finnum við þriðja Python og búum til skotmark wandbox, sem býr til beiðni sem samsvarar þjónustu API Kassi, og sendir hann burt. Svarið kemur með hlekk á fullunna sandkassann.

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 "Для создания онлайн-песочницы требуется интерпретатор ЯП python 3-й версии")
endif()

Verkefni úti

Nú skulum við skoða hvernig á að nota allt þetta.

Þing

Að byggja þetta verkefni, eins og öll önnur verkefni á CMake byggingarkerfinu, samanstendur af tveimur áföngum:

Kynslóð

cmake -S путь/к/исходникам -B путь/к/сборочной/директории [опции ...]

Ef skipunin hér að ofan virkaði ekki vegna gamallar útgáfu af CMake, reyndu að sleppa því -S:

cmake путь/к/исходникам -B путь/к/сборочной/директории [опции ...]

Meira um valkosti.

Byggja verkefnið

cmake --build путь/к/сборочной/директории [--target target]

Meira um samsetningarmarkmið.

Valkostir

MYLIB_COVERAGE

cmake -S ... -B ... -DMYLIB_COVERAGE=ON [прочие опции ...]

Inniheldur skotmark coverage, sem þú getur byrjað að mæla umfang kóða með prófum.

MYLIB_TESTING

cmake -S ... -B ... -DMYLIB_TESTING=OFF [прочие опции ...]

Veitir getu til að slökkva á einingarprófun og miða check. Fyrir vikið er slökkt á mælingu á kóðaþekju með prófum (sjá. MYLIB_COVERAGE).

Prófun er einnig sjálfkrafa óvirk ef verkefnið er tengt öðru verkefni sem undirverkefni með skipuninni add_subdirectory.

MYLIB_DOXYGEN_LANGUAGE

cmake -S ... -B ... -DMYLIB_DOXYGEN_LANGUAGE=English [прочие опции ...]

Skiptir um tungumál skjalanna sem markið býr til doc til hins gefna. Fyrir lista yfir tiltæk tungumál, sjá Vefsíða Doxygen kerfisins.

Rússneska er sjálfgefið virkt.

Samkoma markmið

Sjálfgefið

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

Ef markmiðið er ekki tilgreint (sem jafngildir markmiðinu all), safnar öllu sem það getur, og kallar líka á markið check.

mylib-einingapróf

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

Tekur saman einingapróf. Sjálfgefið virkt.

athuga

cmake --build путь/к/сборочной/директории --target check

Keyrir söfnuð (söfnuð, ef ekki þegar) einingaprófin. Sjálfgefið virkt.

Sjá einnig mylib-unit-tests.

umfjöllun

cmake --build путь/к/сборочной/директории --target coverage

Greinir keyrandi (keyrir, ef ekki þegar) einingarprófanir fyrir kóðaþekju með prófunum með því að nota forritið gcovr.

Húðunarútblástur mun líta eitthvað svona út:

------------------------------------------------------------------------------
                           GCC Code Coverage Report
Directory: /path/to/cmakecpptemplate/include/
------------------------------------------------------------------------------
File                                       Lines    Exec  Cover   Missing
------------------------------------------------------------------------------
mylib/myfeature.hpp                            2       2   100%   
------------------------------------------------------------------------------
TOTAL                                          2       2   100%
------------------------------------------------------------------------------

Markmiðið er aðeins tiltækt þegar valkosturinn er virkur MYLIB_COVERAGE.

Sjá einnig check.

doc

cmake --build путь/к/сборочной/директории --target doc

Byrjar að búa til kóðaskjöl með því að nota kerfið doxygen.

sprotabox

cmake --build путь/к/сборочной/директории --target wandbox

Svarið frá þjónustunni lítur einhvern veginn svona út:

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

Þjónustan er notuð til þess Kassi. Ég veit ekki hversu sveigjanlegir netþjónar þeirra eru, en ég held að það ætti ekki að misnota þetta tækifæri.

dæmi

Byggðu verkefnið í villuleitarham með þekjumælingu

cmake -S путь/к/исходникам -B путь/к/сборочной/директории -DCMAKE_BUILD_TYPE=Debug -DMYLIB_COVERAGE=ON
cmake --build путь/к/сборочной/директории --target coverage --parallel 16

Uppsetning verkefnis án forsamsetningar og prófunar

cmake -S путь/к/исходникам -B путь/к/сборочной/директории -DMYLIB_TESTING=OFF -DCMAKE_INSTALL_PREFIX=путь/к/установойной/директории
cmake --build путь/к/сборочной/директории --target install

Byggja í útgáfuham með tilteknum þýðanda

cmake -S путь/к/исходникам -B путь/к/сборочной/директории -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=g++-8 -DCMAKE_PREFIX_PATH=путь/к/директории/куда/установлены/зависимости
cmake --build путь/к/сборочной/директории --parallel 4

Búa til skjöl á ensku

cmake -S путь/к/исходникам -B путь/к/сборочной/директории -DCMAKE_BUILD_TYPE=Release -DMYLIB_DOXYGEN_LANGUAGE=English
cmake --build путь/к/сборочной/директории --target doc

Verkfæri

  1. CMake 3.13

    Reyndar er CMake útgáfa 3.13 aðeins nauðsynleg til að keyra nokkrar af stjórnborðsskipunum sem lýst er í þessari hjálp. Frá sjónarhóli setningafræði CMake forskrifta dugar útgáfa 3.8 ef kynslóð er kölluð á annan hátt.

  2. Prófa bókasafn doktorspróf

    Hægt er að slökkva á prófun (sjá опцию MYLIB_TESTING).

  3. doxygen

    Til að skipta um tungumál sem skjölin verða búin til á er valkostur MYLIB_DOXYGEN_LANGUAGE.

  4. Tungumálatúlkur Python 3

    Fyrir sjálfvirka kynslóð sandkassa á netinu.

Statísk greining

Með CMake og nokkrum góðum verkfærum geturðu veitt kyrrstöðugreiningu með lágmarks fyrirhöfn.

Cppcheck

CMake hefur innbyggðan stuðning fyrir kyrrstöðugreiningartæki Cppcheck.

Til að gera þetta þarftu að nota valkostinn CMAKE_CXX_CPPCHECK:

cmake -S путь/к/исходникам -B путь/к/сборочной/директории -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_CPPCHECK="cppcheck;--enable=all;-Iпуть/к/исходникам/include"

Eftir þetta verður kyrrstöðugreining ræst sjálfkrafa í hvert skipti sem heimildin er sett saman og endursamsett. Það er engin þörf á að gera neitt til viðbótar.

Klangur

Með hjálp frábærs tóls scan-build Þú getur líka keyrt kyrrstöðugreiningu á skömmum tíma:

scan-build cmake -S путь/к/исходникам -B путь/к/сборочной/директории -DCMAKE_BUILD_TYPE=Debug
scan-build cmake --build путь/к/сборочной/директории

Hér, ólíkt tilfellinu með Cppcheck, þarftu að keyra bygginguna í hvert skipti scan-build.

Eftirsögn

CMake er mjög öflugt og sveigjanlegt kerfi sem gerir þér kleift að innleiða virkni fyrir hvert bragð og lit. Og þó setningafræðin skilji stundum eftir sig miklu, þá er djöfullinn samt ekki eins hræðilegur og hann er málaður. Notaðu CMake smíðakerfið í þágu samfélagsins og heilsunnar.

Sækja sniðmát fyrir verkefni

Heimild: www.habr.com

Bæta við athugasemd