【问题标题】:Passing a list to a CMake macro将列表传递给 CMake 宏
【发布时间】:2011-07-12 01:10:28
【问题描述】:

我正在尝试编写一个通过给定库列表的宏。但是,宏中的消息调用仅打印列表的第一项。我在这里做错了什么?

代码:

    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" )

【问题讨论】:

    标签: cmake


    【解决方案1】:

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

    FindLibs("${LIBRARY_NAMES_LIST}")
    

    【讨论】:

    • 它有效。为什么我们应该引用 ${LIBRARY_NAMES_LIST}?
    • 因为宏接受一个参数,如果你不引用它并且变量扩展为多个单词,它们将作为多个参数传递给宏。
    【解决方案2】:

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

    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 文档的链接。

    希望对你有帮助:-)

    【讨论】:

    • cmake_parse_arguments( _FINDLIBS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN} ) 行表明 Kitware 在将列表传递给函数或宏方面也遇到了同样的困难。 :-)
    【解决方案3】:

    您的宏应如下所示:

    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 = 列表的长度)。

    【讨论】:

    • 请注意:使用${ARGN} 并不能防止在没有任何参数的情况下使用该函数:FindLibs(),但可以通过执行list(LENGTH ARGN _ARG_COUNT) 并确保您返回的变量_ARG_COUNT 大于零,如果不是,则发出致命错误消息。这完全是可选的,但这将是 cmake 开发人员需要注意的两种解决方案之间的另一个主要区别。
    【解决方案4】:

    根据(几乎)current CMake documentation,${ARGV} 符号应该扩展到整个参数列表。这应该使调用位置的事情变得更简单。

    【讨论】:

    • 小心:${ARGV} 包含宏提供的所有参数,包括已定义的参数。例如,如果你有这个宏:macro( FindLibs SomeVar1 SomeVar2 ) 并像这样使用它:FindLibs( "value1" "value2" zlib png jpeg),那么${ARGV} 将持有value1;value2;zlib;png;jpeg,这可能不是用户想要的。如果用户只想得到"zlib;png;jpeg",那么正确使用的变量是${ARGN} 而不是${ARGV} 在给定的问题中,使用${ARGV} 很好,只是因为它是接收到的唯一参数。跨度>
    • 另外,使用${ARGV}${ARGN} 并不能保护函数在没有任何参数的情况下被使用,例如:FindLibs(),但它可以通过list(LENGTH ARGN _ARG_COUNT) 和 make 轻松修复确定_ARG_COUNT 大于零。
    猜你喜欢
    • 1970-01-01
    • 2015-08-03
    • 1970-01-01
    • 2019-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-24
    相关资源
    最近更新 更多