Передача списка в макрос 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} должен быть расширен до всего списка аргументов. Это должно сделать вещи проще в месте вызова.

Другие вопросы по тегам