ฉันขอสิ่งนี้เป็นเครื่องเตือนใจตัวเองในครั้งต่อไปที่ฉันใช้ CMake มันไม่ติดและผลลัพธ์ของ Google ก็ไม่ได้ยอดเยี่ยม
ไวยากรณ์ในการตั้งค่าและใช้ตัวแปรใน CMake คืออะไร
ฉันขอสิ่งนี้เป็นเครื่องเตือนใจตัวเองในครั้งต่อไปที่ฉันใช้ CMake มันไม่ติดและผลลัพธ์ของ Google ก็ไม่ได้ยอดเยี่ยม
ไวยากรณ์ในการตั้งค่าและใช้ตัวแปรใน CMake คืออะไร
คำตอบ:
เมื่อเขียนสคริปต์ของ CMake มีจำนวนมากที่คุณต้องรู้เกี่ยวกับไวยากรณ์และวิธีการใช้ตัวแปรใน CMake
เงื่อนไขการใช้set():
set(MyString "Some Text")set(MyStringWithVar "Some other Text: ${MyString}")set(MyStringWithQuot "Some quote: \"${MyStringWithVar}\"")หรือด้วยstring():
string(APPEND MyStringWithContent " ${MyString}")รายการที่ใช้set():
set(MyList "a" "b" "c")set(MyList ${MyList} "d")หรือดีกว่าด้วยlist():
list(APPEND MyList "a" "b" "c")list(APPEND MyList "d")รายการชื่อไฟล์:
set(MySourcesList "File.name" "File with Space.name")list(APPEND MySourcesList "File.name" "File with Space.name")add_excutable(MyExeTarget ${MySourcesList})set()คำสั่งCMakestring()คำสั่งCMakelist()คำสั่งCMakeอันดับแรกมี "ตัวแปรปกติ" และสิ่งที่คุณต้องรู้เกี่ยวกับขอบเขต:
CMakeLists.txtพวกเขาจะตั้งอยู่ในและทุกอย่างที่เรียกว่าจากที่นั่น ( add_subdirectory(), include(), macro()และfunction())add_subdirectory()และfunction()คำสั่งเป็นพิเศษเพราะพวกเขาเปิดขึ้นขอบเขตของตัวเอง
set(...)มีให้เห็นได้เฉพาะที่นั่นและทำสำเนาของตัวแปรปกติทั้งหมดของระดับขอบเขตที่ถูกเรียกจาก (เรียกว่าขอบเขตหลัก)set(... PARENT_SCOPE)function(xyz _resultVar)เป็นการตั้งค่าset(${_resultVar} 1 PARENT_SCOPE)include()หรือmacro()สคริปต์จะปรับเปลี่ยนตัวแปรโดยตรงในขอบเขตที่พวกเขาจะถูกเรียกจากประการที่สองคือ "แคชตัวแปรส่วนกลาง" สิ่งที่คุณต้องรู้เกี่ยวกับแคช:
CMakeCache.txtไฟล์ในไดเรกทอรีเอาต์พุตไบนารีของคุณค่าใน Cache สามารถแก้ไขได้ในแอปพลิเคชันGUI ของ CMakeก่อนที่จะถูกสร้างขึ้น ดังนั้นพวกเขาจึง - เมื่อเทียบกับตัวแปรปกติ - มีและtype docstringปกติแล้วฉันจะไม่ใช้ GUI ดังนั้นฉันจึงใช้set(... CACHE INTERNAL "")เพื่อตั้งค่าโกลบอลและค่าที่ทนได้ของฉัน
โปรดทราบว่าINTERNALประเภทตัวแปรแคชนั้นแปลว่าFORCE
ในสคริปต์ CMake คุณสามารถเปลี่ยนรายการแคชที่มีอยู่หากคุณใช้set(... CACHE ... FORCE)ไวยากรณ์ พฤติกรรมนี้มีการใช้งานเช่นโดย CMake เองเพราะปกติแล้วจะไม่บังคับให้รายการแคชเองดังนั้นคุณจึงสามารถกำหนดค่าล่วงหน้าด้วยค่าอื่นได้
cmake -D var:type=valueเพียงหรือcmake -D var=valuecmake -C CMakeInitialCache.cmakeunset(... CACHE)รายการในแคชด้วยCache นั้นเป็นสากลและคุณสามารถตั้งค่าได้แทบทุกที่ในสคริปต์ CMake ของคุณ แต่ฉันขอแนะนำให้คุณคิดสองครั้งเกี่ยวกับตำแหน่งที่จะใช้ตัวแปร Cache (เป็นแบบโกลบอลและแบบถาวร) ปกติแล้วฉันชอบset_property(GLOBAL PROPERTY ...)และset_property(GLOBAL APPEND PROPERTY ...)ไวยากรณ์เพื่อกำหนดตัวแปรทั่วโลกของฉันเองไม่ทน
เพื่อหลีกเลี่ยงข้อผิดพลาดคุณควรทราบข้อมูลเกี่ยวกับตัวแปรดังต่อไปนี้:
find_...คำสั่ง - ถ้าประสบความสำเร็จ - อย่าเขียนผลของพวกเขาเป็นตัวแปรที่เก็บไว้ชั่วคราว "เพื่อให้ไม่มีการโทรจะค้นหาอีกครั้ง"set(MyVar a b c)เป็น"a;b;c"และset(MyVar "a b c")เป็น"a b c"list()คำสั่งสำหรับการจัดการรายการfunctions()แทนmacros()เพราะคุณไม่ต้องการให้ตัวแปรในเครื่องของคุณปรากฏในขอบเขตพาเรนต์project()และการenable_language()เรียก ดังนั้นการตั้งค่าตัวแปรให้สำคัญก่อนที่จะใช้คำสั่งเหล่านั้นบางครั้งการดีบักตัวแปรช่วยเท่านั้น ต่อไปนี้อาจช่วยคุณได้:
printfรูปแบบการดีบักแบบเก่าโดยใช้message()คำสั่ง นอกจากนี้ยังมีบางส่วนที่พร้อมใช้งานโมดูลที่มาพร้อมกับ CMake เอง: CMakePrintHelpers.cmake , CMakePrintSystemInformation.cmakeCMakeCache.txtไฟล์ในไดเรกทอรีเอาต์พุตไบนารีของคุณ ไฟล์นี้จะถูกสร้างขึ้นหากการสร้างสภาพแวดล้อมการสร้างของคุณล้มเหลวcmake --trace ...เพื่อดูกระบวนการแยกวิเคราะห์ที่สมบูรณ์ของ CMake นั่นคือการสำรองครั้งสุดท้ายเพราะมันสร้างผลผลิตจำนวนมาก$ENV{...}และเขียนset(ENV{...} ...)ตัวแปรสภาพแวดล้อมได้$<...>จะได้รับการประเมินก็ต่อเมื่อตัวสร้างของ CMake เขียนสภาพแวดล้อมที่สร้าง (เปรียบเทียบกับตัวแปรปกติที่ถูกแทนที่ "in-place" โดยตัวแยกวิเคราะห์)${${...}}คุณสามารถให้ชื่อตัวแปรในตัวแปรและอ้างอิงเนื้อหาif()คำสั่ง)
if(MyVariable)คุณโดยตรงสามารถตรวจสอบตัวแปรสำหรับ / เท็จจริง (ไม่จำเป็นต้องที่นี่สำหรับการปิดล้อม${...})1, ON, YES, TRUE, Yหรือจำนวนไม่เป็นศูนย์0, OFF, NO, FALSE, N, IGNORE, NOTFOUND, -NOTFOUNDสตริงที่ว่างเปล่าหรือปลายในคำต่อท้ายif(MSVC)แต่อาจทำให้สับสนสำหรับคนที่ไม่รู้จักทางลัดไวยากรณ์นี้set(CMAKE_${lang}_COMPILER ...)if()คำสั่ง นี่คือตัวอย่างในกรณีที่CMAKE_CXX_COMPILER_IDเป็น"MSVC"และMSVCเป็น"1":
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") เป็นจริงเพราะมันประเมิน if("1" STREQUAL "1")if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") เป็นเท็จเพราะมันประเมิน if("MSVC" STREQUAL "1")if(MSVC)cmake_policy(SET CMP0054 NEW)เป็น "ตีความif()อาร์กิวเมนต์เท่านั้นเป็นตัวแปรหรือคำหลักเมื่อไม่ได้อ้างอิง"option()คำสั่ง
ONหรือหรือOFFพวกเขาให้การจัดการพิเศษบางอย่างเช่นการอ้างอิงoptionกับsetคำสั่ง คุ้มค่าให้กับoptionมันเพียง "ค่าเริ่มต้น" (โอนครั้งเดียวไปยังแคชในระหว่างขั้นตอนการตั้งค่าครั้งแรก) และมีความหมายหลังจากนั้นก็จะมีการเปลี่ยนแปลงโดยผู้ใช้ผ่านCMake ของ GUI${MyString}นำไปสู่พวงของข้อผิดพลาดสำหรับ"ถ้าข้อโต้แย้งให้ ..."เหมือนCMake ข้อผิดพลาดถ้าอยู่ใกล้กับ:“ถ้าข้อโต้แย้งให้” ตามด้วยวงเล็บ“ไม่”,“เท่ากับ” และที่คล้ายกัน
if (MyString ...)(ถ้ารหัสของคุณเป็นคำเตือน)
ต่อไปนี้เป็นตัวอย่างพื้นฐานในการเริ่มต้นอย่างรวดเร็วและสกปรก
ตั้งค่าตัวแปร:
SET(INSTALL_ETC_DIR "etc")
ใช้ตัวแปร:
SET(INSTALL_ETC_CROND_DIR "${INSTALL_ETC_DIR}/cron.d")
ตั้งค่าตัวแปร:
SET(PROGRAM_SRCS
program.c
program_utils.c
a_lib.c
b_lib.c
config.c
)
ใช้ตัวแปร:
add_executable(program "${PROGRAM_SRCS}")
$ENV{FOO}สำหรับการใช้งานที่FOOมีการรับจากตัวแปรสภาพแวดล้อม มิฉะนั้นจะใช้เป็น${FOO}, ซึ่งFOOเป็นตัวแปรอื่น ๆ สำหรับการตั้งค่าSET(FOO "foo")จะใช้ใน CMake
if ("${MyString}" ...)ฉันเห็นคำเตือน:Policy CMP0054 is not set: Only interpret if() arguments as variables or keywords when unquoted. ดูตัวอย่างเช่นสร้าง 367 ความคิดใด ๆ