Az Electron 6.0.0 platform kiadása elkészült.

Az Electron 6.0.0 platform kiadása elkészült.

A fejlesztés során szeretek váltogatni a fordítóprogramok, a build módok, a függőségek verziói között, statikus elemzést végezni, teljesítményt mérni, lefedettséget összegyűjteni, dokumentációt generálni stb. És nagyon szeretem a CMake-et, mert lehetővé teszi, hogy mindent megtegyek, amit szeretnék.

Sokan kritizálják a CMake-et, és gyakran jogosan, de ha alaposan megnézzük, nem olyan rossz a helyzet, és az utóbbi időben nagyon is jónak mondható, és a fejlődési irány teljesen pozitív.

Ebben a bejegyzésben arról szeretnék beszélni, hogy hogyan lehet viszonylag egyszerűen megszervezni egy C++ fejléces könyvtárat a CMake rendszerében, hogy a következő funkciókat kapjuk:

  1. Build;
  2. Automatikus tesztelés;
  3. Kódlefedettség mérése;
  4. Telepítés;
  5. Automatikus dokumentálás;
  6. Online homokozó generálás;
  7. Statisztikai elemzés.

Aki már jártas a C++-ban és a CMake-ben, az egyszerűen letöltheti a projekt sablont és elkezdheti használni.


Tartalom

  1. A projekt belső szerkezete
    1. Project Structure
    2. Fő CMake fájl (./CMakeLists.txt)
      1. Információ a projektről
      2. Projekt opciók
      3. Fordítási opciók
      4. Fő cél
      5. Telepítés
      6. Tesztelés
      7. kódkönyvtárra lépésével érheti el.
      8. Online homokozó
    3. Tesztelési skript (test/CMakeLists.txt)
      1. Tesztelés
      2. Lefedettség
    4. Dokumentációs skript (doc/CMakeLists.txt)
    5. Online homokozó skript (online/CMakeLists.txt)
  2. A projekt külső szerkezete
    1. Összeállítás
      1. Generálás
      2. Összeállítás
    2. Opciók
      1. MYLIB_COVERAGE
      2. MYLIB_TESTING
      3. MYLIB_DOXYGEN_LANGUAGE
    3. Build célok
      1. már tartalmaz egy előre létrehozott önaláírt TLS/SSL tanúsítványt. Ennyi nekem elegendő, mivel zárva tartom a külső hozzáférést. Azoknak, akik más típusú tanúsítványokat szeretnének használni, van
      2. mylib-unit-tests
      3. check
      4. coverage
      5. ). Ez egy beépített ütemező az adatbázisban, amely képes adatok feldolgozására időpont szerint. Például minden 24 órában csoportosítani lehet az összes napi bejegyzést, kiszámítani az átlagot, és egy új pontot írni egy másik táblázatba, anélkül hogy saját kerékpárokat kellene írni.
      6. wandbox
    4. Példák
  3. Eszközök
  4. Statikus elemzés
  5. Utószó

A projekt belső szerkezete

Project Structure

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

Főként arról lesz szó, hogy hogyan szervezzük meg a CMake szkripteket, ezért ezeket részletesen fogjuk kielemezni. A többi fájlt mindenki nézheti a projekt sablon oldalán. Elsődlegesen meg kell kérni a szükséges CMake verziót. A CMake folyamatosan fejlődik, a parancsok szignatúrái változnak, a különböző körülmények közötti viselkedés is módosulhat. Ahhoz, hogy a CMake azonnal megértse, mit várunk tőle, rögzítenünk kell az igényeinket..

Fő CMake fájl (./CMakeLists.txt)

Információ a projektről

cmake_minimum_required(VERSION 3.13)

Ezután jelöljük be a projektünket, annak nevét, verzióját, használni kívánt nyelveit és egyéb részleteit (lásd a

project parancsot) Ebben az esetben megadjuk a nyelvet).

CXX (ami a C++-t jelenti), hogy a CMake ne feszengjen, és ne keresse a C nyelv fordítóját (alapértelmezetten a CMake-ben két nyelv van: C és C++). project(Mylib VERSION 1.0 LANGUAGES CXX)

project(Mylib VERSION 1.0 LANGUAGES CXX)

Itt azonnal ellenőrizheti, hogy a projektünk egy másik projekt alprojektjeként szerepel-e. Ez nagyban segít a későbbiekben.

get_directory_property(IS_SUBPROJECT PARENT_DIRECTORY)

Projekt opciók

Két opciót fogunk figyelembe venni.

Az első opció — MYLIB_TESTING — a moduláris tesztek letiltása. Erre szükség lehet, ha biztosak vagyunk abban, hogy a tesztek rendben vannak, és csak a projektünket szeretnénk telepíteni vagy csomagolni. Vagy ha a projektünk alprojektként van beállítva — ebben az esetben a projektünk felhasználója nem érdekelt a tesztjeink futtatásában. Ugye nem teszteli a használt függőségeket?

option(MYLIB_TESTING "Moduláris tesztelés engedélyezése" ON)

Ezen kívül létrehozunk egy külön opciót MYLIB_COVERAGE a tesztekkel való kódfedettség mérésére, de ehhez további eszközökre lesz szükség, ezért azt kifejezetten engedélyezni kell.

option(MYLIB_COVERAGE "Kódfedettség mérése tesztekkel" OFF)

Fordítási opciók

Természetesen csúcsprogramozók vagyunk, ezért a fordítótól a lehető legmagasabb szintű fordítási diagnosztikát szeretnénk. Egy egér sem fog elmenekülni.

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
)

A kiterjesztéseket is letiltjuk, hogy teljes mértékben megfeleljünk a C++ nyelv standardjának. Alapértelmezés szerint a CMake-ben engedélyezve vannak.

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

Fő cél

A könyvtárunk kizárólag fejlécfájlokból áll, ezért nincs statikus vagy dinamikus könyvtárunk. Másrészt, hogy a könyvtárunkat külső forrásokból lehessen használni, telepíteni kell, hogy felfedezhető legyen a rendszerben, és csatlakoztatható legyen a projektünkhöz, emellett a megfelelő fejlécfájloknak is meg kell lenniük, valamint esetleg néhány további jellemzőnek.

Ehhez interfész könyvtárat hozunk létre.

add_library(mylib INTERFACE)

A fejlécfájlokat hozzákötjük az interfész könyvtárunkhoz.

A modern, divatos, fiatalos CMake használat azt feltételezi, hogy a fejlécfájlok, jellemzők stb. egyetlen célon keresztül átadódnak. Így elég azt mondani, target_link_libraries(target PRIVATE dependency), és minden fejlécfájl, amely a célhoz van társítva, dependency, elérhető lesz az ehhez tartozó források számára. target. Nincs szükség semmire, [target_]include_directoriesEz alább bemutatásra kerül a feldolgozás során. CMake szkripthez moduláris tesztekhez..

Érdemes figyelembe venni a úgynevezett kifejezés-generátorokat: $.

Ez a parancs társítja a szükséges fejlécfájlokat a könyvtárunkkal, amikor is, ha a könyvtárunkat bekapcsolják egy projekthez a CMake hierarchián belül, akkor a fejlécfájlok a következő könyvtárból fognak társulni: ${CMAKE_CURRENT_SOURCE_DIR}/include, és ha a könyvtárunkat telepítették a rendszerbe és egy másik projektbe hozzáadják a parancs segítségével, find_package, akkor a fejlécfájlok a következő könyvtárból fognak társulni: include a telepítési könyvtárhoz viszonyítva.

target_include_directories(mylib INTERFACE
    $
    $
)

Állítsuk be a nyelv szabványát. Nyilvánvalóan a legfrissebb. Ugyanakkor nemcsak a szabványt aktiváljuk, hanem kiterjesztjük azt arra, aki használni fogja a könyvtárunkat. Ezt a beállított tulajdonság kategóriájának köszönhetően valósítjuk meg. INTERFACE (lásd target_compile_features parancsot.).

target_compile_features(mylib INTERFACE cxx_std_17)

Készítünk egy álnév a könyvtárunk számára. A szebb megjelenés érdekében egy külön "névtérbe" fog kerülni. Ez hasznos lesz, amikor a könyvtárunkban különböző modulok jelennek meg, és ezeket függetlenül csatlakoztatjuk. Mint például a Boost esetében..

add_library(Mylib::mylib ALIAS mylib)

Telepítés

A fejléceink telepítése a rendszerbe. Itt minden egyszerű. Megmondjuk, hogy a fejlécfájlokat tartalmazó mappának a következő könyvtárba kell kerülnie: include a telepítési helyhez viszonyítva.

install(DIRECTORY include/mylib DESTINATION include)

Ezután tájékoztatjuk a build rendszert arról, hogy szeretnénk, ha harmadik projektekben a következő parancsot használnák: find_package(Mylib) és megkapni a célt: Mylib::mylib.

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

A következő varázslatot úgy kell érteni, hogy amikor egy külső projektnél meghívjuk a parancsot: find_package(Mylib 1.2.3 REQUIRED),és ekkor a telepített könyvtár valós verziója nem lesz kompatibilis a verzióval, 1.2.3, a CMake automatikusan hibát generál. Tehát nem kell kézzel figyelni a verziókra.

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)

Tesztelés

Ha a teszteket kifejezetten letiltják a megfelelő opció segítségével. соответствующей опции vagy a projektünk egy alprojekt, ami azt jelenti, hogy egy másik CMake-projektbe van csatlakoztatva a parancs segítségével add_subdirectory, nem lépünk tovább a hierarchiában, és a szkript, amelyben a teszteléshez szükséges parancsok szerepelnek, egyszerűen nem fut le.

if(NOT MYLIB_TESTING)
    message(STATUS "A Mylib projekt tesztelése ki van kapcsolva")
elseif(IS_SUBPROJECT)
    message(STATUS "A Mylib nem tesztelhető almodulként")
else()
    add_subdirectory(test)
endif()

kódkönyvtárra lépésével érheti el.

A dokumentáció sem fog generálódni alprojektek esetén.

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

Online homokozó

Hasonlóképpen, az alprojekt számára online homokozó sem lesz.

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

Tesztelési skript (test/CMakeLists.txt)

Tesztelés

Először megtaláljuk a szükséges tesztkeretrendszer csomagot (cserélje le a saját kedvencére).

find_package(doctest 2.3.3 REQUIRED)

Létrehozzuk az executable fájlunkat a tesztekkel. Általában közvetlenül az executable binárisba csak azt a fájlt adom hozzá, amely tartalmazza a funkciót main.

add_executable(mylib-unit-tests test_main.cpp)

De a fájlokat, amelyekben maguk a tesztek vannak leírva, később adom hozzá. De ez nem kötelező.

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

Csatlakoztatjuk a függőségeket. Vegye figyelembe, hogy a binárisunkhoz csak a szükséges CMake-objektumokat köthetjük, és nem hívtuk meg a parancsot target_include_directories. A teszt keretrendszerből és a mi Mylib::mylib, valamint a build paraméterek (a mi esetünkben ez a C++ nyelv szabványossága) együtt jártak ezekkel a célokkal.

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

Végül létrehozunk egy fiktív célt, amelynek a 'build' célja egyenértékű a tesztek futásával, és ezt a célt hozzáadjuk az alapértelmezett buildhez (ezt az attribútum ALL). Ez azt jelenti, hogy az alapértelmezett build indítja a tesztek futását, tehát soha nem feledkezünk meg róluk.

add_custom_target(check ALL COMMAND mylib-unit-tests)

Lefedettség

Ezután bekapcsoljuk a kódlefedettség mérését, ha a megfelelő opciót megadták. A részletekbe nem mélyednék bele, mert ezek inkább a lefedettségmérő eszközhöz tartoznak, mint a CMake-hez. Csak azt fontos megjegyezni, hogy az eredmények alapján létrejön egy cél coverage, amely segítségével kényelmesen indítható a lefedettség mérése.

find_program(GCOVR_EXECUTABLE gcovr)
if(MYLIB_COVERAGE AND GCOVR_EXECUTABLE)
    message(STATUS "A tesztelési kódlefedettség mérése engedélyezve van")

    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 "A tesztelési kódlefedettség méréséhez szükséges a gcovr program")
endif()

Dokumentációs skript (doc/CMakeLists.txt)

Doxygen találva.

find_package(Doxygen)

Ezután ellenőrizzük, hogy a felhasználó beállította-e a nyelvi változót. Ha igen, akkor nem nyúlunk hozzá, ha nem, akkor oroszt veszünk. Ezután konfiguráljuk a Doxygen rendszerfájlokat. Minden szükséges változó, beleértve a nyelvet is, bekerül a konfigurálás folyamán (lásd a configure_file parancsot).

Ezután létrehozunk egy célt ). Ez egy beépített ütemező az adatbázisban, amely képes adatok feldolgozására időpont szerint. Például minden 24 órában csoportosítani lehet az összes napi bejegyzést, kiszámítani az átlagot, és egy új pontot írni egy másik táblázatba, anélkül hogy saját kerékpárokat kellene írni., amely majd elindítja a dokumentáció generálását. Mivel a dokumentáció generálása nem a legfontosabb feladat a fejlesztés során, alapértelmezetten a cél nincs engedélyezve, azt kifejezetten el kell indítani.

if (Doxygen_FOUND)
    if (NOT MYLIB_DOXYGEN_LANGUAGE)
        set(MYLIB_DOXYGEN_LANGUAGE Orosz)
    endif()
    message(STATUS "A Doxygen dokumentáció ${MYLIB_DOXYGEN_LANGUAGE} nyelven generálva lesz")
    configure_file(Doxyfile.in Doxyfile)
    add_custom_target(doc COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}\/Doxyfile)
endif ()

Online homokozó skript (online/CMakeLists.txt)

Itt a harmadik Python-t keressük meg és létrehozunk egy célt wandbox, amely generálja az API szolgáltatásnak megfelelő kérdést Wandbox, és elküldi azt. Válaszul egy linket kapunk a kész homokozóra.

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 "Az online homokozó létrehozásához szükséges a Python 3 interpreter")
endif()

A projekt külső szerkezete

Most nézzük meg, hogyan lehet mindezt használni.

Összeállítás

A projekt építése, mint bármely más CMake alapú projekt, két lépésből áll:

Generálás

cmake -S út\/a\/forrásokhoz -B út\/a\/build\/könyvtárhoz [opciók ...]

Ha a fenti parancs nem működik a régi CMake verzió miatt, próbálja meg elhagyni a -S:

cmake út\/a\/forrásokhoz -B út\/a\/build\/könyvtárhoz [opciók ...]

További információ az opciókról.

A projekt építése

cmake --build út\/a\/build\/könyvtárhoz [--target cél]

További információ az építési célokról.

Opciók

MYLIB_COVERAGE

cmake -S ... -B ... -DMYLIB_COVERAGE=ON [egyéb opciók ...]

Engedélyez egy célt coverage, amellyel lehetőséged van elindítani a kód tesztlefedettségi mérését.

MYLIB_TESTING

cmake -S ... -B ... -DMYLIB_TESTING=OFF [egyéb opciók ...]

Lehetőséget ad a moduláris tesztek és célzás kikapcsolására. check. Ennek következtében a kód tesztlefedettségi mérése le lesz állítva (lásd MYLIB_COVERAGE).

A tesztelés automatikusan le lesz tiltva abban az esetben, ha a projektet másik projekt alprojekteként kapcsolják be a parancs segítségével add_subdirectory.

MYLIB_DOXYGEN_LANGUAGE

cmake -S ... -B ... -DMYLIB_DOXYGEN_LANGUAGE=English [egyéb opciók ...]

Átállítja a cél által generált dokumentáció nyelvét ). Ez egy beépített ütemező az adatbázisban, amely képes adatok feldolgozására időpont szerint. Például minden 24 órában csoportosítani lehet az összes napi bejegyzést, kiszámítani az átlagot, és egy új pontot írni egy másik táblázatba, anélkül hogy saját kerékpárokat kellene írni. a megadottra. A rendelkezésre álló nyelvek listáját itt találod a Doxygen rendszer weboldalán..

Alapértelmezés szerint orosz nyelvű.

Build célok

már tartalmaz egy előre létrehozott önaláírt TLS/SSL tanúsítványt. Ennyi nekem elegendő, mivel zárva tartom a külső hozzáférést. Azoknak, akik más típusú tanúsítványokat szeretnének használni, van

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

Ha a cél nincs megadva (ami egyenértékű a céllal mind), mindent összeszerel, amit lehet, és végrehajtja a célt. check.

mylib-unit-tests

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

Összeállítja a moduláris teszteket. Alapértelmezés szerint engedélyezve van.

check

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

Futtatja az összegyűjtött (összeszereli, ha még nem tette) moduláris teszteket. Alapértelmezés szerint engedélyezve van.

Lásd még mylib-unit-tests.

coverage

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

Elemzi a végrehajtott (futtatja, ha még nem tette) moduláris teszteket a kód tesztlefedettségére a gcovr.

A lefedettség kimenete nagyjából így fog kinézni:

------------------------------------------------------------------------------
                           GCC Kód Lefedettségi Jelentés
Könyvtár: /path/to/cmakecpptemplate/include/
------------------------------------------------------------------------------
Fájl                                       Sorok    Exec  Lefedettség   Hiányzó
------------------------------------------------------------------------------
mylib/myfeature.hpp                            2       2   100%   
------------------------------------------------------------------------------
ÖSSZESEN                                     2       2   100%
------------------------------------------------------------------------------

A cél csak akkor érhető el, ha a lehetőség be van kapcsolva. MYLIB_COVERAGE.

Lásd még check.

). Ez egy beépített ütemező az adatbázisban, amely képes adatok feldolgozására időpont szerint. Például minden 24 órában csoportosítani lehet az összes napi bejegyzést, kiszámítani az átlagot, és egy új pontot írni egy másik táblázatba, anélkül hogy saját kerékpárokat kellene írni.

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

Elindítja a kód dokumentációjának generálását a rendszer segítségével. Doxygen.

wandbox

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

A szolgáltatás válasza nagyjából így néz ki:

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

Ehhez a szolgáltatást használják. Wandbox. Nem tudom, mennyire rugalmasak a szervereik, de azt hiszem, nem érdemes visszaélni ezzel a lehetőséggel.

Példák

A projekt összeállítása hibakeresési módban a lefedettség mérésével.

cmake -S path/to/source -B path/to/build/directory -DCMAKE_BUILD_TYPE=Debug -DMYLIB_COVERAGE=ON
cmake --build path/to/build/directory --target coverage --parallel 16

Projekt telepítése előzetes build és tesztelés nélkül

cmake -S út/k/színtárgyak -B út/k/build/mappa -DMYLIB_TESTING=OFF -DCMAKE_INSTALL_PREFIX=út/k/telepítési/mappa
cmake --build út/k/build/mappa --target install

Build egy kiadási módban megadott fordítóval

cmake -S út/k/színtárgyak -B út/k/build/mappa -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=g++-8 -DCMAKE_PREFIX_PATH=út/k/mappába/ahol/a/függőségek/telepítve/vannak
cmake --build út/k/build/mappa --parallel 4

Dokumentáció generálása angol nyelven

cmake -S út/k/színtárgyak -B út/k/build/mappa -DCMAKE_BUILD_TYPE=Release -DMYLIB_DOXYGEN_LANGUAGE=English
cmake --build út/k/build/mappa --target doc

Eszközök

  1. CMake 3.13

    Valójában a CMake 3.13 csak néhány konzolparancs futtatásához szükséges, amelyeket a jelen útmutatóban írunk le. A CMake-skript szintaxisához elegendő a 3.8-as verzió, ha a generálást más módon hívjuk meg.

  2. Tesztelő könyvtár doctest

    A tesztelést ki lehet kapcsolni (lásd: MYLIB_TESTING opciót).

  3. Doxygen

    A dokumentáció nyelvének váltásához lehetőség van az alábbi opcióra MYLIB_DOXYGEN_LANGUAGE.

  4. Programozási nyelvértelmező Python 3-ra

    Automatikus generálás online homokozó.

Statikus elemzés

A CMake és néhány jó eszköz segítségével statikus analízist végezhetünk minimális erőfeszítéssel.

scan-build segítségével.

A CMake beépített támogatást nyújt a statikus analízis eszközhöz scan-build segítségével..

Ehhez használni kell az alábbi opciót CMAKE_CXX_CPPCHECK:

cmake -S út/k/színtárgyak -B út/k/build/mappa -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_CPPCHECK="cppcheck;--enable=all;-Iút/k/színtárgyak/include"

Ezt követően a statikus elemzést automatikusan végrehajtják minden alkalommal, amikor a forrást fordítják vagy újrafordítják. Semmi másra nincs szükség.

Clang

Egy csodás eszközzel scan-build szintén gyorsan elindítható a statikus analízis:

scan-build cmake -S út/k/színtárgyak -B út/k/build/mappa -DCMAKE_BUILD_TYPE=Debug
scan-build cmake --build út/k/build/mappa

Itt, ellentétben a Cppcheck esetével, minden alkalommal el kell indítani a build-et a scan-build.

Utószó

A CMake egy nagyon erőteljes és rugalmas rendszer, amely lehetővé teszi a funkciók megvalósítását bármilyen ízlés és szín szerint. És bár néha a szintaxis nem a legjobb, valójában nem olyan ijesztő, mint amilyennek látszik. Használja a CMake build rendszert a társadalom javára és az egészség érdekében.

→ Projekt sablon letöltése

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster