Během vývoje rád měním kompilátory, sestavuji režimy, verze závislostí, provádím statickou analýzu, měřím výkon, shromažďuji pokrytí, generuji dokumentaci a tak dále. A opravdu miluji CMake, protože mi umožňuje dělat, co chci.
Mnozí nadávají CMake a často zaslouženě, ale když se podíváte, není to tak špatné, ale v poslední době to vůbec není špatnéa směr vývoje je vcelku pozitivní.
V této poznámce vám chci říci, jak snadné je uspořádat knihovnu hlaviček C++ v systému CMake, abyste získali následující funkce:
To se zaměří hlavně na to, jak organizovat skripty CMake, takže budou podrobně analyzovány. Zbytek souborů může kdokoli přímo zobrazit. na stránce projektu šablony.
Nejprve je potřeba požádat o požadovanou verzi systému CMake. CMake se vyvíjí, podpisy příkazů se mění, chování za různých podmínek. Aby CMake okamžitě pochopil, co od něj chceme, musíme na něj okamžitě opravit naše požadavky.
cmake_minimum_required(VERSION 3.13)
Poté označíme náš projekt, jeho název, verzi, používané jazyky atd. команду project).
V tomto případě zadejte jazyk CXX (což znamená C++), aby se CMake neobtěžovalo hledáním kompilátoru C (ve výchozím nastavení jsou v CMake zahrnuty dva jazyky: C a C++).
project(Mylib VERSION 1.0 LANGUAGES CXX)
Zde si můžete ihned ověřit, zda je náš projekt zařazen do jiného projektu jako podprojekt. Do budoucna to hodně pomůže.
První možností je MYLIB_TESTING - zakázat testy jednotek. To může být potřeba, pokud jsme si jisti, že je vše v pořádku s testy a chceme například pouze nainstalovat nebo zabalit náš projekt. Nebo je náš projekt zařazen jako podprojekt – v tomto případě uživatel našeho projektu nemá zájem spouštět naše testy. Netestuješ závislosti, které používáš, že ne?
Kromě toho vytvoříme samostatnou možnost MYLIB_COVERAGE pro měření pokrytí kódem pomocí testů, ale bude vyžadovat další nástroje, takže jej budete muset explicitně povolit.
Naše knihovna se skládá pouze z hlavičkových souborů, což znamená, že nemáme žádný výstup ve formě statických nebo dynamických knihoven. Na druhou stranu, abyste mohli naši knihovnu používat zvenčí, musíte si ji nainstalovat, musíte ji umět najít v systému a připojit k vašemu projektu a zároveň právě tyto hlavičky jako případně nějaké další vlastnosti.
Za tímto účelem vytvoříme knihovnu rozhraní.
add_library(mylib INTERFACE)
Svážeme hlavičky s naší knihovnou rozhraní.
Moderní, trendy a mladistvé použití CMake znamená, že záhlaví, vlastnosti atd. přenášeny přes jediný cíl. Takže stačí říct target_link_libraries(target PRIVATE dependency)a všechna záhlaví, která jsou přidružena k cíli dependency, bude k dispozici pro zdroje patřící do cíle target. A ty žádné nepotřebuješ [target_]include_directories. To bude ukázáno níže při analýze CMake skript pro testy jednotek.
Tento příkaz spojuje hlavičky, které potřebujeme, s naší knihovnou rozhraní, a pokud je naše knihovna připojena k jakémukoli cíli ve stejné hierarchii CMake, pak k ní budou přiřazeny hlavičky z adresáře. ${CMAKE_CURRENT_SOURCE_DIR}/include, a pokud je naše knihovna nainstalována v systému a připojena k jinému projektu pomocí příkazu find_package, pak k němu budou přiřazeny hlavičky z adresáře include vzhledem k instalačnímu adresáři.
Nastavte jazykový standard. Samozřejmě nejnovější. Standard přitom nejen zařazujeme, ale také distribuujeme těm, kteří budou naši knihovnu využívat. Toho je dosaženo tím, že vlastnost set má kategorii INTERFACE (viz příkaz target_compile_features).
Získáme alias pro naši knihovnu. A pro krásu to bude ve speciálním „jmenném prostoru“. To bude užitečné, když se v naší knihovně objeví různé moduly a budeme je propojovat nezávisle na sobě. Jako například v Bustě.
Instalace našich hlaviček do systému. Všechno je zde jednoduché. Říkáme, že složka se všemi záhlavími by měla spadat do adresáře include ohledně místa instalace.
Následující zaklínadlo je třeba chápat takto. Když jsme ve vedlejším projektu, voláme příkaz find_package(Mylib 1.2.3 REQUIRED), a zároveň skutečná verze nainstalované knihovny bude nekompatibilní s verzí 1.2.3, CMake automaticky vygeneruje chybu. To znamená, že nebudete muset sledovat verze ručně.
Pokud jsou testy výslovně zakázány pomocí odpovídající možnost nebo náš projekt je podprojekt, to znamená, že je připojen k jinému projektu CMake pomocí příkazu add_subdirectory, nejdeme dále v hierarchii a skript, který popisuje příkazy pro generování a spouštění testů, se jednoduše nespustí.
if(NOT MYLIB_TESTING)
message(STATUS "Тестирование проекта Mylib выключено")
elseif(IS_SUBPROJECT)
message(STATUS "Mylib не тестируется в режиме подмодуля")
else()
add_subdirectory(test)
endif()
Propojujeme závislosti. Vezměte prosím na vědomí, že jsme k našemu binárnímu souboru připojili pouze cíle CMake, které jsme potřebovali, a nevolali příkaz target_include_directories. Záhlaví z testovacího rámce a z našeho Mylib::mylib, stejně jako možnosti sestavení (v našem případě jazykový standard C++) procházely společně s těmito cíli.
Nakonec vytvoříme fiktivní cíl, jehož „sestavení“ je ekvivalentní spouštění testů, a přidáme tento cíl do výchozího sestavení (toto je odpovědností atributu ALL). To znamená, že výchozí sestavení spustí testy, což znamená, že je nikdy nezapomeneme spustit.
add_custom_target(check ALL COMMAND mylib-unit-tests)
Dále zapněte měření pokrytí kódem, pokud je nastavena odpovídající možnost. Nebudu zabíhat do podrobností, protože se týkají spíše nástroje pro měření pokrytí než CMake. Důležité je pouze poznamenat, že výsledky vytvoří cíl coverage, se kterým je vhodné začít měřit pokrytí.
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()
Dále zkontrolujeme, zda je proměnná s jazykem nastavena uživatelem. Pokud ano, pak se toho nedotkneme, pokud ne, vezmeme ruštinu. Poté nakonfigurujeme systémové soubory Doxygen. Všechny potřebné proměnné, včetně jazyka, se tam dostanou během procesu konfigurace (viz. команду configure_file).
Poté vytvoříme cíl doc, který zahájí generování dokumentace. Protože generování dokumentace není ve vývojovém procesu tou největší potřebou, cíl nebude ve výchozím nastavení zahrnut, bude muset být spuštěn explicitně.
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 ()
Zde najdeme třetí Python a vytvoříme cíl wandbox, který vygeneruje požadavek odpovídající servisnímu API Schránka na hůlkua odešle. Jako odpověď přichází odkaz na hotový sandbox.
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()
Ve skutečnosti je CMake verze 3.13 vyžadován pouze ke spuštění některých příkazů konzoly popsaných v této nápovědě. Z hlediska syntaxe skriptů CMake je verze 3.8 dostačující, pokud je generování voláno jinými způsoby.
CMake je velmi výkonný a flexibilní systém, který vám umožní implementovat funkce pro každý vkus a barvu. A i když syntaxe někdy ponechává mnoho přání, ďábel stále není tak hrozný, jak je namalován. Používejte sestavovací systém CMake ve prospěch společnosti a zdraví.