Başlangıç olarak, göz ardı edemeyeceğiniz bazı geleneksel isimler vardır, bunlar Unix dosya sistemindeki uzun geleneğe dayanmaktadır. Bunlar:
trunk
├── bin : for all executables (applications)
├── lib : for all other binaries (static and shared libraries (.so or .dll))
├── include : for all header files
├── src : for source files
└── doc : for documentation
En azından en üst düzeyde bu temel düzene bağlı kalmak muhtemelen iyi bir fikirdir.
Başlık dosyalarını ve kaynak dosyalarını (cpp) bölme hakkında, her iki şema da oldukça yaygındır. Ancak, onları bir arada tutmayı tercih ediyorum, günlük işlerde dosyaların bir arada olması daha pratik. Ayrıca, kodun tamamı tek bir üst düzey klasörün, yani klasörün altında olduğunda trunk/src/
, diğer tüm klasörlerin (bin, lib, include, doc ve belki bazı test klasörlerinin) en üst düzeyde olduğunu ve buna ek olarak kaynak dışı derlemenin "derleme" dizini, oluşturma sürecinde oluşturulan dosyalardan başka bir şey içermeyen tüm klasörlerdir. Ve bu nedenle, yalnızca src klasörünün yedeklenmesi veya daha da iyisi bir sürüm kontrol sistemi / sunucusu (Git veya SVN gibi) altında tutulması gerekir.
Ve başlık dosyalarınızı hedef sisteme yüklemek söz konusu olduğunda (sonunda kitaplığınızı dağıtmak istiyorsanız), CMake'in dosyaları yüklemek için bir komutu vardır (örtük olarak bir "yükleme" hedefi oluşturur, "make install" yapmak için) tüm başlıkları /usr/include/
dizine yerleştirmek için kullanabilirsiniz . Bu amaçla sadece aşağıdaki cmake makrosunu kullanıyorum:
# custom macro to register some headers as target for installation:
# setup_headers("/path/to/header/something.h" "/relative/install/path")
macro(setup_headers HEADER_FILES HEADER_PATH)
foreach(CURRENT_HEADER_FILE ${HEADER_FILES})
install(FILES "${SRCROOT}${CURRENT_HEADER_FILE}" DESTINATION "${INCLUDEROOT}${HEADER_PATH}")
endforeach(CURRENT_HEADER_FILE)
endmacro(setup_headers)
Nerede SRCROOT
Ben src klasörüne belirlemesinin bir cmake değişkendir ve INCLUDEROOT
ben başlıklarına gitmeye gerek her yere yapılandırmanız cmake değişkendir. Tabii ki, bunu yapmanın birçok yolu var ve eminim ki benim yöntemim en iyisi değildir. Mesele şu ki, başlıkları ve kaynakları ayırmak için bir neden yok çünkü hedef sisteme yalnızca başlıkların yüklenmesi gerekiyor, çünkü özellikle CMake (veya CPack) ile başlıkları seçip yapılandırmak çok kolay. ayrı bir dizinde bulundurmak zorunda kalmadan kurulabilir. Ve çoğu kütüphanede gördüğüm şey bu.
Alıntı: İkinci olarak, kullanımı oldukça kolay göründüğü için kodumu birim test etmek için Google C ++ Test Çerçevesini kullanmak istiyorum. Bunu kodumla, örneğin bir "inc / gtest" veya "katkıda / gtest" klasöründe paketlemenizi önerir misiniz? Paketlenmişse, sayıyı veya dosyaları azaltmak için fuse_gtest_files.py komut dosyasını kullanmanızı veya olduğu gibi bırakmanızı önerir misiniz? Paketlenmemişse, bu bağımlılık nasıl ele alınır?
Bağımlılıkları kitaplığınızla birleştirmeyin. Bu genellikle oldukça korkunç bir fikir ve bunu yapan bir kütüphane oluşturmaya çalışırken takılıp kaldığımda her zaman bundan nefret ediyorum. Bu sizin son çare olmalı ve tuzaklara karşı dikkatli olun. Çoğu zaman, insanlar ya korkunç bir geliştirme ortamını (örneğin, Windows) hedefledikleri için ya da söz konusu kitaplığın yalnızca eski (kullanımdan kaldırılmış) bir sürümünü (bağımlılık) destekledikleri için bağımlılıkları kitaplıklarıyla bir araya toplarlar. Temel tuzak, paketlenmiş bağımlılığınızın aynı kitaplığın / uygulamanın halihazırda yüklenmiş sürümleriyle çakışabilir (örneğin, gtest'i paketlediniz, ancak kitaplığınızı oluşturmaya çalışan kişi zaten daha yeni (veya daha eski) bir gtest sürümüne sahipse, o zaman ikisi çatışabilir ve o kişiye çok kötü bir baş ağrısı verebilir). Yani, dediğim gibi, riski size ait olacak şekilde yapın. ve sadece son çare olarak söyleyebilirim. İnsanlardan kitaplığınızı derlemeden önce birkaç bağımlılık kurmalarını istemek, paketlenmiş bağımlılıklarınız ve mevcut kurulumlarınız arasındaki çatışmaları çözmeye çalışmaktan çok daha az kötüdür.
Alıntı: Yazma testleri söz konusu olduğunda, bunlar genel olarak nasıl düzenlenir? Her sınıf için (örneğin test_vector3.cpp) bir cpp dosyasına sahip olmayı düşünüyordum, ancak hepsi birlikte kolayca çalıştırılabilmeleri için tek bir ikili dosyada derlendi mi?
Sınıf başına bir cpp dosyası (veya küçük birleşik sınıflar ve işlevler grubu) bence daha normal ve pratiktir. Ancak, kesinlikle, hepsini tek bir ikili dosyada derlemeyin, böylece "hepsi birlikte çalıştırılabilir". Bu gerçekten kötü bir fikir. Genel olarak, kodlama söz konusu olduğunda, makul olduğu kadar işleri bölmek istersiniz. Birim testleri söz konusu olduğunda, tek bir ikilinin tüm testleri çalıştırmasını istemezsiniz, çünkü bu, kitaplığınızdaki herhangi bir şeyde yapacağınız herhangi bir küçük değişikliğin muhtemelen o birim test programının neredeyse tamamen yeniden derlenmesine neden olacağı anlamına gelir. ve bu, yeniden derlemeyi bekleyen dakikalar / saatler. Basit bir şemaya bağlı kalın: 1 birim = 1 birim test programı. Sonra,
Alıntı: gtest kütüphanesi genellikle cmake ve make kullanılarak inşa edildiğinden, projemin de böyle inşa edilmesinin mantıklı olacağını düşünüyordum. Aşağıdaki proje düzenini kullanmaya karar verirsem:
Bu düzeni önermeyi tercih ederim:
trunk
├── bin
├── lib
│ └── project
│ └── libvector3.so
│ └── libvector3.a products of installation / building
├── docs
│ └── Doxyfile
├── include
│ └── project
│ └── vector3.hpp
│_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
│
├── src
│ └── CMakeLists.txt
│ └── Doxyfile.in
│ └── project part of version-control / source-distribution
│ └── CMakeLists.txt
│ └── vector3.hpp
│ └── vector3.cpp
│ └── test
│ └── test_vector3.cpp
│_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
│
├── build
└── test working directories for building / testing
└── test_vector3
Burada dikkat edilmesi gereken birkaç nokta. İlk olarak, src dizininizin alt dizinleri, içerme dizininizin alt dizinlerini yansıtmalıdır; bu, yalnızca şeyleri sezgisel tutmak içindir (ayrıca, alt dizin yapınızı makul derecede düz (sığ) tutmaya çalışın, çünkü klasörlerin derinlemesine yuvalanması genellikle her şeyden çok güçlüktür). İkincisi, "include" dizini sadece bir kurulum dizinidir, içeriği src dizininden seçilen başlıklardır.
Üçüncüsü, CMake sisteminin en üst düzeyde bir CMakeLists.txt dosyası olarak değil, kaynak alt dizinler üzerinden dağıtılması amaçlanmıştır. Bu, her şeyi yerel tutar ve bu iyidir (her şeyi bağımsız parçalara bölme ruhuyla). Yeni bir kaynak, yeni bir başlık veya yeni bir test programı eklerseniz, ihtiyacınız olan tek şey söz konusu alt dizindeki küçük ve basit bir CMakeLists.txt dosyasını başka hiçbir şeyi etkilemeden düzenlemektir. Bu aynı zamanda dizinleri kolaylıkla yeniden yapılandırmanıza izin verir (CMakeLists yereldir ve taşınan alt dizinlerde yer alır). En üst düzey CMakeListleri, hedef dizinleri, özel komutları (veya makroları) ayarlama ve sistemde yüklü paketleri bulma gibi üst düzey yapılandırmaların çoğunu içermelidir. Alt düzey CMakeListleri yalnızca basit başlıkların, kaynakların ve kaynakların listelerini içermelidir.
Alıntı: Yalnızca kitaplığı veya kitaplığı ve testleri oluşturabilmesi için CMakeLists.txt'nin nasıl görünmesi gerekir?
Temel yanıt, CMake'in belirli hedefleri "tümü" nden ("make" yazdığınızda oluşturulan şey) özel olarak hariç tutmanıza izin vermesidir ve ayrıca belirli hedef grupları da oluşturabilirsiniz. Burada bir CMake eğitimi yapamam, ancak kendi başınıza öğrenmek oldukça basittir. Bununla birlikte, bu özel durumda, elbette, önerilen çözüm, birim olarak işaretlenmiş bir dizi hedefi (programı) kaydetmek için CMakeLists dosyalarında kullanabileceğiniz ek bir komut seti olan CTest'i kullanmaktır. testleri. Dolayısıyla, CMake tüm testleri özel bir yapı kategorisine koyacak ve tam olarak istediğiniz şey bu, yani problem çözüldü.
Alıntı: Ayrıca, bir bin dizini oluşturma reklamı olan birkaç proje gördüm. Yapı, yapı dizininde mi oluyor ve ardından ikili dosyalar bin dizinine mi taşınıyor? Testler ve kütüphane için ikili dosyalar aynı yerde mi yaşar? Veya aşağıdaki gibi yapılandırmak daha mantıklı olur mu:
Kaynağın dışında bir derleme dizinine sahip olmak ("kaynak dışı" derleme) gerçekten yapılacak tek mantıklı şeydir, bu günlerde fiili standarttır. Dolayısıyla, kesinlikle, CMake insanlarının önerdiği ve şimdiye kadar tanıştığım her programcının yaptığı gibi, kaynak dizinin dışında ayrı bir "yapı" dizinine sahip olun. Bin dizinine gelince, bu bir kongre ve bu yazının başında söylediğim gibi, ona bağlı kalmak muhtemelen iyi bir fikirdir.
Alıntı: Kodumu belgelemek için doxygen kullanmak istiyorum. Bunun otomatik olarak cmake ve make ile çalışmasını sağlamak mümkün mü?
Evet. Mümkün olandan daha fazlası, harika. Ne kadar süslü olmak istediğinize bağlı olarak, birkaç olasılık vardır. CMake, find_package(Doxygen)
bazı dosyalarda Doxygen çalıştıracak hedefleri kaydetmenize olanak tanıyan Doxygen (yani ) için bir modüle sahiptir . Doxyfile'daki sürüm numarasını güncellemek veya kaynak dosyalar için otomatik olarak bir tarih / yazar damgası girmek gibi daha süslü şeyler yapmak istiyorsanız, hepsi biraz CMake kung-fu ile mümkündür. Genel olarak, bunu yapmak, bulunacak ve CMake'nin ayrıştırma komutları ile değiştirilecek tokenlere sahip bir Doxyfile kaynağını (örneğin, yukarıdaki klasör düzenine koyduğum "Doxyfile.in") tutmanızı gerektirecektir. En üst düzey CMakeLists dosyamda , cmake-doxygen ile birkaç süslü şey yapan böyle bir CMake kung-fu parçası bulacaksınız.