Değişkenleri ayarlamak ve kullanmak için CMake sözdizimi nedir?


168

CMake'i bir sonraki kullanışımda bunu kendime hatırlatmak istiyorum. Asla yapışmaz ve Google sonuçları harika değildir.

CMake'de değişkenleri ayarlamak ve kullanmak için sözdizimi nedir?

Yanıtlar:


281

CMake komut dosyaları yazarken, sözdizimi ve CMake'de değişkenlerin nasıl kullanılacağı hakkında bilmeniz gereken çok şey vardır.

Sözdizimi

Dizeleri kullanarak set():

  • set(MyString "Some Text")
  • set(MyStringWithVar "Some other Text: ${MyString}")
  • set(MyStringWithQuot "Some quote: \"${MyStringWithVar}\"")

Veya string():

  • string(APPEND MyStringWithContent " ${MyString}")

Şunu kullanan listeler set():

  • set(MyList "a" "b" "c")
  • set(MyList ${MyList} "d")

Veya daha iyisi list():

  • list(APPEND MyList "a" "b" "c")
  • list(APPEND MyList "d")

Dosya Adlarının Listeleri:

  • set(MySourcesList "File.name" "File with Space.name")
  • list(APPEND MySourcesList "File.name" "File with Space.name")
  • add_excutable(MyExeTarget ${MySourcesList})

Dökümantasyon

Kapsam veya "Değişkenimin değeri nedir?"

İlk olarak "Normal Değişkenler" ve kapsamları hakkında bilmeniz gereken şeyler vardır:

  • Normal değişkenler görülebilir CMakeLists.txtdedikleri ayarlanır ve her şeyi vardır orada ( add_subdirectory(), include(), macro()ve function()).
  • add_subdirectory()Ve function()açtıkları-up çünkü kendi kapsamı komutları özeldir.
    • set(...)Oradaki anlam değişkenleri sadece orada görülebilir ve çağrıldıkları kapsam seviyesinin tüm normal değişkenlerinin bir kopyasını oluştururlar (üst kapsam olarak adlandırılır).
    • Dolayısıyla, bir alt dizinde veya işlevdeyseniz, üst kapsamda zaten var olan bir değişkeni set(... PARENT_SCOPE)
    • Değişken adını bir işlev parametresi olarak ileterek, örneğin işlevlerde bunu kullanabilirsiniz. Örnek olarak function(xyz _resultVar),set(${_resultVar} 1 PARENT_SCOPE)
  • Diğer yandan, ayarladığınız her şey include()veya macro()komut dosyaları, değişkenleri doğrudan çağrıldıkları yer kapsamında değiştirir.

İkincisi "Global Değişkenler Önbelleği" var. Önbellek hakkında bilmeniz gerekenler:

  • Geçerli kapsamda belirtilen ada sahip normal bir değişken tanımlanmamışsa, CMake eşleşen bir Önbellek girdisini arayacaktır.
  • Önbellek değerleri, CMakeCache.txtikili çıktı dizininizdeki dosyada saklanır .
  • Önbellekteki değerler , oluşturulmadan önce CMake'in GUI uygulamasında değiştirilebilir . Bu nedenle onlar - Normal değişkenlere göre - bir var typebir docstring. Normalde GUI kullanmıyorum, bu yüzden set(... CACHE INTERNAL "")genel ve kalıcı değerlerimi ayarlamak için kullanıyorum .

    Unutmayın ki INTERNALönbellek değişken türü anlamına gelmezFORCE

  • CMake komut dosyasında varolan Önbellek girdilerini yalnızca set(... CACHE ... FORCE)sözdizimi kullanıyorsanız değiştirebilirsiniz . Bu davranış, örneğin CMake'in kendisi tarafından kullanılır, çünkü normalde Önbellek girdilerini zorlamaz ve bu nedenle başka bir değerle önceden tanımlayabilirsiniz.

  • Önbellekteki girişleri sözdizimi ile cmake -D var:type=value(yalnızca cmake -D var=valueveya) ayarlamak için komut satırını kullanabilirsiniz cmake -C CMakeInitialCache.cmake.
  • İle Önbellekteki girişleri kaldırabilirsiniz unset(... CACHE).

Önbellek geneldir ve CMake komut dosyalarınızda neredeyse her yere ayarlayabilirsiniz. Ancak Önbellek değişkenlerini nerede kullanacağınızı düşünmenizi öneririm (bunlar globaldir ve kalıcıdır). Ben normalde kendi kalıcı olmayan değişkenlerimi tanımlamak için set_property(GLOBAL PROPERTY ...)ve set_property(GLOBAL APPEND PROPERTY ...)sözdizimini tercih ederim .

Değişken Tuzaklar ve "Değişken değişiklikleri nasıl ayıklanır?"

Tuzaklardan kaçınmak için değişkenler hakkında aşağıdakileri bilmelisiniz:

  • Her ikisi de aynı ada sahipse yerel değişkenler önbelleğe alınmış değişkenleri gizler
  • find_...Başarılı olursa - - komutlar önbelleğe değişkenler olarak sonuçlarını yazabilirim "böylece hiçbir çağrı yeniden arama edeceğini"
  • CMake'deki listeler yalnızca noktalı virgül sınırlayıcılı dizelerdir ve bu nedenle tırnak işaretleri önemlidir
    • set(MyVar a b c)öyle "a;b;c"ve set(MyVar "a b c")öyle"a b c"
    • Öneri, liste olarak bir liste vermek istediğinizde, her zaman bir istisna dışında tırnak işaretleri kullanmanızdır.
    • Genellikle list()listeleri işleme komutunu tercih edin
  • Yukarıda açıklanan tüm kapsam sorunu. Özellikle , yerel değişkenlerinizin ana kapsamda görünmesini istemediğiniz için functions()bunun yerine kullanılması önerilir macros().
  • CMake tarafından kullanılan birçok değişken project()ve enable_language()çağrıları ile ayarlanır . Bu yüzden, bu komutlar kullanılmadan önce bazı değişkenlerin ayarlanması önemli olabilir.
  • Ortam değişkenleri, CMake'nin make ortamını oluşturduğu yerden ve make dosyalarının ne zaman kullanıma alındığından farklı olabilir.
    • Ortam değişkenindeki bir değişiklik üretim sürecini yeniden tetiklemez.
    • Özellikle oluşturulan bir IDE ortamı komut satırınızdan farklı olabilir, bu nedenle ortam değişkenlerinizi önbelleğe alınmış bir şeye aktarmanız önerilir.

Bazen sadece hata ayıklama değişkenleri yardımcı olur. Aşağıdakiler size yardımcı olabilir:

  • Sadece komutu printfkullanarak eski hata ayıklama stilini message()kullanın. CMake'in kendisi ile birlikte gelen bazı kullanıma hazır modüller de vardır: CMakePrintHelpers.cmake , CMakePrintSystemInformation.cmake
  • CMakeCache.txtİkili çıktı dizininizdeki dosyaya bakın . Bu dosya, make ortamınızın gerçek nesli başarısız olursa bile oluşturulur.
  • Değişkenlerinizin nerede okunduğunu / yazıldığını / kaldırıldığını görmek için variable_watch () kullanın .
  • CACHE_VARIABLES ve VARIABLES dizin özelliklerine bakın
  • cmake --trace ...CMake'in tam ayrıştırma işlemini görmek için arayın . Bu bir tür son rezerv, çünkü çok fazla çıktı üretiyor.

Özel Sözdizimi

  • Ortam Değişkenleri
    • Ortam değişkenlerini okuyabilir $ENV{...}ve yazabilirsinizset(ENV{...} ...)
  • Jeneratör İfadeleri
    • Jeneratör ifadeleri $<...>yalnızca CMake'nin jeneratörü marka oluşturma ortamını yazdığında değerlendirilir (ayrıştırıcı tarafından "yerinde" değiştirilen normal değişkenlerle karşılaştırılır)
    • Çok kullanışlı, örneğin derleyici / bağlayıcı komut satırlarında ve çoklu yapılandırma ortamlarında
  • Referanslar
    • Bir ${${...}}değişkene değişken isimleri verebilir ve içeriğine başvurabilirsiniz.
    • Genellikle işlev / makro parametresi olarak bir değişken adı verilirken kullanılır.
  • Sabit Değerler ( if()komuta bakınız )
    • İle if(MyVariable)doğrudan sizinle doğru / yanlış için bir değişken (kapatmakta burada gerek kontrol edebilirsiniz ${...})
    • Gerçek sabitse 1, ON, YES, TRUE, Y, ya da sıfır olmayan bir sayı.
    • Yanlış sabitse 0, OFF, NO, FALSE, N, IGNORE, NOTFOUND, boş dize veya son eki biter -NOTFOUND.
    • Bu sözdizimi genellikle benzer bir şey için kullanılır if(MSVC), ancak bu sözdizimi kısayolunu bilmeyen biri için kafa karıştırıcı olabilir.
  • Özyinelemeli sübstitüsyonlar
    • Değişkenleri kullanarak değişken adları oluşturabilirsiniz. CMake değişkenleri değiştirdikten sonra, sonucun bir değişken olup olmadığını tekrar kontrol eder. Bu CMake'in kendisinde kullanılan çok güçlü bir özelliktir, örneğin bir çeşit şablon olarakset(CMAKE_${lang}_COMPILER ...)
    • Ancak bununif() komutlarda baş ağrısına neden olabileceğini unutmayın . İşte bir örnek CMAKE_CXX_COMPILER_IDolduğunu "MSVC"ve MSVCbir "1":
      • if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") doğrudur, çünkü if("1" STREQUAL "1")
      • if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") yanlıştır, çünkü if("MSVC" STREQUAL "1")
      • Dolayısıyla, buradaki en iyi çözüm - doğrudan bakın - doğrudan kontrol etmek if(MSVC)
    • İyi haber, bunun CMake 3.1'de CMP0054 politikasının getirilmesiyle düzeltildiğidir . Her zaman cmake_policy(SET CMP0054 NEW)"yalnızca if()bağımsız değişkenleri değişken veya anahtar kelime olarak tırnak işaretsiz olarak yorumla" olarak ayarlamanız önerilir .
  • option()komuta
    • Temelde sadece önbelleğe alınmış dizeler sadece olabilir ONveya OFFbunlar gibi bağımlılıklar gibi bazı özel işlemlere izin verir
    • Ama farkında , hata yok optionolan setkomuta. Verilen değer optiongerçekten yalnızca "başlangıç ​​değeri" dir (ilk yapılandırma adımı sırasında bir kez önbelleğe aktarılır) ve daha sonra CMake'in GUI'si aracılığıyla kullanıcı tarafından değiştirilmesi amaçlanır .

Referanslar


Ben kullandığınızda if ("${MyString}" ...)görüyorum uyarıları değilim: Policy CMP0054 is not set: Only interpret if() arguments as variables or keywords when unquoted. Bkz. Örneğin, Yapı 367 . Herhangi bir fikir?
jww

Ve unquoting ${MyString}için hataların bir grup potansiyel müşteri "eğer verilen argümanlar ..." gibi eğer yakınındaki CKağıt hatası: parantez ardından “verilen argümanlar eğer”, “DEĞİL”, “EŞİT” ve benzeri .
jww

@jww Uyarı MyString, daha sonra yeniden referans verilecek bir değişken adı içeren anlamına gelir . Kimsenin bu OLDdavranışı gerçekten istemediğine inanıyorum . Yani benim açımdan gelen onun tamamen güvenli ve yalnızca kümesi politikasına uyumlu geriye CMP0054üzere NEW(tartışma burada ).
Florian

@jww Ve bu sorunlardan / uyarılardan kaçınmanın en güvenli yolu sadece bunu yapmaktır if (MyString ...)(eğer kodunuz uyarı verirse).
Florian

Teşekkürler. İle ilgili tüm tekrarları kaldırdık ${MyString}ve onunla değiştirdik MyString(veya hepsini kaldırdığımıza inanıyorum). Hala neşe yok: Yapı 372 . Bok kodumuzdan bile gelmiyor. CMake'ten geliyor gibi görünüyor. 283. satır if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC").
jww

18

İşte hızlı ve kirli başlamak için birkaç temel örnek.

Bir öğe değişkeni

Set değişkeni:

SET(INSTALL_ETC_DIR "etc")

Değişkeni kullan:

SET(INSTALL_ETC_CROND_DIR "${INSTALL_ETC_DIR}/cron.d")

Çok öğeli değişken (yani liste)

Set değişkeni:

SET(PROGRAM_SRCS
        program.c
        program_utils.c
        a_lib.c
        b_lib.c
        config.c
        )

Değişkeni kullan:

add_executable(program "${PROGRAM_SRCS}")

CDeğişkenleri doküman haline getirme


1

$ENV{FOO}kullanım için, burada FOOortam değişkeninden alınır. aksi halde ${FOO}, FOObaşka bir değişken olduğu gibi kullanın . Ayarlamak SET(FOO "foo")için CMake'de kullanılır.

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.