Làm thế nào để chia chuỗi thành nhiều dòng trong CMake?


95

Tôi thường có một chính sách trong dự án của mình, không bao giờ tạo các dòng trong tệp văn bản vượt quá độ dài dòng là 80, vì vậy chúng có thể dễ dàng chỉnh sửa trong tất cả các loại trình chỉnh sửa (bạn biết đấy). Nhưng với CMake, tôi gặp vấn đề là tôi không biết làm thế nào để chia một chuỗi đơn giản thành nhiều dòng để tránh một dòng lớn. Hãy xem xét mã cơ bản này:

set(MYPROJ_VERSION_MAJOR "1")
set(MYPROJ_VERSION_MINOR "0")
set(MYPROJ_VERSION_PATCH "0")
set(MYPROJ_VERSION_EXTRA "rc1")
set(MYPROJ_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_EXTRA}")

Nó đã vượt quá giới hạn 80 dòng. Vậy làm cách nào để ngắt một dòng trong CMake thành nhiều dòng mà không bị dài dòng (nhiều list(APPEND ...)hoặc tương tự)?

Câu trả lời:


88

Cập nhật cho CMake 3.0 và mới hơn :

có thể tiếp tục dòng với \. xem cmake-3.0-doc

message("\
This is the first line of a quoted argument. \
In fact it is the only line but since it is long \
the source code uses line continuation.\
")

Tính khả dụng của các phiên bản CMake:

Debian Wheezy (2013): 2.8.9
Debian Wheezy-backports: 2.8.11
Debian Jessy (2015): 3.0.2
Ubuntu 14.04 (LTS): 2.8.12
Ubuntu 15.04: 3.0.2
Mac OSX: cmake-3 khả dụng thông qua Homebrew , MacportsFink
Windows: cmake-3 có sẵn thông qua Chocolatey


20
Vấn đề với cách tiếp cận CMake 3.0 là nó không bỏ qua thụt lề. Điều đó có nghĩa là không thể thụt lề các chuỗi nhiều dòng với phần còn lại của mã.
void.pointer

@ void.pointer Tôi gặp phải vấn đề tương tự, bạn đã tìm ra cách thụt lề với nhiều dòng chưa?
user3667089

Ngoài ra, nếu bạn muốn sử dụng thụt lề và bị ràng buộc giới hạn 80 ký tự thì một cách khác là làm như sau: <code> message ("Đây là giá trị của biến:" <br> "$ {varValue}") </code>
munsingh

54

CMake 3.0 và mới hơn

Sử dụng string(CONCAT)lệnh:

set(MYPROJ_VERSION_MAJOR "1")
set(MYPROJ_VERSION_MINOR "0")
set(MYPROJ_VERSION_PATCH "0")
set(MYPROJ_VERSION_EXTRA "rc1")
string(CONCAT MYPROJ_VERSION "${MYPROJ_VERSION_MAJOR}"
                             ".${MYPROJ_VERSION_MINOR}"
                             ".${MYPROJ_VERSION_PATCH}"
                             "-${MYPROJ_VERSION_EXTRA}")

Mặc dù CMake 3.0 và dòng hỗ trợ mới hơn tiếp tục các đối số được trích dẫn , bạn không thể thụt lề dòng thứ hai hoặc dòng tiếp theo mà không nhận được khoảng trắng thụt lề trong chuỗi của bạn.

CMake 2.8 trở lên

Bạn có thể sử dụng một danh sách. Mỗi phần tử của danh sách có thể được đặt trên một dòng mới:

set(MYPROJ_VERSION_MAJOR "1")
set(MYPROJ_VERSION_MINOR "0")
set(MYPROJ_VERSION_PATCH "0")
set(MYPROJ_VERSION_EXTRA "rc1")
set(MYPROJ_VERSION_LIST "${MYPROJ_VERSION_MAJOR}"
                        ".${MYPROJ_VERSION_MINOR}"
                        ".${MYPROJ_VERSION_PATCH}"
                        "-${MYPROJ_VERSION_EXTRA}")

Một danh sách được sử dụng không có dấu ngoặc kép được nối với nhau mà không có khoảng trắng:

message(STATUS "Version: " ${MYPROJ_VERSION_LIST})
-- Version: 1.0.0-rc1

Nếu bạn thực sự cần một chuỗi, trước tiên bạn có thể chuyển đổi danh sách thành chuỗi:

string(REPLACE ";" "" MYPROJ_VERSION "${MYPROJ_VERSION_LIST}")
message(STATUS "Version: ${MYPROJ_VERSION}")
-- Version: 1.0.0-rc1

Bất kỳ dấu chấm phẩy nào trong chuỗi ban đầu của bạn sẽ được coi là dấu phân tách phần tử danh sách và bị xóa. Họ phải được thoát ra:

set(MY_LIST "Hello World "
            "with a \;semicolon")

1
Đối với các dòng rất dài, một dòng mới sau tên biến thậm chí còn cải thiện mô hình này (không cần thiết trong ví dụ này).
sage,

tò mò , có đúng không khi đoán rằng dấu ngoặc kép trong chuỗi cũng cần được thoát bằng dấu gạch chéo ngược và vì vậy có bất kỳ dấu gạch chéo ngược nào cần xuất hiện như một ký tự trong chuỗi không?
Jonathan Leffler

@JonathanLeffler Có, họ cần thoát. Các quy tắc ngôn ngữ có ở đây: cmake.org/cmake/help/latest/manual/… nhưng nó thực sự gây nhầm lẫn. Xem thêm: stackoverflow.com/a/40728463
Douglas Royds

9

Nó vẫn còn hơi dài dòng, nhưng nếu giới hạn ký tự 80 thực sự gây lỗi cho bạn thì bạn có thể liên tục thêm vào cùng một biến:

set(MYPROJ_VERSION_MAJOR "1")
set(MYPROJ_VERSION_MINOR "0")
set(MYPROJ_VERSION_PATCH "0")
set(MYPROJ_VERSION_EXTRA "rc1")
set(MYPROJ_VERSION "${MYPROJ_VERSION_MAJOR}.")
set(MYPROJ_VERSION "${MYPROJ_VERSION}${MYPROJ_VERSION_MINOR}.")
set(MYPROJ_VERSION "${MYPROJ_VERSION}${MYPROJ_VERSION_PATCH}-")
set(MYPROJ_VERSION "${MYPROJ_VERSION}${MYPROJ_VERSION_EXTRA}")
message(STATUS "version: ${MYPROJ_VERSION}")

Cung cấp đầu ra:

$ cmake  ~/project/tmp
-- version: 1.0.0-rc1
-- Configuring done
-- Generating done
-- Build files have been written to: /home/rsanderson/build/temp

7

Không có cách nào để chia một chuỗi theo nghĩa đen thành nhiều dòng trong tệp CMakeLists.txt hoặc trong tập lệnh CMake. Nếu bạn bao gồm một dòng mới trong một chuỗi, sẽ có một dòng mới theo nghĩa đen trong chính chuỗi đó.

# Don't do this, it won't work, MYPROJ_VERSION will contain newline characters:
set(MYPROJ_VERSION "${VERSION_MAJOR}.
  ${VERSION_MINOR}.${VERSION_PATCH}-
  ${VERSION_EXTRA}")

Tuy nhiên, CMake sử dụng khoảng trắng để phân tách các đối số, vì vậy bạn có thể thay đổi khoảng trắng là dấu phân cách đối số thành một dòng mới ở bất kỳ đâu bạn thích mà không cần thay đổi hành vi.

Bạn có thể diễn đạt lại dòng dài hơn này:

set(MYPROJ_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_EXTRA}")

như hai dòng ngắn hơn sau:

set(MYPROJ_VERSION
  "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_EXTRA}")

Chúng hoàn toàn tương đương.


5

Ví dụ trong câu hỏi ban đầu chỉ về một chuỗi tương đối ngắn. Đối với các chuỗi dài hơn (bao gồm các ví dụ được đưa ra trong các câu trả lời khác), một đối số trong ngoặc có thể tốt hơn. Từ tài liệu:

Dấu ngoặc mở đầu được viết [theo sau bằng 0 hoặc nhiều hơn =sau đó [. Dấu ngoặc đóng tương ứng được viết ]theo cùng một số =theo sau ]. Dấu ngoặc không lồng vào nhau. Một độ dài duy nhất có thể luôn được chọn cho các dấu ngoặc mở và đóng để chứa các dấu ngoặc đóng có độ dài khác.

[...]

Ví dụ:

message([=[
This is the first line in a bracket argument with bracket length 1.
No \-escape sequences or ${variable} references are evaluated.
This is always one argument even though it contains a ; character.
The text does not end on a closing bracket of length 0 like ]].
It does end in a closing bracket of length 1.
]=])```

Nếu tôi hiểu điều này một cách chính xác, Dấu ngắt dòng trong nguồn cũng sẽ giới thiệu dấu ngắt dòng trong chuỗi. Ví dụ: sẽ có \ n sau "độ dài 1". Có cách nào để tránh điều đó không?
Lukas Schmelzeisen

Đúng vậy, sẽ có \ns. Nếu bạn không muốn điều đó, tôi không nghĩ rằng các đối số trong ngoặc là giải pháp của bạn.
ingomueller.net

BTW, nó hợp lệ cho phiên bản 3.x, không phải 2.x
Maxim Suslov

4

Đối với những người được đưa đến đây từ Làm cách nào để chia biểu thức trình tạo CMake thành nhiều dòng? Tôi muốn thêm một số lưu ý.

Phương pháp tiếp tục dòng sẽ không hoạt động, CMake không thể phân tích cú pháp danh sách trình tạo được tạo bằng khoảng trắng (thụt đầu dòng) và tiếp tục dòng.

Trong khi giải pháp chuỗi (CONCAT) sẽ cung cấp một biểu thức trình tạo có thể được đánh giá, biểu thức được đánh giá sẽ được bao quanh bởi dấu ngoặc kép nếu kết quả chứa khoảng trắng.

Đối với mỗi tùy chọn riêng lẻ được thêm vào một danh sách trình tạo riêng biệt phải được xây dựng, vì vậy các tùy chọn xếp chồng như tôi đã thực hiện trong phần sau sẽ gây ra lỗi xây dựng:

string(CONCAT WARNING_OPTIONS "$<"
    "$<OR:"
        "$<CXX_COMPILER_ID:MSVC>,"
        "$<STREQUAL:${CMAKE_CXX_SIMULATE_ID},MSVC>"
    ">:"
    "/D_CRT_SECURE_NO_WARNINGS "
">$<"
    "$<AND:"
        "$<CXX_COMPILER_ID:Clang,GNU>,"
        "$<NOT:$<STREQUAL:${CMAKE_CXX_SIMULATE_ID},MSVC>>"
    ">:"
    "-Wall -Werror "
">$<"
    "$<CXX_COMPILER_ID:GNU>:"
    "-Wno-multichar -Wno-sign-compare "
">")
add_compile_options(${WARNING_OPTIONS})

Điều này là do các tùy chọn kết quả được chuyển đến trình biên dịch trong dấu ngoặc kép

/usr/lib64/ccache/c++  -DGTEST_CREATE_SHARED_LIBRARY=1 -Dgtest_EXPORTS -I../ThirdParty/googletest/googletest/include -I../ThirdParty/googletest/googletest -std=c++11 -fno-rtti -fno-exceptions -fPIC    -std=c++11 -fno-rtti -fno-exceptions -Wall -Wshadow -DGTEST_HAS_PTHREAD=1 -fexceptions -Wextra -Wno-unused-parameter -Wno-missing-field-initializers "-Wall -Werror -Wno-multichar -Wno-sign-compare " -fdiagnostics-color -MD -MT ThirdParty/googletest/googletest/CMakeFiles/gtest.dir/src/gtest-all.cc.o -MF ThirdParty/googletest/googletest/CMakeFiles/gtest.dir/src/gtest-all.cc.o.d -o ThirdParty/googletest/googletest/CMakeFiles/gtest.dir/src/gtest-all.cc.o -c ../ThirdParty/googletest/googletest/src/gtest-all.cc
c++: error: unrecognized command line option ‘-Wall -Werror -Wno-multichar -Wno-sign-compare ’

Để đánh giá các biểu thức trình tạo độ dài được biểu diễn bằng giải pháp chuỗi (CONCAT), mỗi biểu thức trình tạo phải đánh giá một tùy chọn duy nhất không có khoảng trắng:

string(CONCAT WALL "$<"
    "$<AND:"
        "$<CXX_COMPILER_ID:Clang,GNU>,"
        "$<NOT:$<STREQUAL:${CMAKE_CXX_SIMULATE_ID},MSVC>>"
    ">:"
    "-Wall"
">")
string(CONCAT WERROR "$<"
    "$<AND:"
        "$<CXX_COMPILER_ID:Clang,GNU>,"
        "$<NOT:$<STREQUAL:${CMAKE_CXX_SIMULATE_ID},MSVC>>"
    ">:"
    "-Werror"
">")
message(STATUS "Warning Options: " ${WALL} ${WERROR})
add_compile_options(${WALL} ${WERROR})

Điều này có thể không liên quan đến câu hỏi tôi đang đăng câu trả lời, rất tiếc là câu hỏi tôi đang trả lời bị đánh dấu sai là bản sao của câu hỏi này.

Danh sách trình tạo không được xử lý và phân tích cú pháp giống như các chuỗi, và do đó, có những biện pháp bổ sung mà người ta phải thực hiện để tách danh sách trình tạo thành nhiều dòng.


Cũng có thể đáng giá nếu đăng một phiên bản của câu trả lời này trên "bản sao" được liên kết. Đây là câu trả lời tôi đã tìm kiếm khi tôi bắt gặp nó.
Keith Prussing

3

Để duy trì thụt lề tốt trong mã của bạn, bạn chỉ cần làm đủ đơn giản

message("These strings " "will all be "
        "concatenated. Don't forget "
        "your trailing spaces!")

Hoặc tạo một chuỗi trực tiếp với

string(CONCAT MYSTR "This and " "that "
                    "and me too!")

như trong câu trả lời của Douglas, người có nhiều chi tiết hơn. Tuy nhiên, tôi nghĩ điều này có thể chỉ tóm tắt điểm cốt yếu.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.