Geliştirme sırasında derleyicileri değiştirmeyi, modları, bağımlılık sürümlerini değiştirmeyi, statik analiz gerçekleştirmeyi, performansı ölçmeyi, kapsamı toplamayı, belge oluşturmayı vb. seviyorum. Ve CMake'i gerçekten seviyorum çünkü istediğim her şeyi yapmamı sağlıyor.
Pek çok kişi CMake'i eleştiriyor ve çoğu zaman bunu hak ediyor, ancak ona bakarsanız her şeyin o kadar da kötü olmadığını görüyorsunuz ve son zamanlarda hiç de fena değilve gelişme yönü oldukça olumlu.
Bu notta, aşağıdaki işlevleri elde etmek için CMake sisteminde C++ 'da bir başlık kitaplığını nasıl düzenleyeceğinizi anlatmak istiyorum:
Toplantı;
Otomatik çalıştırma testleri;
Kod kapsamı ölçümü;
Kurulum;
Otomatik belgeleme;
Çevrimiçi sanal alan oluşturma;
Statik analiz.
Avantajlarını ve C yapımını zaten anlayan herkes kolayca yapabilir proje şablonunu indir ve kullanmaya başlayın.
Biz esas olarak CMake scriptlerinin nasıl organize edileceğinden bahsedeceğiz dolayısıyla bunlar detaylı olarak ele alınacaktır. Herkes dosyaların geri kalanını doğrudan görüntüleyebilir şablon proje sayfasında.
Öncelikle CMake sisteminin gerekli sürümünü talep etmeniz gerekiyor. CMake gelişiyor, komut imzaları ve farklı koşullardaki davranışlar değişiyor. CMake'in ondan ne istediğimizi hemen anlayabilmesi için ona yönelik gereksinimlerimizi hemen kaydetmemiz gerekiyor.
cmake_minimum_required(VERSION 3.13)
Daha sonra projemizi, adını, versiyonunu, kullanılan dilleri vb. belirleyeceğiz (bkz. команду project).
Bu durumda dili belirtiyoruz CXX (ve bu C++ anlamına gelir) böylece CMake bir C dili derleyicisini zorlamaz ve aramaz (CMake varsayılan olarak iki dil içerir: C ve C++).
project(Mylib VERSION 1.0 LANGUAGES CXX)
Buradan projemizin alt proje olarak başka bir projeye dahil olup olmadığını hemen kontrol edebilirsiniz. Bu gelecekte çok yardımcı olacaktır.
İlk seçenek MYLIB_TESTING — birim testlerini devre dışı bırakmak için. Testlerde her şeyin yolunda olduğundan eminsek ancak örneğin yalnızca projemizi kurmak veya paketlemek istiyorsak bu gerekli olabilir. Veya projemiz bir alt proje olarak dahil edilmiştir - bu durumda projemizin kullanıcısı testlerimizi yürütmekle ilgilenmez. Kullandığınız bağımlılıkları test etmiyorsunuz, değil mi?
Ayrıca ayrı bir seçenek yapacağız MYLIB_COVERAGE kod kapsamını testlerle ölçmek için, ancak ek araçlar gerektireceğinden açıkça etkinleştirilmesi gerekecektir.
Kütüphanemiz sadece başlık dosyalarından oluşuyor, yani statik veya dinamik kütüphaneler şeklinde herhangi bir egzozumuz yok. Öte yandan kütüphanemizi harici olarak kullanabilmek için yüklü olması, sistemde algılanabilir olması ve projenize bağlanması ve aynı zamanda aynı başlıkların yanı sıra muhtemelen bazı ek başlıkların olması gerekir. onun özelliklerine bağlıdır.
Bu amaçla bir arayüz kütüphanesi oluşturuyoruz.
add_library(mylib INTERFACE)
Başlıkları arayüz kütüphanemize bağlarız.
CMake'in modern, modaya uygun, gençlik kullanımı, başlıkların, özelliklerin vb. tek bir hedef üzerinden iletilir. yani şunu söylemem yeterli target_link_libraries(target PRIVATE dependency)ve hedefle ilişkili tüm başlıklar dependency, hedefe ait kaynaklar için mevcut olacak target. Ve hiçbirine ihtiyacın yok [target_]include_directories. Bu, aşağıda analizde gösterilecektir. Birim testleri için CMake betiği.
Bu komut, ihtiyacımız olan başlıkları arayüz kitaplığımızla ilişkilendirir ve eğer kitaplığımız aynı CMake hiyerarşisi içindeki herhangi bir hedefe bağlıysa dizindeki başlıklar onunla ilişkilendirilir. ${CMAKE_CURRENT_SOURCE_DIR}/include, ve eğer kütüphanemiz sistemde kuruluysa ve komutu kullanarak başka bir projeye bağlıysa find_package, daha sonra dizindeki başlıklar onunla ilişkilendirilecek include kurulum dizinine göre.
Dil standardını belirleyelim. Tabii ki en sonuncusu. Aynı zamanda sadece standardı dahil etmiyoruz, kütüphanemizi kullanacak kişilere de yaygınlaştırıyoruz. Bu, set özelliğinin bir kategoriye sahip olması nedeniyle elde edilir. INTERFACE (Bkz. target_compile_features komutu).
Kütüphanemiz için bir takma ad oluşturalım. Üstelik güzellik için özel bir “isim alanı” içinde olacak. Kütüphanemizde farklı modüller göründüğünde ve bunları birbirinden bağımsız olarak bağlamaya gittiğimizde bu faydalı olacaktır. Mesela Busta'daki gibi.
Başlıklarımızı sisteme yüklüyoruz. Burada her şey basit. Tüm başlıkların bulunduğu klasörün dizine gitmesi gerektiğini söylüyoruz include Kurulum konumuna göre.
Bir sonraki büyü bu şekilde anlaşılmalıdır. Üçüncü taraf bir projedeyken komutu çağırıyoruz find_package(Mylib 1.2.3 REQUIRED)ve yüklü kitaplığın gerçek sürümü, sürümle uyumsuz olacaktır. 1.2.3CMake otomatik olarak bir hata üretecektir. Yani sürümleri manuel olarak takip etmenize gerek kalmayacak.
Testler açıkça kullanılarak devre dışı bırakılırsa karşılık gelen seçenek veya projemiz alt projedir yani başka bir CMake projesine şu komutla bağlanır add_subdirectory, hiyerarşide daha fazla ilerlemeyiz ve testleri oluşturmaya ve çalıştırmaya yönelik komutları açıklayan komut dosyası çalışmaz.
if(NOT MYLIB_TESTING)
message(STATUS "Тестирование проекта Mylib выключено")
elseif(IS_SUBPROJECT)
message(STATUS "Mylib не тестируется в режиме подмодуля")
else()
add_subdirectory(test)
endif()
Bağımlılıkları birbirine bağlıyoruz. Lütfen yalnızca ihtiyacımız olan CMake hedeflerini ikili dosyamıza bağladığımızı ve komutu çağırmadığımızı unutmayın. target_include_directories. Test çerçevesinden ve bizimkilerden başlıklar Mylib::mylib, ve derleme parametreleri (bizim durumumuzda bu, C++ dil standardıdır) bu hedeflerle birlikte ortaya çıktı.
Son olarak, "derlemesi" test çalıştırmaya eşdeğer olan yapay bir hedef oluştururuz ve bu hedefi varsayılan yapıya ekleriz (bundan nitelik sorumludur) ALL). Bu, varsayılan yapının testleri çalıştırmayı tetiklediği anlamına gelir; bu da onları çalıştırmayı asla unutmayacağımız anlamına gelir.
add_custom_target(check ALL COMMAND mylib-unit-tests)
Daha sonra uygun seçeneğin belirtilmesi durumunda kod kapsamı ölçümünü etkinleştiriyoruz. Ayrıntılara girmeyeceğim çünkü bunlar CMake'ten çok kapsamı ölçmek için kullanılan bir araçla ilgilidir. Sadece sonuçlara göre bir hedefin oluşturulacağını unutmamak önemlidir. coverageKapsamı ölçmeye başlamanın uygun olduğu.
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()
Daha sonra kullanıcının dil değişkenini ayarlayıp ayarlamadığını kontrol ederiz. Eğer evet ise, o zaman ona dokunmayız, değilse, o zaman Rusça alırız. Daha sonra Doxygen sistem dosyalarını yapılandırıyoruz. Dil de dahil olmak üzere gerekli tüm değişkenler yapılandırma işlemi sırasında oraya gider (bkz. команду configure_file).
Daha sonra bir hedef oluşturuyoruz doc, dokümantasyon oluşturmaya başlayacak. Belge oluşturmak geliştirme sürecindeki en büyük ihtiyaç olmadığından hedef varsayılan olarak etkinleştirilmeyecek; açıkça başlatılması gerekecek.
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 ()
Burada üçüncü Python'u buluyoruz ve bir hedef oluşturuyoruz wandboxhizmet API'sine karşılık gelen bir istek üreten Asa kutusuve onu uzaklaştırır. Yanıt, tamamlanmış sanal alana bir bağlantıyla birlikte gelir.
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()
Birim testi derlemesini ve hedefini devre dışı bırakma yeteneği sağlar check. Sonuç olarak, testlerle kod kapsamının ölçümü kapatılır (bkz. MYLIB_COVERAGE).
Proje, komut kullanılarak başka bir projeye alt proje olarak bağlanırsa test de otomatik olarak devre dışı bırakılır. add_subdirectory.
Hizmet bunun için kullanılıyor Asa kutusu. Sunucularının ne kadar esnek olduğunu bilmiyorum ama bu fırsatın suiistimal edilmemesi gerektiğini düşünüyorum.
Aslında CMake sürüm 3.13 yalnızca bu yardımda açıklanan konsol komutlarından bazılarını çalıştırmak için gereklidir. CMake komut dosyalarının sözdizimi açısından bakıldığında, nesil başka yollarla çağrılırsa sürüm 3.8 yeterlidir.
CMake, her zevke ve renge uygun işlevsellik uygulamanıza olanak tanıyan çok güçlü ve esnek bir sistemdir. Ve sözdizimi bazen arzulanan çok şey bıraksa da, şeytan hâlâ resmedildiği kadar korkunç değildir. CMake derleme sistemini toplumun ve sağlığın yararına kullanın.