将列表传递给CMake宏

Pau*_*aul 43 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})
Run Code Online (Sandbox Code Playgroud)

输出:

message( "outside lib1 lib2 lib3" )
message( "inside lib1" )
Run Code Online (Sandbox Code Playgroud)

Jac*_*lly 64

在将变量传递给宏时引用变量:

FindLibs("${LIBRARY_NAMES_LIST}")
Run Code Online (Sandbox Code Playgroud)

  • 因为宏接受单个参数,如果不引用它并且变量扩展为多个单词,它们将作为多个参数传递给宏。 (4认同)

tam*_*nez 8

你的宏应该是这样的:

macro(FindLibs list_var_name)            
    message( "inside ${${list_var_name}}" )
endmacro()
Run Code Online (Sandbox Code Playgroud)

并像这样调用宏:

FindLibs(LIBRARY_NAMES_LIST)
Run Code Online (Sandbox Code Playgroud)

所以在宏内: ${list_var_name} = LIBRARY_NAMES_LIST, ${${list_var_name}} = ${LIBRARY_NAMES_LIST} = your list.

另一种解决方案可能(有点更模糊):

macro(FindLibs)            
    message( "inside ${ARGN}" )
endmacro()

FindLibs(${LIBRARY_NAMES_LIST})
Run Code Online (Sandbox Code Playgroud)

在第一个解决方案中,您只将list-variable的名称传递给宏(一个参数).在第二个解决方案中,您在调用宏之前展开列表并传递N个参数(N =列表的长度).


mch*_*son 8

其他人提供的答案是正确的.确实最好的解决方案是用双引号提供这样的列表:

FindLibs( "${LIBRARY_NAMES_LIST}" )
Run Code Online (Sandbox Code Playgroud)

但是,如果你真的不想强迫用户使用双引号并且还希望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()
Run Code Online (Sandbox Code Playgroud)

它会像这样使用(你的期望):

FindLibs( ${LIBRARY_NAMES_LIST} )
Run Code Online (Sandbox Code Playgroud)

这很好,因为它会强制用户提供至少一个库.称之为

FindLibs()
Run Code Online (Sandbox Code Playgroud)

不行.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()
Run Code Online (Sandbox Code Playgroud)

不幸的是,你必须自己执行你的论证,但至少它让你可以选择哪些参数是必需的,哪些不是(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
)
Run Code Online (Sandbox Code Playgroud)

如果我这样做:

FindLibs()

# or that:
FindLibs( DEPENDS ${LIBRARY_DEPENDENCY_LIST} )
Run Code Online (Sandbox Code Playgroud)

然后我会得到我的自定义错误消息:

错误:FindLibs:需要'NAMES'参数.

如果您想了解更多信息,请点击此处链接到CMakeParseArguments文档.

我希望它有所帮助:-)