CMake nasıl kullanılır? [kapalı]


100

Yeni başlayanlar olarak CMake hakkında herhangi bir yararlı bilgi edinmek herkesin bildiği gibi zordur. Şimdiye kadar, çok basit bir projenin veya başka bir projenin nasıl kurulacağına dair birkaç öğretici gördüm. Ancak bunların hiçbiri, içlerinde gösterilen herhangi bir şeyin arkasındaki mantığı açıklamaz ve her zaman doldurulacak birçok boşluk bırakır.

CMakeLists'de CMake'i çağırmak ne anlama geliyor ? Her yapı ağacı için bir kez mi çağrılması gerekiyor, yoksa ne? Hepsi aynı kaynaktan aynı CMakeLists.txt dosyasını kullanıyorsa, her derleme için farklı ayarları nasıl kullanırım? Neden her alt dizinin kendi CMakeLists dosyasına ihtiyacı var? CMake'i CMakeLists.txt üzerinde, projenin kökünden farklı bir şekilde kullanmak mantıklı olur mu? Eğer öyleyse, hangi durumlarda? CMakeLists dosyasından kendi alt dizinindeki bir yürütülebilir dosyanın veya kitaplığın nasıl oluşturulacağını belirtmekle, bunu tüm kaynağın kökündeki CMakeLists dosyasında yapmak arasındaki fark nedir? Eclipse için bir proje ve Visual Studio için başka bir proje oluşturabilir miyim, sadece -GCMake'i çağırırken seçeneği değiştirebilir miyim? Böyle mi kullanılıyor?

Şimdiye kadar gördüğüm öğreticiler, belge sayfaları veya soruların / yanıtların hiçbiri, CMake'in nasıl kullanılacağını anlamaya yönelik herhangi bir yararlı fikir vermiyor. Örnekler tam değil. Hangi dersi okuduğum önemli değil, önemli bir şeyi kaçırdığımı hissediyorum.

Benim gibi CMake yeni başlayanlar tarafından sorulan ve bunu açıkça sormayan birçok soru var, ancak bu, yeniler olarak CMake ile nasıl başa çıkacağımız veya bundan ne çıkaracağımız hakkında hiçbir fikrimiz olmadığı gerçeğini açıkça ortaya koyuyor.


8
Belki onun yerine bir blog yazısı yazmalısın.
steveire

2
"Çok geniş" oylamayı kapatmaya başladım ... Bu, yığın aşımı için iyi bir uyumdan çok CMake üzerine kişisel bir makale gibi geliyor. Neden tüm bu soruları ayrı sorulara koymadınız? Soru + yanıtınız diğerlerinden nasıl farklıdır, örneğin stackoverflow.com/q/20884380/417197 , stackoverflow.com/q/4745996/417197 , stackoverflow.com/q/4506193/417197 ?
André

14
@Andre Neden bu soru: CMake'i anlamaya çalışırken bir hafta geçirdim ve bulduğum hiçbir öğretici tamamlanmadı. Gösterdiğiniz bağlantılar iyidir, ancak CMake'yi bulan biri için, içeride bir grup CMakeList ile kendilerine bir proje fırlatılan bir proje var, CMake'nin nasıl çalıştığına çok fazla ışık tutmazlar. Dürüst olmak gerekirse, CMake'yi öğrenmeye başladığımda kendime zamanında geri gönderebilmeyi dilediğim bir cevabı yazmaya çalıştım. Ve alt sorular, bu şüphelere sahip olmamak için aslında bilmem gereken şeyin ne olduğunu sormaya çalıştığımı göstermek içindir. Doğru soruyu sormak ZOR.
leinaD_natipaC

2
Cevap değil, ama sizi jaws.rootdirectory.de'ye bir göz atmaya davet ediyorum . CKağıt Dokumentation'a (ve kabul cevap ...) ne ait birçok ısırık büyüklüğünde parçacıkları gösterileri Oysa olabilir yapmak, bunu boyunca yorumlar dahil, bir (hiçbir şekilde "tam" veya "mükemmel") temel kurulum yukarı yazdım IMHO, CMake'nin (ve CTest ve CPack ve CDash ...) sizin için neler yapabileceğini gösterir. Kutudan çıkar çıkmaz inşa eder ve projenizin ihtiyaçlarına kolayca uyarlayabilir / genişletebilirsiniz.
DevSolar

10
Bugünlerde bu tür soruların kapanması utanç verici. Cevaplar gibi öğretici gerektiren ancak yetersiz / belirsiz şekilde belgelenmiş konularla ilgili geniş soruların (başka bir örnek Torch7 C api olabilir) ve araştırma seviyesindeki soruların açık kalması gerektiğini düşünüyorum. Bunlar, siteyi rahatsız eden tipik "hey, bazı oyuncak projeleri yaparken bir segfault'um var" olandan çok daha ilginç.
Ash

Yanıtlar:


144

CMake ne içindir?

Wikipedia'ya göre:

CMake, derleyiciden bağımsız bir yöntem kullanarak yazılım oluşturma sürecini yönetmek için [...] bir yazılımdır. Birden çok kitaplığa bağlı olan dizin hiyerarşilerini ve uygulamaları desteklemek için tasarlanmıştır. Make, Apple'ın Xcode'u ve Microsoft Visual Studio gibi yerel derleme ortamlarıyla birlikte kullanılır.

CMake ile artık derleyicinize / derleme ortamınıza özgü ayrı ayarlar tutmanıza gerek kalmaz. Tek bir yapılandırmanız var ve bu birçok ortam için çalışıyor .

CMake, içindeki hiçbir şeyi değiştirmeden aynı dosyalardan bir Microsoft Visual Studio çözümü, bir Eclipse projesi veya bir Makefile labirenti oluşturabilir .

İçlerinde kod bulunan bir grup dizin verildiğinde, CMake tüm bağımlılıkları, derleme siparişlerini ve projenizin derlenmeden önce yapılması gereken diğer görevleri yönetir. Aslında hiçbir şey derlemez. CMake'i kullanmak için (CMakeLists.txt adlı yapılandırma dosyalarını kullanarak) hangi yürütülebilir dosyaları derlemeniz gerektiğini, hangi kitaplıklara bağlandıklarını, projenizde hangi dizinlerin olduğunu ve bunların içinde ne olduğunu ve bayraklar gibi ayrıntıları söylemelisiniz. veya ihtiyacınız olan herhangi bir şey (CMake oldukça güçlüdür).

Bu doğru bir şekilde ayarlanmışsa, seçtiğiniz "yerel oluşturma ortamının" işini yapması için ihtiyaç duyduğu tüm dosyaları oluşturmak için CMake kullanırsınız. Linux'ta varsayılan olarak bu Makefiles anlamına gelir. Yani CMake'i çalıştırdığınızda, kendi kullanımı için bir sürü dosya ve bazı dosyalar oluşturacaktır Makefile. Bundan sonra yapmanız gereken tek şey, kodunuzu her düzenlemeyi bitirdiğinizde kök klasörden konsola "make" yazmaktır ve bam, derlenmiş ve bağlantılı bir yürütülebilir dosya oluşturulur.

CMake nasıl çalışır? Bu ne işe yarıyor?

İşte boyunca kullanacağım örnek bir proje kurulumu:

simple/
  CMakeLists.txt
  src/
    tutorial.cxx
    CMakeLists.txt
  lib/
    TestLib.cxx
    TestLib.h
    CMakeLists.txt
  build/

Her dosyanın içeriği daha sonra gösterilir ve tartışılır.

CMake, projenizi projenizin köküne göre ayarlar CMakeLists.txtve bunu cmakekonsolda çalıştırdığınız dizine göre yapar . Bunu projenizin kökü olmayan bir klasörden yapmak , kaynak dışı derleme denen şeyi üretir , bu da derleme sırasında oluşturulan dosyaların (obj dosyaları, lib dosyaları, çalıştırılabilirler, bilirsiniz) söz konusu klasöre yerleştirileceği anlamına gelir. , gerçek koddan ayrı tutulur. Dağınıklığı azaltmaya yardımcı olur ve tartışmayacağım başka nedenlerle de tercih edilir.

cmakeKök dışında herhangi bir şekilde çalıştırırsanız ne olur bilmiyorum CMakeLists.txt.

Bu örnekte, hepsinin build/klasörün içine yerleştirilmesini istediğim için , önce oraya gitmem, sonra da geçmem gerekiyor CMakeLists.txt. Kökün bulunduğu dizini al .

cd build
cmake ..

Varsayılan olarak, bu, söylediğim gibi her şeyi Makefiles kullanarak ayarlar. Yapı klasörünün şimdi nasıl görünmesi gerektiği aşağıda açıklanmıştır:

simple/build/
  CMakeCache.txt
  cmake_install.cmake
  Makefile
  CMakeFiles/
    (...)
  src/
    CMakeFiles/
      (...)
    cmake_install.cmake
    Makefile
  lib/
    CMakeFiles/
      (...)
    cmake_install.cmake
    Makefile

Tüm bu dosyalar nedir? Endişelenmeniz gereken tek şey Makefile ve proje klasörleridir .

src/Ve lib/klasörlerine dikkat edin . Bunlar simple/CMakeLists.txt, komutu kullanarak onları işaret ettiği için oluşturulmuştur add_subdirectory(<folder>). Bu komut CMake'ye söz konusu klasöre başka bir CMakeLists.txtdosya bakmasını ve bu komut dosyasını çalıştırmasını söyler , böylece bu şekilde eklenen her alt dizinin içinde bir dosya olmalıdırCMakeLists.txt . Bu projede, simple/src/CMakeLists.txtgerçek yürütülebilir dosyanın simple/lib/CMakeLists.txtnasıl oluşturulacağını ve kitaplığın nasıl oluşturulacağını açıklar. CMakeLists.txtAçıklanan her hedef, varsayılan olarak yapı ağacındaki alt dizinine yerleştirilecektir. Yani, kısa bir süre sonra

make

konsolda build/, bazı dosyalar eklenir:

simple/build/
  (...)
  lib/
    libTestLib.a
    (...)
  src/
    Tutorial
    (...)

Proje oluşturuldu ve yürütülebilir dosya yürütülmeye hazır. Yürütülebilir dosyaların belirli bir klasöre yerleştirilmesini istiyorsanız ne yaparsınız? Uygun CMake değişkenini ayarlayın veya belirli bir hedefin özelliklerini değiştirin . CMake değişkenleri hakkında daha sonra.

CMake'e projemi nasıl oluşturacağını nasıl söylerim?

Kaynak dizindeki her dosyanın içeriği açıklanmıştır:

simple/CMakeLists.txt:

cmake_minimum_required(VERSION 2.6)

project(Tutorial)

# Add all subdirectories in this project
add_subdirectory(lib)
add_subdirectory(src)

Gerekli olan minimum sürüm, siz yapmadığınızda CMake'nin attığı uyarıya göre her zaman ayarlanmalıdır. CMake sürümünüz ne olursa olsun kullanın.

Projenizin adı daha sonra kullanılabilir ve aynı CMake dosyalarından birden fazla projeyi yönetebileceğiniz gerçeğine işaret eder. Yine de bununla ilgilenmeyeceğim.

Daha önce bahsedildiği gibi add_subdirectory(), projeye bir klasör ekler, bu da CMake'in bir CMakeLists.txtiçinde olmasını beklediği ve devam etmeden önce çalışacağı anlamına gelir . Bu arada, tanımlanmış bir CMake işlevine sahipseniz, onu CMakeLists.txtalt dizinlerdeki diğer URL'lerden kullanabilirsiniz , ancak kullanmadan önce tanımlamanız add_subdirectory()gerekir, yoksa bulamaz. CMake kütüphaneler konusunda daha akıllıdır, bu yüzden muhtemelen bu tür bir problemle karşılaşacağınız tek zaman budur.

simple/lib/CMakeLists.txt:

add_library(TestLib TestLib.cxx)

Kendi kitaplığınızı oluşturmak için ona bir ad verin ve ardından oluşturduğu tüm dosyaları listeleyin. Basit. Derlenmesi için başka bir dosyaya ihtiyaç foo.cxxduysaydı, onun yerine yazardın add_library(TestLib TestLib.cxx foo.cxx). Bu, örneğin diğer dizinlerdeki dosyalar için de işe yarar add_library(TestLib TestLib.cxx ${CMAKE_SOURCE_DIR}/foo.cxx). CMAKE_SOURCE_DIR değişkeni hakkında daha sonra daha fazlası.

Bununla yapabileceğiniz başka bir şey, paylaşılan bir kitaplık istediğinizi belirtmektir. Örnek: add_library(TestLib SHARED TestLib.cxx). Korkmayın, CMake hayatınızı kolaylaştırmaya başladığı yerdir. Paylaşılmış olsun ya da olmasın, bu şekilde oluşturulmuş bir kitaplığı kullanmak için yapmanız gereken tek şey ona burada verdiğiniz addır. Bu kütüphanenin adı artık TestLib'tir ve projenin herhangi bir yerinden ona başvurabilirsiniz . CMake onu bulacaktır.

Bağımlılıkları listelemenin daha iyi bir yolu var mı? Kesinlikle evet . Bununla ilgili daha fazla bilgi için aşağıya bakın.

simple/lib/TestLib.cxx:

#include <stdio.h>

void test() {
  printf("testing...\n");
}

simple/lib/TestLib.h:

#ifndef TestLib
#define TestLib

void test();

#endif

simple/src/CMakeLists.txt:

# Name the executable and all resources it depends on directly
add_executable(Tutorial tutorial.cxx)

# Link to needed libraries
target_link_libraries(Tutorial TestLib)

# Tell CMake where to look for the .h files
target_include_directories(Tutorial PUBLIC ${CMAKE_SOURCE_DIR}/lib)

Komut , elbette bunun yerine bir yürütülebilir dosya oluşturması dışında, add_executable()tamamen aynı şekilde çalışır add_library(). Bu yürütülebilir dosya artık gibi şeyler için bir hedef olarak gösterilebilir target_link_libraries(). Tutorial.cxx, TestLib kitaplığında bulunan kodu kullandığından, bunu gösterildiği gibi CMake'e yönlendirirsiniz.

Benzer şekilde, herhangi bir kaynaklarca #include herhangi .h dosyaları add_executable()o vardır değil kaynak nasılsa eklenmesi gerekir aynı dizinde. target_include_directories()Komut için değilse , lib/TestLib.hTutorial derlenirken bulunmaz, bu nedenle tüm lib/klasör #includes için aranacak içerme dizinlerine eklenir. include_directories()Tüm çalıştırılabilir dosyalar için doğrudan genel olarak belirlediği için bir hedef belirtmenize gerek olmaması dışında, benzer şekilde davranan komutu da görebilirsiniz . Bir kez daha, CMAKE_SOURCE_DIR'i daha sonra açıklayacağım.

simple/src/tutorial.cxx:

#include <stdio.h>
#include "TestLib.h"
int main (int argc, char *argv[])
{
  test();
  fprintf(stdout, "Main\n");
  return 0;
}

"TestLib.h" dosyasının nasıl dahil edildiğine dikkat edin. Tam yolu eklemeye gerek yok: CMake sayesinde perde arkasındaki her şeyi hallediyor target_include_directories().

Teknik olarak siz olmadan bu gibi basit bir kaynak ağacında, olabilir konuşan CMakeLists.txtaltında s lib/ve src/sadece böyle bir şey eklemeden add_executable(Tutorial src/tutorial.cxx)için simple/CMakeLists.txt. Size ve projenizin ihtiyaçlarına bağlıdır.

CMake'i doğru şekilde kullanmak için başka ne bilmeliyim?

(Anlayışınızla ilgili AKA konuları)

Paketleri bulmak ve kullanmak : Bu sorunun cevabı onu benim yapabileceğimden daha iyi açıklıyor.

Değişkenleri ve fonksiyonları bildirme, kontrol akışını kullanma vb .: CMake'nin sunduğu temel bilgileri açıklayan ve genel olarak iyi bir giriş niteliğindeki bu eğiticiye göz atın.

CMake değişkenleri : Bol miktarda var, bu yüzden sizi doğru yola sokmak için hızlandırılmış bir kurs var. CMake wiki, değişkenler ve görünüşte diğer şeyler hakkında daha derinlemesine bilgi almak için iyi bir yerdir .

Yapı ağacını yeniden oluşturmadan bazı değişkenleri düzenlemek isteyebilirsiniz. Bunun için ccmake kullanın (dosyayı düzenler CMakeCache.txt). Unutmayın cdeğişiklikleri ve daha sonra içinde yapıldığında onfigure ggüncellenmiş yapılandırmayla Nesli bozuk makefiles.

Değişkenleri kullanma hakkında bilgi edinmek için önceden atıfta bulunulan öğreticiyi okuyun , ancak uzun lafın kısası: set(<variable name> value)bir değişkeni değiştirmek veya oluşturmak için. ${<variable name>}kullanmak için.

  • CMAKE_SOURCE_DIR: Kaynağın kök dizini. Önceki örnekte, bu her zaman şuna eşittir:/simple
  • CMAKE_BINARY_DIR: Yapının kök dizini. Önceki örnekte, bu şuna eşittir simple/build/, ancak cmake simple/gibi bir klasörden koşarsanız , bu yapı ağacındaki foo/bar/etc/tüm başvurular CMAKE_BINARY_DIRolur /foo/bar/etc.
  • CMAKE_CURRENT_SOURCE_DIR: Dizin içinde mevcut CMakeLists.txtolan bu boyunca değişen bu araçlar. Bu baskı simple/CMakeLists.txtverimleri /simpleve onu baskı simple/src/CMakeLists.txtverimi /simple/src.
  • CMAKE_CURRENT_BINARY_DIR: Kaptın bu işi. Bu yol sadece yapının bulunduğu klasöre değil, aynı zamanda geçerli CMakeLists.txtbetiğin konumuna da bağlı olacaktır.

Bunlar neden önemlidir? Kaynak dosyalar açıkça yapı ağacında olmayacaktır. target_include_directories(Tutorial PUBLIC ../lib)Önceki örnekteki gibi bir şey denerseniz , bu yol inşa ağacına göre olacaktır, yani yazıya ${CMAKE_BINARY_DIR}/libbenzeyecek ve içeriye bakacaktır simple/build/lib/. Orada .h dosyası yok; en fazla bulacaksın libTestLib.a. Onun ${CMAKE_SOURCE_DIR}/libyerine istiyorsun .

  • CMAKE_CXX_FLAGS: Derleyiciye, bu durumda C ++ derleyicisine iletilecek bayraklar. Ayrıca DEBUG olarak ayarlanmışsa CMAKE_CXX_FLAGS_DEBUGbunun yerine hangisinin kullanılacağına dikkat edilmelidir CMAKE_BUILD_TYPE. Bunun gibi daha fazlası var; kontrol CKağıt wiki .
  • CMAKE_RUNTIME_OUTPUT_DIRECTORY: CMake'e derlendiğinde tüm yürütülebilir dosyaları nereye koyacağını söyleyin. Bu küresel bir ayardır. Örneğin, onu ayarlayabilir bin/ve her şeyi oraya düzgün bir şekilde yerleştirebilirsiniz. EXECUTABLE_OUTPUT_PATHbenzer, ancak yanılmanız durumunda kullanımdan kaldırılmıştır.
  • CMAKE_LIBRARY_OUTPUT_DIRECTORY: Benzer şekilde, CMake'e tüm kitaplık dosyalarını nereye koyacağını söyleyen genel bir ayar.

Hedef özellikleri : Bir yürütülebilir dosya veya bir kitaplık (veya bir arşiv ... fikri alırsınız), yalnızca bir hedefi etkileyen özellikleri ayarlayabilirsiniz. İşte nasıl kullanılacağına dair güzel bir örnek ( set_target_properties().

Bir hedefe otomatik olarak kaynak eklemenin kolay bir yolu var mı? Belirli bir dizindeki her şeyi aynı değişken altında listelemek için GLOB'u kullanın . Örnek sözdizimi FILE(GLOB <variable name> <directory>/*.cxx).

Farklı yapı türleri belirtebilir misiniz? Evet, bunun nasıl çalıştığından veya bunun sınırlamalarından emin değilim. Muhtemelen biraz if / then'ning gerektirir, ancak CMake, örneğin için varsayılanlar gibi herhangi bir şeyi yapılandırmadan bazı temel destek sunar CMAKE_CXX_FLAGS_DEBUG. Derleme türünüzü , örneğin, uygun bayraklarla konsoldan CMake'i çağırarak veya CMakeLists.txtdosya içinden ayarlayabilirsiniz .set(CMAKE_BUILD_TYPE <type>)cmake -DCMAKE_BUILD_TYPE=Debug

CMake kullanan herhangi bir iyi proje örneği var mı? Wikipedia'da, bakmak isterseniz, CMake kullanan açık kaynaklı projelerin bir listesi vardır. Çevrimiçi eğitimler bu konuda şimdiye kadar benim için bir hayal kırıklığından başka bir şey olmadı, ancak bu Stack Overflow sorusu oldukça havalı ve anlaşılması kolay bir CMake kurulumuna sahip. Bir bakmaya değer.

CMake'deki değişkenleri kodunuzda kullanma : İşte hızlı ve kirli bir örnek ( başka bir öğreticiden uyarlanmıştır ):

simple/CMakeLists.txt:

project (Tutorial)

# Setting variables
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 1)

# Configure_file(<input> <output>)
# Copies a file <input> to file <output> and substitutes variable values referenced in the file content.
# So you can pass some CMake variables to the source code (in this case version numbers)
configure_file (
  "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
  "${PROJECT_SOURCE_DIR}/src/TutorialConfig.h"
)

simple/TutorialConfig.h.in:

// Configured options and settings
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

CMake tarafından oluşturulan sonuç dosyası simple/src/TutorialConfig.h:

// Configured options and settings
#define Tutorial_VERSION_MAJOR 1
#define Tutorial_VERSION_MINOR 1

Bunların akıllıca kullanılmasıyla, bir kitaplığı kapatmak gibi harika şeyler yapabilirsiniz. Er ya da geç, daha büyük projelerde çok yararlı olması gereken biraz daha gelişmiş şeyler olduğu için bu eğiticiye bir göz atmanızı tavsiye ederim .

Diğer her şey için, Stack Overflow, başlatılmamış olanlar dışındaki herkes için harika olan belirli sorular ve kısa cevaplarla doludur.


2
Bu cevabı kabul ediyorum ama başka biri daha iyi, daha kısa bir cevap yazarsa, onu seçeceğim. Kendim yapardım ama zaten CMake yüzünden yeterince acı çektim.
leinaD_natipaC

7
Bu harika çalışma için teşekkürler. Umarım bu daha fazla oy alır! :)
LET

4
Oradaki oldukça az ifade edilen nokta: CMake ile artık derleyici / derleme ortamınıza özgü ayrı ayarları korumanıza gerek yok. Tek bir yapılandırmanız var ve bu, Visual Studio, Code Blocks, düz Unix Makefiles ve diğer birçok ortam için (çeşitli sürümleri) çalışır. İlk etapta CMake'e bakmamın nedeni buydu: Autoconf, MSVC 2005 / 32bit ve MSVC 2010 / 64bit konfigürasyonlarını senkronize halde tutmak büyük bir sorun oldu. Ve bunu bir kez öğrendiğimde, doküman oluşturma, test etme, paketleme vb. Gibi daha birçok şeyi platformlar arası bir şekilde ekledim.
DevSolar

1
@DevSolar True. Bu satırı Wikipedia'dakinden daha çok seviyorum, bu yüzden sakıncası yoksa yanıta ekleyeceğim. CMake'i bu etkiye nasıl doğru kullanacağıma dair hiçbir şeye uymayacağım. Bu daha çok neler olup bittiğini anlayabilmekle ilgili.
leinaD_natipaC

1
@RichieHH Örneği takiben, önce CMake'i Makefiles kullanacak şekilde yapılandırırsınız, ardından CMake'i projenizin oluşturulması gereken dosyaları oluşturmak için kullanırsınız ve son olarak CMake için endişelenmeyi bırakırsınız çünkü onun işi burada bitmiştir. Yani bundan böyle makeprojenizi yapmak için bash'da kullanmanız gerektiği anlamında Makefile hakkında "endişeleniyorsunuz" .
leinaD_natipaC
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.