Передача списка в макрос CMake
Я пытаюсь написать макрос, который проходит через данный список библиотек. Однако при вызове сообщения в макросе печатается только первый элемент списка. Что я здесь не так делаю?
Код:
macro( FindLibs LIBRARY_NAMES_LIST )
message( "inside ${LIBRARY_NAMES_LIST}" )
endmacro()
set( LIBRARY_NAMES_LIST lib1 lib2 lib3)
message( "outside ${LIBRARY_NAMES_LIST}" )
FindLibs(${LIBRARY_NAMES_LIST})
Выход:
message( "outside lib1 lib2 lib3" )
message( "inside lib1" )
4 ответа
Заключите переменную в кавычки, когда вы передаете ее макросу
FindLibs("${LIBRARY_NAMES_LIST}")
Предоставленные ответы других являются правильными. Лучшее решение действительно состоит в том, чтобы предоставить список в двойных кавычках как это:
FindLibs( "${LIBRARY_NAMES_LIST}" )
Но если вы действительно не хотите заставлять пользователя использовать двойные кавычки, а также хотите увидеть LIBRARY_NAMES_LIST
аргумент в вашем объявлении макроса, вот как я бы это сделал:
macro( FindLibs LIBRARY_NAMES_LIST )
set( _LIBRARY_NAMES_LIST ${LIBRARY_NAMES_LIST} ${ARGN} ) # Merge them together
message( "inside ${_LIBRARY_NAMES_LIST}" )
endmacro()
И это будет использоваться так (ваше ожидание):
FindLibs( ${LIBRARY_NAMES_LIST} )
Это хорошо, потому что это заставит пользователя предоставить хотя бы одну библиотеку. Называя это как
FindLibs()
не сработает CMake сообщит о следующей ошибке:
Макрос FindLibs вызван с неверными аргументами для макроса с именем: FindLibs
Если вы используете CMake 2.8.3 или новее, другой вариант - использовать CmakeParseArguments
, но это потребует от вас поставить ключевой аргумент перед вашим списком. Но этот метод, вероятно, является самым простым способом управления более чем одним списком и обеспечивает высокую гибкость. По этой причине это очень удобно знать. Это также мой любимый способ сделать это. Вот как это сделать:
include( CMakeParseArguments )
macro( FindLibs )
set( _OPTIONS_ARGS )
set( _ONE_VALUE_ARGS )
set( _MULTI_VALUE_ARGS NAMES DEPENDS )
cmake_parse_arguments( _FINDLIBS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN} )
# Mandatory
if( _FINDLIBS_NAMES )
message( STATUS "inside NAMES=${_FINDLIBS_NAMES}" )
else()
message( FATAL_ERROR "FindLibs: 'NAMES' argument required." )
endif()
# Optional
if( _FINDLIBS_DEPENDS )
message( STATUS "inside DEPENDS=${_FINDLIBS_DEPENDS}" )
endif()
endmacro()
К сожалению, вы должны сами применять свои аргументы, но, по крайней мере, это дает вам возможность выбрать, какие аргументы являются обязательными, а какие нет (DEPENDS
не является обязательным в моем примере выше).
И это будет использоваться так:
FindLibs( NAMES ${LIBRARY_NAMES_LIST} )
FindLibs( NAMES ${LIBRARY_NAMES_LIST} DEPENDS ${LIBRARY_DEPENDENCY_LIST} )
# You can change the order
FindLibs( DEPENDS ${LIBRARY_DEPENDENCY_LIST} NAMES ${LIBRARY_NAMES_LIST} )
# You can even build your lists on the fly
FindLibs(
NAMES
zlib
png
jpeg
DEPENDS
otherProject1
otherProject2
)
И если я сделаю это:
FindLibs()
# or that:
FindLibs( DEPENDS ${LIBRARY_DEPENDENCY_LIST} )
Тогда я получу свое сообщение об ошибке:
ошибка: FindLibs: необходим аргумент 'NAMES'.
А здесь ссылка на документацию CMakeParseArguments, если вы хотите узнать больше об этом.
Я надеюсь, что это помогает:-)
Ваш макрос должен выглядеть так:
macro(FindLibs list_var_name)
message( "inside ${${list_var_name}}" )
endmacro()
и вызвать макрос так:
FindLibs(LIBRARY_NAMES_LIST)
Итак, внутри макроса: ${list_var_name} = LIBRARY_NAMES_LIST, ${${list_var_name}} = ${LIBRARY_NAMES_LIST} = your list.
Другое решение может быть (несколько более неясным):
macro(FindLibs)
message( "inside ${ARGN}" )
endmacro()
FindLibs(${LIBRARY_NAMES_LIST})
В первом решении вы передаете макросу только имя переменной списка (один аргумент). Во втором решении вы расширяете список перед вызовом макроса и передаете N параметров (N = длина списка).
Согласно (почти) текущей документации CMake, символ ${ARGV} должен быть расширен до всего списка аргументов. Это должно сделать вещи проще в месте вызова.