次の方法で共有


CMake スタイル ガイド

次のいずれかであるすべての CMake スクリプトが必要です。

  • scripts/ ディレクトリで、または
  • vcpkg-* ポート内

は、このドキュメントに記載されているガイドラインに従う必要があります。 既存のスクリプトは、これらのガイドラインにまだ従っていない可能性があります。これらのガイドラインに従って古いスクリプトを引き続き更新することが期待されます。

これらのガイドラインは、スクリプトに安定性を生み出すことを目的としています。 前方互換性と下位互換性の両方を容易にすることを願っています。

ガイドライン

  • アウト パラメーターを除き、関数パラメーターや${ARG<N>}を参照するのではなく、常にcmake_parse_arguments()を使用します。

    • これは必ずしも "スクリプト ローカル ヘルパー関数" に従う必要はありません

      • この場合、位置指定パラメーターは ( ${ARG<N>}を使用するのではなく) 関数宣言に配置し、ローカル ルール (つまり、 snake_case) に従って名前を付ける必要があります。
      • 例外: 省略可能な位置指定パラメーターは、ARGCを確認した後、set(argument_name "${ARG<N>}")を介して名前を指定する必要があります。
    • 出力パラメーターは、関数の最初のパラメーターである必要があります。 例:

      function(format out_var)
        cmake_parse_arguments(PARSE_ARGV 1 "arg" ...)
        # ... set(buffer "output")
        set("${out_var}" "${buffer}" PARENT_SCOPE)
      endfunction()
      
  • 解析されていない引数や未使用の引数はありません。 常に ARGN または arg_UNPARSED_ARGUMENTSを確認します。 FATAL_ERROR 可能な場合は、下位互換性のために必要に応じて WARNING します。

  • すべての cmake_parse_argumentsPARSE_ARGVを使用する必要があります。

  • すべての foreach ループでは、 IN LISTSIN ITEMS、または RANGEを使用する必要があります。

  • 変数 ${ARGV}${ARGN} は、ユーザーに役立つメッセージを除き、参照されません。

    • (つまり、 message(FATAL_ERROR "blah was passed extra arguments: ${ARGN}"))
  • マクロや最上位のコードではなく、常に関数を使用します。

    • 例外: "script-local helper macros"。 小さなマクロを定義すると便利な場合があります。 これは控えめに行う必要があり、関数を優先する必要があります。
    • 例外: vcpkg.cmakefind_package
  • スクリプト ツリー内のスクリプトでは、通常の操作の一環として監視可能な変更が必要になることは想定されません。

    • 違反の例: vcpkg_acquire_msys() には、MSYS プロジェクトが古いパッケージを削除するため、時間の経過と同時に更新が必要なパッケージとバージョンがハードコーディングされています。
    • 例外の例: vcpkg_from_sourceforge() には、メンテナンスが必要なミラーの一覧がありますが、呼び出し元に対する監視可能な動作の影響はありません。
  • 引用符の規則: CMake には、引用符で囲まれていない (foo(BAR))、引用符 (foo("BAR"))、角かっこ (foo([[BAR]])) の 3 種類の引数があります。 正しく見積もるために、次の規則に従います。

    • 引数に変数拡張 ${...}が含まれている場合は、引用符で囲む必要があります。

      • 例外: 1 つの変数が複数の引数として関数に渡される場合の "splat" 変数拡張。 この場合、引数は単に ${foo}する必要があります。

        vcpkg_list(SET working_directory)
        if(DEFINED "arg_WORKING_DIRECTORY")
          vcpkg_list(SET working_directory WORKING_DIRECTORY "${arg_WORKING_DIRECTORY}")
        endif()
        # calls do_the_thing() if NOT DEFINED arg_WORKING_DIRECTORY,
        # else calls do_the_thing(WORKING_DIRECTORY "${arg_WORKING_DIRECTORY}")
        do_the_thing(${working_directory})
        
    • それ以外の場合、引数に \\\"、または \$されていないエスケープ シーケンスが含まれている場合、その引数は引用符で囲まれた引数である必要があります。

      • たとえば、 "foo\nbar" は引用符で囲む必要があります。
    • それ以外の場合、引数に \"、または $が含まれている場合は、その引数を角かっこで囲む必要があります。

      • 例:

        set(x [[foo\bar]])
        set(y [=[foo([[bar\baz]])]=])
        
    • それ以外の場合、引数に英数字または _ではない文字が含まれている場合は、その引数を引用符で囲む必要があります。

    • それ以外の場合は、引数を引用符で囲む必要があります。

    • 例外: <variable|string>型のif()の引数は常に引用符で囲む必要があります。

      • 比較演算子に対する両方の引数 ( EQUALSTREQUALVERSION_LESSなど)。

      • MATCHESする最初の引数IN_LIST

      • 例:

        if("${FOO}" STREQUAL "BAR") # ...
        if("${BAZ}" EQUAL "0") # ...
        if("FOO" IN_LIST list_variable) # ...
        if("${bar}" MATCHES [[a[bcd]+\.[bcd]+]]) # ...
        
      • 単一の式と、 <variable|string>を受け取らないその他の種類の述語の場合は、通常の規則を使用します。

  • 単純な out-parameters を除き、"ポインター" パラメーターまたは "in-out" パラメーター (ユーザーが内容ではなく変数名を渡す) はありません。

  • 変数は空とは見なされません。 変数がローカルで使用されることを意図している場合は、文字列変数の場合は set(foo "") を使用して明示的に空に初期化し、リスト変数の場合は vcpkg_list(SET foo) する必要があります。

  • set(var) は使用しないでください。 unset(var)を使用して変数の設定を解除し、set(var "")して空の文字列に設定し、vcpkg_list(SET var)空のリストに設定します。 注: 空の文字列と空のリストは同じ値です。これは結果の違いではなく、表記上の違いです

  • API 境界を越えて親スコープから継承されることが予想されるすべての変数 (つまり、ファイルローカル関数ではない) を文書化する必要があります。 Triplet ファイルに記載されているすべての変数は文書化されていると見なされます。

  • 出力パラメーターは、 PARENT_SCOPE でのみ設定され、読み取りは行われます。 関数スコープを介してパラメーターを転送するためのヘルパー z_vcpkg_forward_output_variable() も参照してください。

  • CACHE 変数は、厳密に結合された関数間で内部的に共有されるグローバル変数と、1 つの関数内の内部状態に対してのみ使用され、作業が重複しないようにします。 これらは非常に控えめに使用し、 Z_VCPKG_ プレフィックスを使用して、他のコードで定義されるローカル変数との衝突を回避する必要があります。

    • 例:
      • vcpkg_cmake_configure's Z_VCPKG_CMAKE_GENERATOR
      • z_vcpkg_get_cmake_vars's Z_VCPKG_GET_CMAKE_VARS_FILE
  • include()s は、 ports.cmake または vcpkg-port-config.cmakeでのみ許可されます。

  • foreach(RANGE)'s 引数常に自然数<start> must は常に<stop>以下です。

    • これは、次のような方法でチェックする必要があります。

      if("${start}" LESS_EQUAL "${end}")
        foreach(RANGE "${start}" "${end}")
          ...
        endforeach()
      endif()
      
  • ポート ベースのスクリプトはすべて、複数回含まれるのを避けるために include_guard(GLOBAL) を使用する必要があります。

必要な CMake バージョン

  • vcpkg.cmakeを除くすべての CMake スクリプトは、ports.cmakecmake_minimum_requiredに存在する CMake のバージョンを想定できます。
    • このcmake_minimum_requiredは、すべてのヘルパー CMakeLists.txt ファイルのcmake_minimum_requiredと同様に、新しいバージョンの CMake がvcpkgTools.xmlに追加されるたびにバンプする必要があります。
  • vcpkg.cmake CMake のバージョンを 3.7.2 に戻す必要があります。
    • 特定の関数とオプションでは、より大きな CMake バージョンが想定される場合があります。その場合は、必要な CMake バージョンでその関数またはオプションをコメントしてください。

既存の関数の変更

  • 非内部関数の引数を削除しないでください。何もする必要がなくなった場合は、通常どおりに受け取り、使用時に警告します。
  • 新しい必須引数を追加しないでください。

変数に名前を付ける

  • cmake_parse_arguments: プレフィックスを > に設定します。 "arg"

  • ローカル変数の名前は次のとおりです。 snake_case

  • 内部グローバル変数名の前には、 Z_VCPKG_が付いています。

  • 外部の実験用グローバル変数名の先頭には、 X_VCPKG_が付いています。

  • 内部関数の先頭に z_vcpkg_

    • 1 つの関数 (つまり、ヘルパー関数) の内部にある関数は、 [z_]<func>_<name>という名前になります。ここで、 <func> はヘルパーである関数の名前であり、 <name> はヘルパー関数の機能です。
      • z_<func>z_がなく、ヘルパー関数にz_z_foo_bar名前を付けない場合は、前面に追加する必要があります。
  • パブリック グローバル変数には、 VCPKG_という名前が付けられます。