Лучший/Самый короткий способ присоединиться к списку в CMake
Каков наилучший способ присоединиться к списку в CMake в строку?
Присоединившись, я имею в виду преобразовать SET (somelist "a" "b" "c \; c" ) в "a: b: c; c", где строка слияния ( ":" ) может быть выбрана. Следующий код работает, но он ДЕЙСТВИТЕЛЬНО длинный, есть ли лучший способ?
FUNCTION(JOIN LISTNAME GLUE OUTPUT)
SET(_TMP_STR "")
FOREACH(VAL ${${LISTNAME}})
SET(_TMP_STR "${_TMP_STR}${GLUE}${VAL}")
ENDFOREACH(VAL ${${LISTNAME}})
STRING(LENGTH "${GLUE}" GLUE_LEN)
STRING(LENGTH "${_TMP_STR}" OUT_LEN)
MATH(EXPR OUT_LEN ${OUT_LEN}-${GLUE_LEN})
STRING(SUBSTRING "${_TMP_STR}" ${GLUE_LEN} ${OUT_LEN} _TMP_STR)
SET(${OUTPUT} "${_TMP_STR}" PARENT_SCOPE)
ENDFUNCTION()
#USAGE:
SET(somelist "a" "b" "c\;c")
JOIN(somelist ":" output)
MESSAGE("${output}") # will output "a:b:c;c"
К сожалению, использование STRING (REPLACE...) не работает:
function(JOINSTRREPLACE VALUES GLUE OUTPUT)
string (REPLACE ";" "${GLUE}" _TMP_STR "${VALUES}")
set (${OUTPUT} "${_TMP_STR}" PARENT_SCOPE)
endfunction()
JOINSTRREPLACE("${somelist}" ":" output)
MESSAGE(${output}) # will output "a:b:c\:c"
Ответы
Ответ 1
Обычно эта задача решается с помощью простой команды string REPLACE
. Вы можете найти ряд таких замещений в сценариях, идущих с cmake. Но если вам действительно нужно заботиться о точках с запятой внутри вас, вы можете использовать следующий код:
function(JOIN VALUES GLUE OUTPUT)
string (REGEX REPLACE "([^\\]|^);" "\\1${GLUE}" _TMP_STR "${VALUES}")
string (REGEX REPLACE "[\\](.)" "\\1" _TMP_STR "${_TMP_STR}") #fixes escaping
set (${OUTPUT} "${_TMP_STR}" PARENT_SCOPE)
endfunction()
SET( letters "" "\;a" b c "d\;d" )
JOIN("${letters}" ":" output)
MESSAGE("${output}") # :;a:b:c:d;d
Ответ 2
CMake 3.12 готов наконец добавить этот апстрим:
https://github.com/Kitware/CMake/commit/a58158727be4585f9fd71449e9cc9e801c59a009
https://github.com/Kitware/CMake/commit/689eeb67cb87a9ed1d91a4971806488d00e68f42
Ответ 3
Вы можете использовать функцию string REPLACE :
function(JOIN VALUES GLUE OUTPUT)
string (REPLACE ";" "${GLUE}" _TMP_STR "${VALUES}")
set (${OUTPUT} "${_TMP_STR}" PARENT_SCOPE)
endfunction()
#USAGE:
SET(somelist a b c)
JOIN("${somelist}" ":" output)
MESSAGE("${output}") # will output "a:b:c"
Ответ 4
Ответы, приведенные выше, в порядке, когда вы не используете точки с запятой или когда можете (и хотите) их избежать.
Я предпочитаю не избегать точек с запятой, поэтому я написал следующую функцию:
function(JOIN OUTPUT GLUE)
set(_TMP_RESULT "")
set(_GLUE "") # effective glue is empty at the beginning
foreach(arg ${ARGN})
set(_TMP_RESULT "${_TMP_RESULT}${_GLUE}${arg}")
set(_GLUE "${GLUE}")
endforeach()
set(${OUTPUT} "${_TMP_RESULT}" PARENT_SCOPE)
endfunction()
Преимущество состоит в том, что список может быть пустым, и он не должен быть в переменной (но может быть записан в месте вызова).
Использование:
set(SOME_LIST a b c d)
join(RESULT "/" ${SOME_LIST})
message(STATUS "RESULT='${RESULT}'") # outputs RESULT='a/b/c/d'
# or
join(RESULT " " e f g h)
message(STATUS "RESULT='${RESULT}'") # outputs RESULT='e f g h'