web-dev-qa-db-ja.com

リストを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" )
44
Paul

マクロに渡すときに変数を引用します。

FindLibs("${LIBRARY_NAMES_LIST}")
67
Jack Kelly

他の人から提供された答えは正しいです。最善の解決策は、実際に次のように二重引用符でリストを提供することです:

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

これは、ユーザーに少なくとも1つのライブラリーを提供するように強制するので、これは素晴らしいことです。のように呼ぶ

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 のドキュメントへのリンクを参照してください。

それが役に立てば幸いです:-)

8
mchiasson

マクロは次のようになります。

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

最初のソリューションでは、リスト変数の名前のみをマクロに渡します(1つの引数)。 2番目のソリューションでは、マクロを呼び出す前にリストを展開し、N個のパラメーターを渡します(N =リストの長さ)。

8
tamas.kenez

(ほぼ) 現在のCMakeのドキュメント によると、$ {ARGV}シンボルは引数のリスト全体に展開されるはずです。これにより、呼び出し側での処理がより簡単になります。

1
John