Tôi đang hỏi điều này như một lời nhắc nhở bản thân vào lần tới khi tôi sử dụng CMake. Nó không bao giờ dính, và kết quả Google không tuyệt vời.
Cú pháp để đặt và sử dụng các biến trong CMake là gì?
Tôi đang hỏi điều này như một lời nhắc nhở bản thân vào lần tới khi tôi sử dụng CMake. Nó không bao giờ dính, và kết quả Google không tuyệt vời.
Cú pháp để đặt và sử dụng các biến trong CMake là gì?
Câu trả lời:
Khi viết tập lệnh CMake, có rất nhiều thứ bạn cần biết về cú pháp và cách sử dụng các biến trong CMake.
Chuỗi sử dụng set()
:
set(MyString "Some Text")
set(MyStringWithVar "Some other Text: ${MyString}")
set(MyStringWithQuot "Some quote: \"${MyStringWithVar}\"")
Hoặc với string()
:
string(APPEND MyStringWithContent " ${MyString}")
Danh sách sử dụng set()
:
set(MyList "a" "b" "c")
set(MyList ${MyList} "d")
Hoặc tốt hơn với list()
:
list(APPEND MyList "a" "b" "c")
list(APPEND MyList "d")
Danh sách tên tệp:
set(MySourcesList "File.name" "File with Space.name")
list(APPEND MySourcesList "File.name" "File with Space.name")
add_excutable(MyExeTarget ${MySourcesList})
set()
Lệnh CMakestring()
Lệnh CMakelist()
Lệnh CMakeĐầu tiên là "Biến thông thường" và những điều bạn cần biết về phạm vi của chúng:
CMakeLists.txt
họ được thiết lập trong và tất cả mọi thứ được gọi là từ đó ( add_subdirectory()
, include()
, macro()
và function()
).add_subdirectory()
và function()
là đặc biệt, bởi vì chúng mở ra phạm vi riêng của chúng.
set(...)
có nghĩa chỉ có thể nhìn thấy ở đó và chúng tạo một bản sao của tất cả các biến thông thường của mức phạm vi mà chúng được gọi từ (gọi là phạm vi cha).set(... PARENT_SCOPE)
function(xyz _resultVar)
là thiết lậpset(${_resultVar} 1 PARENT_SCOPE)
include()
hoặc macro()
tập lệnh sẽ sửa đổi các biến trực tiếp trong phạm vi chúng được gọi từ đâu.Thứ hai là "Cache biến toàn cầu". Những điều bạn cần biết về Cache:
CMakeCache.txt
tệp trong thư mục đầu ra nhị phân của bạn.Các giá trị trong Cache có thể được sửa đổi trong ứng dụng GUI của CMake trước khi chúng được tạo. Do đó, chúng - so với các biến thông thường - có a type
và a docstring
. Tôi thường không sử dụng GUI vì vậy tôi sử dụng set(... CACHE INTERNAL "")
để đặt các giá trị toàn cầu và liên tục của mình.
Xin lưu ý rằng INTERNAL
loại biến bộ đệm có nghĩa làFORCE
Trong tập lệnh CMake, bạn chỉ có thể thay đổi các mục Cache hiện có nếu bạn sử dụng set(... CACHE ... FORCE)
cú pháp. Hành vi này được sử dụng ví dụ như bởi chính CMake, vì thông thường nó không bắt buộc các mục nhập Cache và do đó bạn có thể xác định trước nó với một giá trị khác.
cmake -D var:type=value
, chỉ cmake -D var=value
hoặc với cmake -C CMakeInitialCache.cmake
.unset(... CACHE)
.Cache là toàn cầu và bạn có thể đặt chúng hầu như ở mọi nơi trong tập lệnh CMake của bạn. Nhưng tôi khuyên bạn nên suy nghĩ kỹ về nơi sử dụng các biến Cache (chúng là toàn cầu và chúng vẫn tồn tại). Tôi thường thích set_property(GLOBAL PROPERTY ...)
và set_property(GLOBAL APPEND PROPERTY ...)
cú pháp để xác định các biến toàn cục không liên tục của riêng tôi.
Để tránh những cạm bẫy, bạn nên biết những điều sau về các biến:
find_...
lệnh - nếu thành công - hãy viết kết quả của chúng dưới dạng các biến được lưu trong bộ nhớ cache "để không có cuộc gọi nào sẽ tìm kiếm lại"set(MyVar a b c)
đang "a;b;c"
và set(MyVar "a b c")
là"a b c"
list()
lệnh để xử lý danh sáchfunctions()
thay macros()
vì vì bạn không muốn các biến cục bộ của mình hiển thị trong phạm vi cha.project()
và enable_language()
các lệnh gọi. Vì vậy, điều quan trọng là phải đặt một số biến trước khi các lệnh đó được sử dụng.Đôi khi chỉ có các biến gỡ lỗi giúp. Những điều sau đây có thể giúp bạn:
printf
kiểu gỡ lỗi cũ bằng cách sử dụng message()
lệnh. Ngoài ra còn có một số mô-đun sẵn sàng để sử dụng với chính CMake: CMakePrintHelpers.cmake , CMakePrintSystemIn information.cmakeCMakeCache.txt
tập tin trong thư mục đầu ra nhị phân của bạn. Tệp này thậm chí được tạo nếu thế hệ thực tế của môi trường tạo của bạn không thành công.cmake --trace ...
để xem quá trình phân tích cú pháp hoàn chỉnh của CMake. Đó là loại dự trữ cuối cùng, bởi vì nó tạo ra rất nhiều đầu ra.$ENV{...}
và viết set(ENV{...} ...)
các biến môi trường$<...>
chỉ được đánh giá khi trình tạo của CMake ghi môi trường tạo (so sánh với các biến thông thường được thay thế "tại chỗ" bởi trình phân tích cú pháp)${${...}}
bạn có thể đặt tên biến trong một biến và tham chiếu nội dung của nó.if()
lệnh)
if(MyVariable)
bạn có thể trực tiếp kiểm tra một biến cho đúng / sai (không cần ở đây để kèm theo ${...}
)1
, ON
, YES
, TRUE
, Y
, hoặc một số khác không.0
, OFF
, NO
, FALSE
, N
, IGNORE
, NOTFOUND
, chuỗi rỗng, hoặc kết thúc trong hậu tố -NOTFOUND
.if(MSVC)
, nhưng nó có thể gây nhầm lẫn cho một người không biết phím tắt cú pháp này.set(CMAKE_${lang}_COMPILER ...)
if()
các lệnh. Dưới đây là một ví dụ trong đó CMAKE_CXX_COMPILER_ID
là "MSVC"
và MSVC
là "1"
:
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
là đúng, bởi vì nó đánh giá if("1" STREQUAL "1")
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
là sai, bởi vì nó đánh giá if("MSVC" STREQUAL "1")
if(MSVC)
cmake_policy(SET CMP0054 NEW)
thành "chỉ diễn giải các if()
đối số dưới dạng các biến hoặc từ khóa khi không được trích dẫn."option()
lệnh
ON
hoặc OFF
chúng cho phép xử lý một số đặc biệt, ví dụ như phụ thuộcoption
với set
lệnh. Giá trị được cung cấp option
thực sự chỉ là "giá trị ban đầu" (được chuyển một lần vào bộ đệm trong bước cấu hình đầu tiên) và sau đó được người dùng thay đổi thông qua GUI của CMake .${MyString}
dẫn đến một loạt các lỗi cho "đối số nếu được ..." như CMake lỗi gần nếu: “nếu đối số cho” tiếp theo parantheses, “KHÔNG”, “bằng” và tương tự .
if (MyString ...)
(nếu đó là mã của bạn đưa ra cảnh báo).
${MyString}
và thay thế bằng MyString
(hoặc tôi tin rằng chúng tôi đã xóa tất cả). Vẫn không có niềm vui: Xây dựng 372 . Crap thậm chí không đến từ mã của chúng tôi. Nó dường như đến từ CMake. Dòng 283 là if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
.
Dưới đây là một vài ví dụ cơ bản để bắt đầu nhanh và bẩn.
Đặt biến:
SET(INSTALL_ETC_DIR "etc")
Sử dụng biến:
SET(INSTALL_ETC_CROND_DIR "${INSTALL_ETC_DIR}/cron.d")
Đặt biến:
SET(PROGRAM_SRCS
program.c
program_utils.c
a_lib.c
b_lib.c
config.c
)
Sử dụng biến:
add_executable(program "${PROGRAM_SRCS}")
$ENV{FOO}
để sử dụng, nơi FOO
đang được chọn từ biến môi trường. mặt khác sử dụng như là ${FOO}
, FOO
một số biến khác. Để cài đặt, SET(FOO "foo")
sẽ được sử dụng trong CMake.
if ("${MyString}" ...)
tôi thấy cảnh báo :Policy CMP0054 is not set: Only interpret if() arguments as variables or keywords when unquoted
. Xem, ví dụ, Xây dựng 367 . Có ý kiến gì không?