CMake jeung C ++ duduluran salawasna

CMake jeung C ++ duduluran salawasna

Salila pamekaran, kuring resep ngarobih kompiler, ngawangun modeu, versi dependensi, ngalakukeun analisa statik, ngukur kinerja, ngumpulkeun sinyalna, ngahasilkeun dokuméntasi, jsb. Sareng kuring resep pisan ka CMake sabab ngamungkinkeun kuring pikeun ngalakukeun sagala anu dipikahoyong.

Seueur jalma anu nyempad CMake, sareng sering pantes kitu, tapi upami anjeun ningali éta, henteu sadayana parah, sareng ayeuna-ayeuna. teu goréng pisan, sarta arah ngembangkeun rada positif.

Dina catetan ieu, abdi hoyong ngabejaan Anjeun kumaha ngan saukur ngatur perpustakaan lulugu dina C ++ dina sistem CMake pikeun meunangkeun pungsionalitas handap:

  1. Majelis;
  2. tés Autorun;
  3. Pangukuran cakupan kode;
  4. Pamasangan;
  5. Dokuméntasi otomatis;
  6. Generasi sandbox online;
  7. Analisis statik.

Saha waé anu parantos ngartos kauntungan sareng C-make tiasa waé ngundeur template proyék tur mimitian nganggo eta.


eusi

  1. Proyék ti jero
    1. Struktur proyék
    2. File CMake utama (./CMakeLists.txt)
      1. Inpo proyék
      2. Pilihan Proyék
      3. Pilihan kompilasi
      4. Tujuanana primér
      5. setting
      6. Tés
      7. Dokuméntasi
      8. Sandbox online
    3. Skrip tés (test/CMakeLists.txt)
      1. Tés
      2. Покрытие
    4. Skrip pikeun dokuméntasi (doc/CMakeLists.txt)
    5. Skrip pikeun sandbox online (online/CMakeLists.txt)
  2. Proyék luar
    1. Majelis
      1. turunan
      2. Majelis
    2. Pilihan
      1. MYLIB_COVERAGE
      2. MYLIB_TESTING
      3. MYLIB_DOXYGEN_LANGUAGE
    3. Sasaran Majelis
      1. sacara standar
      2. mylib-unit-tés
      3. cek
      4. sinyalna
      5. doc
      6. kotak wand
    4. conto
  3. instrumen
  4. Analisis statik
  5. afterword

Proyék ti jero

Struktur proyék

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

Urang utamana bakal ngobrol ngeunaan kumaha carana ngatur skrip CMake, ngarah bakal dibahas di jéntré. Saha waé tiasa ningali sesa file sacara langsung dina kaca proyék template.

File CMake utama (./CMakeLists.txt)

Inpo proyék

Anu mimiti, anjeun kedah nyuhunkeun versi anu diperyogikeun tina sistem CMake. CMake ngembang, tanda tangan paréntah sareng paripolah dina kaayaan anu béda-béda robih. Supados CMake langsung ngartos naon anu urang pikahoyong tina éta, urang kedah langsung ngarékam sarat pikeun éta.

cmake_minimum_required(VERSION 3.13)

Teras kami bakal nunjuk proyék kami, namina, versi, basa anu dianggo, sareng sajabana (tingali. команду project).

Dina hal ieu kami nunjukkeun basa CXX (sareng ieu hartosna C ++) supados CMake henteu galur sareng milarian kompiler basa C (sacara standar, CMake kalebet dua basa: C sareng C ++).

project(Mylib VERSION 1.0 LANGUAGES CXX)

Di dieu anjeun tiasa langsung pariksa naha proyék kami kalebet dina proyék sanés salaku subproyék. Ieu bakal mantuan pisan di mangsa nu bakal datang.

get_directory_property(IS_SUBPROJECT PARENT_DIRECTORY)

Pilihan Proyék

Urang bakal nyadiakeun dua pilihan.

Pilihan kahiji nyaeta MYLIB_TESTING - pikeun nganonaktipkeun tés unit. Ieu tiasa diperyogikeun upami urang yakin yén sadayana aya dina tes, tapi urang ngan ukur hoyong, contona, masang atanapi ngarangkep proyék urang. Atanapi proyék kami kalebet subproyék - dina hal ieu, pangguna proyék kami henteu kabetot dina ngajalankeun tés kami. Anjeun henteu nguji katergantungan anu anjeun anggo, naha anjeun?

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

Sajaba ti éta, urang bakal nyieun pilihan misah MYLIB_COVERAGE pikeun ngukur sinyalna kode ku tés, tapi bakal merlukeun parabot tambahan, jadi kudu diaktipkeun eksplisit.

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

Pilihan kompilasi

Tangtu, urang tiis tambah programer, jadi urang hoyong tingkat maksimum diagnostics compile-waktos ti compiler nu. Henteu aya beurit anu bakal ngaliwat.

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
)

Urang ogé bakal nganonaktipkeun ekstensi dina raraga pinuh sasuai jeung standar basa C ++. Éta diaktipkeun sacara standar dina CMake.

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

Tujuanana primér

Perpustakaan urang ngan ukur diwangun ku file lulugu, anu hartosna urang henteu ngagaduhan knalpot dina bentuk perpustakaan statik atanapi dinamis. Di sisi anu sanés, pikeun ngagunakeun perpustakaan urang sacara éksternal, éta kedah dipasang, éta kedah dideteksi dina sistem sareng dihubungkeun ka proyék anjeun, sareng dina waktos anu sami ieu header anu sami, ogé kamungkinan sababaraha tambahan, anu napel eta sipat.

Pikeun tujuan ieu, urang nyieun perpustakaan panganteur.

add_library(mylib INTERFACE)

Urang meungkeut headers ka perpustakaan panganteur urang.

Pamakéan CMake modéren, modis, nonoman nunjukkeun yén lulugu, sipat, jsb. dikirimkeun ngaliwatan hiji target tunggal. Janten cekap nyarios target_link_libraries(target PRIVATE dependency), sareng sadaya lulugu anu aya hubunganana sareng udagan dependency, bakal sadia pikeun sumber milik udagan target. Sareng anjeun henteu peryogi [target_]include_directories. Ieu bakal nunjukkeun di handap dina analisis Aksara CMake pikeun tés unit.

Éta ogé patut nengetan nu disebut. выражения-генераторы: $<...>.

Paréntah ieu ngahubungkeun lulugu anu urang peryogikeun sareng perpustakaan antarmuka urang, sareng upami perpustakaan urang disambungkeun kana udagan naon waé dina hierarki CMake anu sami, maka lulugu tina diréktori bakal aya hubunganana sareng éta. ${CMAKE_CURRENT_SOURCE_DIR}/include, sarta lamun perpustakaan urang geus dipasang dina sistem jeung disambungkeun ka proyék séjén maké paréntah find_package, teras lulugu tina diréktori bakal dikaitkeun sareng éta include relatif ka diréktori instalasi.

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

Hayu urang nyetel standar basa. Tangtosna, anu terakhir pisan. Dina waktos anu sami, urang henteu ngan ukur ngalebetkeun standar, tapi ogé ngalegaan ka anu bakal ngagunakeun perpustakaan urang. Ieu kahontal alatan kanyataan yén harta set boga kategori INTERFACE (tingali paréntah target_compile_features).

target_compile_features(mylib INTERFACE cxx_std_17)

Hayu urang nyieun alias pikeun perpustakaan urang. Leuwih ti éta, pikeun kageulisan, éta bakal dina husus "namespace". Ieu bakal mangpaat lamun modul béda muncul dina perpustakaan urang, sarta kami buka nyambungkeun aranjeunna bebas unggal lianna. Kawas di Busta, misalna.

add_library(Mylib::mylib ALIAS mylib)

setting

Masang header kami kana sistem. Sagalana basajan di dieu. Kami nyarios yén folder sareng sadaya header kedah lebet kana diréktori include relatif ka lokasi instalasi.

install(DIRECTORY include/mylib DESTINATION include)

Salajengna, urang ngawartosan sistem ngawangun yén urang hoyong tiasa nelepon paréntah dina proyék pihak katilu find_package(Mylib) jeung meunang gol Mylib::mylib.

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

Mantra salajengna kedah dipikaharti ku cara kieu. Nalika dina proyék pihak katilu urang nelepon paréntah find_package(Mylib 1.2.3 REQUIRED), jeung versi nyata perpustakaan dipasang bakal sauyunan jeung versi 1.2.3CMake bakal otomatis ngahasilkeun kasalahan. Hartina, anjeun henteu kedah ngalacak versi sacara manual.

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)

Tés

Upami tés ditumpurkeun sacara eksplisit ngagunakeun pilihan saluyu atanapi proyék kami mangrupikeun subproyék, nyaéta, nyambung ka proyék CMake anu sanés nganggo paréntah add_subdirectory, urang teu mindahkeun salajengna sapanjang hirarki, jeung naskah, nu ngajelaskeun paréntah pikeun generating jeung ngajalankeun tés, saukur teu ngajalankeun.

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

Dokuméntasi

Dokuméntasi ogé moal dihasilkeun dina kasus subproyék.

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

Sandbox online

Kitu ogé, subproyék moal gaduh sandbox online ogé.

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

Skrip tés (test/CMakeLists.txt)

Tés

Anu mimiti, urang mendakan pakét sareng kerangka tés anu diperyogikeun (ganti ku anu karesep anjeun).

find_package(doctest 2.3.3 REQUIRED)

Hayu urang ngadamel file anu tiasa dieksekusi nganggo tés. Biasana kuring nambihan langsung kana binér anu tiasa dieksekusi ngan ukur file anu bakal ngandung fungsina main.

add_executable(mylib-unit-tests test_main.cpp)

Sareng kuring nambihan file dimana tés sorangan dijelaskeun engké. Tapi anjeun henteu kedah ngalakukeun éta.

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

Urang sambungkeun kagumantungan. Punten dicatet yén kami ngan ukur numbu target CMake anu kami peryogikeun ka binér kami sareng henteu nyauran paréntahna target_include_directories. Judul tina kerangka tés sareng ti kami Mylib::mylib, kitu ogé ngawangun parameter (dina hal urang, ieu téh standar basa C ++) datang ngaliwatan babarengan jeung tujuan ieu.

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

Tungtungna, urang nyieun udagan dummy, anu "ngawangun" nu sarua jeung ngajalankeun tés, sarta nambahkeun target ieu ka wangunan standar (atribut tanggung jawab ieu. ALL). Ieu ngandung harti yén wangunan standar micu tés pikeun ngajalankeun, hartina urang moal poho ngajalankeun aranjeunna.

add_custom_target(check ALL COMMAND mylib-unit-tests)

Покрытие

Salajengna, urang ngaktifkeun pangukuran sinyalna kode upami pilihan anu pas ditangtukeun. Kuring moal balik kana detil, sabab patali leuwih alat pikeun ngukur sinyalna ti CMake. Ieu ngan penting pikeun dicatet yén dumasar kana hasil tujuan bakal dijieun coverage, nu merenah pikeun ngamimitian ngukur cakupan.

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

Skrip pikeun dokuméntasi (doc/CMakeLists.txt)

Kapanggih Doxygen.

find_package(Doxygen)

Salajengna, urang pariksa naha pamaké geus nyetel variabel basa. Upami enya, maka urang henteu nyabak, upami henteu, maka urang nyandak basa Rusia. Teras we ngonpigurasikeun file sistem Doxygen. Sadaya variabel anu diperyogikeun, kalebet basa, angkat ka dinya salami prosés konfigurasi (tingali. команду configure_file).

Lajeng urang nyieun gol doc, anu bakal ngamimitian ngahasilkeun dokuméntasi. Kusabab ngahasilkeun dokuméntasi sanés kabutuhan anu paling ageung dina prosés pamekaran, targetna moal diaktipkeun sacara standar; éta kedah diluncurkeun sacara eksplisit.

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

Skrip pikeun sandbox online (online/CMakeLists.txt)

Di dieu urang manggihan Python katilu jeung nyieun udagan wandbox, nu ngahasilkeun pamundut pakait jeung API jasa Wandbox, sarta ngirim anjeunna jauh. réspon hadir kalawan tumbu ka sandbox rengse.

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

Proyék luar

Ayeuna hayu urang tingali kumaha ngagunakeun sadayana ieu.

Majelis

Ngawangun proyék ieu, sapertos proyék sanés dina sistem ngawangun CMake, diwangun ku dua tahap:

turunan

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

Upami paréntah di luhur henteu tiasa dianggo kusabab versi CMake anu lami, cobian ngaleungitkeun -S:

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

Langkung seueur ngeunaan pilihan.

Ngawangun proyék

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

Leuwih lengkep ngeunaan tujuan assembly.

Pilihan

MYLIB_COVERAGE

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

Ngawengku udagan coverage, dimana anjeun tiasa ngamimitian ngukur cakupan kode ku tés.

MYLIB_TESTING

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

Nyadiakeun kamampuhan pikeun nganonaktipkeun Unit test ngawangun jeung target check. Hasilna, pangukuran cakupan kode ku tés dipareuman (tingali. MYLIB_COVERAGE).

Tés ogé otomatis ditumpurkeun lamun proyék disambungkeun ka proyék séjén salaku subproject maké paréntah add_subdirectory.

MYLIB_DOXYGEN_LANGUAGE

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

Ngalihkeun basa dokuméntasi anu dibangkitkeun target doc ka anu dipasihkeun. Pikeun daptar basa sadia, tingali ramatloka Sistim Doxygen.

Rusia diaktipkeun sacara standar.

Sasaran Majelis

sacara standar

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

Lamun udagan teu dieusian (anu sarua jeung udagan all), ngumpulkeun sagalana bisa, sarta ogé nelepon udagan check.

mylib-unit-tés

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

Nyusun tés unit. Diaktipkeun sacara standar.

cek

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

Ngajalankeun tés unit anu dikumpulkeun (dikumpulkeun, upami henteu acan). Diaktipkeun sacara standar.

Tingali ogé mylib-unit-tests.

sinyalna

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

Nganalisis ngajalankeun (ngajalankeun, upami teu acan) tés unit pikeun sinyalna kode ku tés ngagunakeun program gcovr.

The knalpot palapis bakal kasampak kawas kieu:

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

Target ngan sadia sawaktos pilihan diaktipkeun MYLIB_COVERAGE.

Tingali ogé check.

doc

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

Ngamimitian generasi dokuméntasi kode ngagunakeun sistem Doksigén.

kotak wand

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

Tanggapan tina jasa sapertos kieu:

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

jasa dipaké pikeun ieu Wandbox. Kuring henteu weruh kumaha fléksibel server maranéhanana, tapi kuring nyangka yén kasempetan ieu teu kudu abused.

conto

Ngawangun proyék dina modeu debug kalayan pangukuran cakupan

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

Masang proyék tanpa assembly awal jeung nguji

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

Ngawangun dina modeu release kalawan compiler dibikeun

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

Ngahasilkeun dokuméntasi dina basa Inggris

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

instrumen

  1. CMkeun 3.13

    Kanyataanna, CMake versi 3.13 ngan diperlukeun pikeun ngajalankeun sababaraha paréntah konsol dijelaskeun dina pitulung ieu. Tina sudut pandang sintaksis skrip CMake, versi 3.8 cekap upami generasi disebut ku cara anu sanés.

  2. Perpustakaan nguji doctest

    Tés tiasa ditumpurkeun (tingali опцию MYLIB_TESTING).

  3. Doksigén

    Pikeun ngalihkeun basa anu bakal ngahasilkeun dokuméntasi, aya pilihan MYLIB_DOXYGEN_LANGUAGE.

  4. Juru basa Python 3

    Pikeun generasi otomatis sandboxes online.

Analisis statik

Kalayan CMake sareng sababaraha alat anu saé, anjeun tiasa nyayogikeun analisa statik kalayan usaha minimal.

Cppcheck

CMake ngagaduhan dukungan anu diwangun pikeun alat analisis statik Cppcheck.

Jang ngalampahkeun ieu anjeun kudu make pilihan CMAKE_CXX_CPPCHECK:

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

Saatos ieu, analisa statik bakal otomatis diluncurkeun unggal waktos sumberna disusun sareng dikompilasi deui. Teu perlu ngalakukeun nanaon tambahan.

clang

Kalayan bantuan alat éndah scan-build Anjeun ogé tiasa ngajalankeun analisa statik dina waktos sanés:

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

Di dieu, teu sapertos kasus Cppcheck, anjeun kedah ngajalankeun ngawangun unggal waktos scan-build.

afterword

CMake mangrupakeun sistem anu pohara kuat sarta fléksibel nu ngidinan Anjeun pikeun nerapkeun fungsionalitas pikeun tiap rasa jeung warna. Sareng, sanaos sintaksisna kadang-kadang nyéépkeun anu dipikahoyong, sétan tetep henteu pikasieuneun sapertos anjeunna dicét. Anggo sistem ngawangun CMake pikeun kapentingan masarakat sareng kaséhatan.

Unduh template proyék

sumber: www.habr.com

Tambahkeun komentar