Apa sintaks CMake untuk mengatur dan menggunakan variabel?

168

Saya meminta ini sebagai pengingat untuk diri saya lain kali saya menggunakan CMake. Tidak pernah menempel, dan hasil Google tidak bagus.

Apa sintaks untuk mengatur dan menggunakan variabel di CMake?

CivFan
sumber

Jawaban:

281

Saat menulis skrip CMake ada banyak yang perlu Anda ketahui tentang sintaks dan cara menggunakan variabel di CMake.

Sintaksnya

String menggunakan set():

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

Atau dengan string():

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

Daftar menggunakan set():

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

Atau lebih baik dengan list():

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

Daftar Nama File:

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

Dokumentasi

Cakupan atau "Nilai apa yang dimiliki variabel saya?"

Pertama ada "Variabel Normal" dan hal-hal yang perlu Anda ketahui tentang ruang lingkup mereka:

  • Variabel yang normal terlihat ke CMakeLists.txtmereka ditetapkan dalam dan segala sesuatu yang disebut dari sana ( add_subdirectory(), include(), macro()dan function()).
  • The add_subdirectory()dan function()perintah yang khusus, karena mereka membuka-up lingkup mereka sendiri.
    • Variabel yang berarti set(...)hanya ada yang terlihat di sana dan mereka membuat salinan dari semua variabel normal dari tingkat lingkup tempat mereka dipanggil (disebut lingkup orangtua).
    • Jadi jika Anda berada di sub-direktori atau fungsi Anda dapat memodifikasi variabel yang sudah ada dalam lingkup induk set(... PARENT_SCOPE)
    • Anda dapat menggunakan ini misalnya dalam fungsi dengan mengirimkan nama variabel sebagai parameter fungsi. Contohnya function(xyz _resultVar)adalah pengaturanset(${_resultVar} 1 PARENT_SCOPE)
  • Di sisi lain, semua yang Anda atur include()atau macro()skrip akan mengubah variabel langsung dalam lingkup tempat mereka dipanggil.

Yang kedua adalah "Global Variables Cache". Hal-hal yang perlu Anda ketahui tentang Cache:

  • Jika tidak ada variabel normal dengan nama yang diberikan didefinisikan dalam lingkup saat ini, CMake akan mencari entri Cache yang cocok.
  • Nilai cache disimpan dalam CMakeCache.txtfile di direktori output biner Anda.
  • Nilai-nilai di Cache dapat dimodifikasi dalam aplikasi GUI CMake sebelum dihasilkan. Oleh karena itu mereka - dibandingkan dengan variabel normal - memiliki a typedan a docstring. Saya biasanya tidak menggunakan GUI jadi saya gunakan set(... CACHE INTERNAL "")untuk mengatur nilai global dan persisten saya.

    Harap perhatikan bahwa INTERNALjenis variabel cache tidak menyiratkanFORCE

  • Dalam skrip CMake Anda hanya dapat mengubah entri Cache yang ada jika Anda menggunakan set(... CACHE ... FORCE)sintaks. Perilaku ini digunakan misalnya oleh CMake itu sendiri, karena biasanya tidak memaksa entri Cache itu sendiri dan oleh karena itu Anda dapat menentukan sebelumnya dengan nilai lain.

  • Anda dapat menggunakan baris perintah untuk mengatur entri di Cache dengan sintaks cmake -D var:type=value, hanya cmake -D var=valueatau dengan cmake -C CMakeInitialCache.cmake.
  • Anda dapat menghapus entri dalam Cache denganunset(... CACHE) .

Cache bersifat global dan Anda dapat mengaturnya di mana saja di skrip CMake Anda. Tapi saya akan merekomendasikan Anda berpikir dua kali tentang di mana menggunakan variabel Cache (mereka bersifat global dan mereka tahan). Saya biasanya lebih suka set_property(GLOBAL PROPERTY ...)danset_property(GLOBAL APPEND PROPERTY ...) sintaks untuk mendefinisikan variabel global non-persisten saya sendiri.

Kesalahan Variabel dan "Bagaimana cara men-debug perubahan variabel?"

Untuk menghindari jebakan Anda harus tahu yang berikut tentang variabel:

  • Variabel lokal menyembunyikan variabel yang di-cache jika keduanya memiliki nama yang sama
  • Itu find_... perintah - jika berhasil - melakukan menulis hasil mereka sebagai variabel cache "sehingga tidak ada panggilan akan mencari lagi"
  • Daftar di CMake hanyalah string dengan pembatas titik koma dan oleh karena itu tanda kutip menjadi penting
    • set(MyVar a b c)adalah "a;b;c"dan set(MyVar "a b c")sekarang"a b c"
    • Rekomendasi adalah bahwa Anda selalu menggunakan tanda kutip dengan satu pengecualian ketika Anda ingin memberikan daftar sebagai daftar
    • Umumnya lebih suka list()perintah untuk menangani daftar
  • Seluruh masalah ruang lingkup yang dijelaskan di atas. Terutama disarankan untuk digunakan functions()daripada macros()karena Anda tidak ingin variabel lokal Anda muncul di lingkup induk.
  • Banyak variabel yang digunakan oleh CMake diatur dengan project()dan enable_language()panggilan. Jadi bisa jadi penting untuk mengatur beberapa variabel sebelum perintah itu digunakan.
  • Variabel lingkungan mungkin berbeda dari tempat CMake menghasilkan lingkungan make dan kapan file make digunakan.
    • Perubahan dalam variabel lingkungan tidak memicu kembali proses pembuatan.
    • Terutama lingkungan IDE yang dihasilkan mungkin berbeda dari baris perintah Anda, jadi disarankan untuk mentransfer variabel lingkungan Anda menjadi sesuatu yang di-cache.

Terkadang hanya variabel debug yang membantu. Berikut ini dapat membantu Anda:

  • Cukup gunakan printfgaya debugging lama dengan menggunakan message()perintah. Ada juga beberapa modul siap pakai yang dikirimkan bersama CMake: CMakePrintHelpers.cmake , CMakePrintSystemInformation.cmake
  • Memeriksa CMakeCache.txt file di direktori output biner Anda. File ini bahkan dihasilkan jika generasi aktual dari lingkungan make Anda gagal.
  • Gunakan variable_watch () untuk melihat di mana variabel Anda dibaca / ditulis / dihapus.
  • Lihatlah ke properti direktori CACHE_VARIABLES dan VARIABLES
  • Panggilan cmake --trace ...untuk melihat proses parsing lengkap CMake. Itu semacam cadangan terakhir, karena menghasilkan banyak output.

Sintaks khusus

  • Variabel Lingkungan
    • Anda dapat membaca $ENV{...}dan menulis set(ENV{...} ...)variabel lingkungan
  • Ekspresi Generator
    • Ekspresi generator $<...>hanya dievaluasi ketika generator CMake menulis lingkungan make (perbandingannya dengan variabel normal yang diganti "di tempat" oleh parser)
    • Sangat berguna misalnya dalam baris perintah compiler / linker dan dalam lingkungan multi-konfigurasi
  • Referensi
    • Dengan ${${...}}Anda dapat memberikan nama variabel dalam variabel dan referensi kontennya.
    • Sering digunakan ketika memberi nama variabel sebagai fungsi / parameter makro.
  • Nilai Konstan (lihat if()perintah)
    • Dengan if(MyVariable)Anda dapat langsung memeriksa variabel benar / salah (tidak perlu di sini untuk melampirkan ${...})
    • Benar jika konstan adalah 1, ON, YES, TRUE, Y, atau nomor non-nol.
    • False jika konstan adalah 0, OFF, NO, FALSE, N, IGNORE, NOTFOUND, string kosong, atau berakhir di akhiran -NOTFOUND.
    • Sintaks ini sering digunakan untuk sesuatu seperti if(MSVC), tetapi dapat membingungkan bagi seseorang yang tidak mengetahui pintasan sintaksis ini.
  • Penggantian rekursif
    • Anda bisa membuat nama variabel menggunakan variabel. Setelah CMake mengganti variabel, itu akan memeriksa lagi jika hasilnya adalah variabel itu sendiri. Ini adalah fitur yang sangat kuat yang digunakan dalam CMake itu sendiri misalnya sebagai semacam templatset(CMAKE_${lang}_COMPILER ...)
    • Namun ketahuilah ini bisa membuat Anda pusing dalam if()perintah. Berikut adalah contoh di mana CMAKE_CXX_COMPILER_IDada "MSVC"dan MSVCtidak "1":
      • if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") itu benar, karena mengevaluasi if("1" STREQUAL "1")
      • if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") salah, karena mengevaluasi ke if("MSVC" STREQUAL "1")
      • Jadi solusi terbaik di sini adalah - lihat di atas - untuk langsung memeriksa if(MSVC)
    • Kabar baiknya adalah bahwa ini diperbaiki dalam CMake 3.1 dengan diperkenalkannya kebijakan CMP0054 . Saya akan merekomendasikan untuk selalu menetapkan cmake_policy(SET CMP0054 NEW)"hanya menafsirkan if()argumen sebagai variabel atau kata kunci ketika tidak dikutip."
  • The option()perintah
    • Terutama hanya cached string yang hanya bisa ONatau OFFdan mereka memungkinkan penanganan khusus seperti ketergantungan misalnya
    • Tapi berhati-hatilah , jangan keliru optiondengan setperintah. Nilai yang diberikan optionadalah benar-benar hanya "nilai awal" (ditransfer satu kali ke cache selama langkah konfigurasi pertama) dan kemudian dimaksudkan untuk diubah oleh pengguna melalui GUI CMake .

Referensi

Florian
sumber
Ketika saya menggunakan if ("${MyString}" ...)saya peringatan melihat: Policy CMP0054 is not set: Only interpret if() arguments as variables or keywords when unquoted. Lihat, misalnya, Bangun 367 . Ada ide?
jww
Dan tanda kutip ${MyString}mengarah ke sekelompok kesalahan untuk "jika diberikan argumen ..." seperti kesalahan CMake dekat jika: "jika diberikan argumen" diikuti oleh paranthes, "TIDAK", "EQUALS" dan sejenisnya .
jww
@jww Peringatan berarti yang MyStringmemang berisi nama variabel yang kemudian akan di-referensikan lagi. Saya percaya bahwa tidak ada yang benar-benar menginginkan OLDperilaku itu. Jadi dari sudut pandang saya ini benar-benar aman dan kompatibel untuk hanya mengatur kebijakan CMP0054untuk NEW(lihat pembahasan di sini ).
Florian
@jww Dan cara teraman untuk menghindari masalah / peringatan itu hanya dengan melakukan if (MyString ...)(jika kode Anda yang memberi peringatan).
Florian
Terima kasih. Kami menghapus semua kemunculan ${MyString}dan menggantinya dengan MyString(atau saya percaya kami menghapus semuanya). Masih tidak ada sukacita: Bangun 372 . Omong kosong itu bahkan tidak berasal dari kode kita. Tampaknya berasal dari CMake. Jalur 283 adalah if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC").
jww
18

Berikut adalah beberapa contoh dasar untuk memulai dengan cepat dan kotor.

Satu variabel item

Setel variabel:

SET(INSTALL_ETC_DIR "etc")

Gunakan variabel:

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

Variabel multi-item (mis. Daftar)

Setel variabel:

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

Gunakan variabel:

add_executable(program "${PROGRAM_SRCS}")

CMake dokumen pada variabel

CivFan
sumber
1

$ENV{FOO}untuk penggunaan, di mana FOOdiambil dari variabel lingkungan. jika tidak digunakan sebagai ${FOO}, di mana FOOada beberapa variabel lain. Untuk pengaturan, SET(FOO "foo")akan digunakan dalam CMake.

parasrish
sumber