日程の確定: BazelCon 2023 は、Google ミュンヘンで 10 月 24 ~ 25 日に開催されます。詳細

Windows でのルールの作成

問題を報告する ソースを表示

このページでは、Windows と互換性のあるルールの記述、移植可能なルールの作成に関する一般的な問題、およびいくつかのソリューションを取り上げます。

パス

問題:

  • 長さの上限: パスの最大長は 259 文字です。

    Windows では、より長いパス(最大 32,767 文字)もサポートされますが、多くのプログラムは下限を使用してビルドされます。

    アクションで実行するプログラムについては、この点に留意してください。

  • 作業ディレクトリ: 259 文字以内に制限されます。

    プロセスは、259 文字を超えるディレクトリに cd することはできません。

  • 大文字と小文字の区別: Windows パスでは大文字と小文字が区別されません。

    操作のコマンドラインを作成する際は、この点に注意してください。

  • パス区切り文字: バックスラッシュ(\`), not forward slash (/`)。

    Bazel は / 区切り文字を使用してパスを Unix 形式で保存します。Windows プログラムの中には、Unix スタイルのパスをサポートしているものもありますが、そうでないものもあります。cmd.exe の組み込みコマンドでサポートされているものもあれば、サポートされていないコマンドもあります。

    アクションのコマンドラインと環境変数を作成する場合は、常に \` separators on Windows: replace / with を使用することをおすすめします。

  • 絶対パス: スラッシュ(/)で始めないでください。

    Windows の絶対パスは、C:\foo\bar.txt などのドライブ文字で始まります。ファイルシステムのルートは 1 つではありません。

    ルールでパスが絶対パスかどうかをチェックする場合は、この点に注意してください。多くの場合、絶対パスは、ポータブルでないので避けてください。

解決策:

  • 経路は短くします。

    長いディレクトリ名、深くネストされたディレクトリ構造、長いファイル名、長いワークスペース名、長いターゲット名は避けてください。

    これらはすべてアクションの入力ファイルのパスを構成する可能性があり、パスの長さの上限を超えることがあります。

  • 短い出力ルートを使用します。

    Bazel 出力の短いパスを指定するには、--output_user_root=<path> フラグを使用します。Bazel 出力専用ドライブ(または仮想ドライブ)を用意することをおすすめします。D:\`), and adding this line to your.bazelrc ファイルなど。

    build --output_user_root=D:/
    

    または

    build --output_user_root=C:/_bzl
    
  • ジャンクションを使用する。

    ジャンクションとは、大まかに言うと、ディレクトリ シンボリック リンク[1]です。ジャンクションは簡単に作成でき、長いパスを持つ(同じパソコン上の)ディレクトリを指定できます。パスが短く対象が長いジャンクションをビルド アクションが作成すると、パスの上限が短いツールがジャンクションのディレクトリ内のファイルにアクセスできます。

    .bat ファイルまたは cmd.exe で、次のようにジャンクションを作成できます。

    mklink /J c:\path\to\junction c:\path\to\very\long\target\path
    

    [1]: ジャンクションは、シンボリック リンクではありません。ただし、ビルド アクションのため、ジャンクションをディレクトリ シンボリック リンクとみなす場合があります。

  • actions / envvars のパスで / を「`」に置き換えます。

    アクションのコマンドラインまたは環境変数を作成する場合は、パスを Windows スタイルにします。例:

    def as_path(p, is_windows):
        if is_windows:
            return p.replace("/", "\\")
        else:
            return p
    

環境変数

問題:

  • 大文字と小文字の区別: Windows 環境変数の名前では大文字と小文字が区別されません。

    たとえば Java では、System.getenv("SystemRoot")System.getenv("SYSTEMROOT") の結果は同じになります。(他の言語にも適用されます)。

  • 密閉性: アクションで使用するカスタム環境変数は、できるだけ少なくする必要があります。

    環境変数はアクションのキャッシュキーの一部です。頻繁に変更される環境変数や、ユーザーに合わせてカスタマイズされる環境変数がアクションで使用される場合、ルールのキャッシュ可能性が低くなります。

解決策:

  • 大文字の環境変数名のみを使用する。

    この機能は Windows、macOS、Linux で動作します。

  • アクション環境を最小化する。

    ctx.actions.run を使用する場合は、環境を ctx.configuration.default_shell_env に設定します。アクションでより多くの環境変数が必要な場合は、これらをすべて辞書に入れて、アクションに渡します。例:

    load("@bazel_skylib//lib:dicts.bzl", "dicts")
    
    def _make_env(ctx, output_file, is_windows):
        out_path = output_file.path
        if is_windows:
            out_path = out_path.replace("/", "\\")
        return dicts.add(ctx.configuration.default_shell_env, {"MY_OUTPUT": out_path})
    

Actions

問題:

  • 実行可能ファイルの出力: すべての実行可能ファイルには、実行可能拡張子が必要です。

    最も一般的な拡張子は .exe(バイナリ ファイル)と .bat(バッチ スクリプト)です。

    シェル スクリプト(.sh)は Windows では実行できないことに注意してください。ctx.actions.runexecutable として指定することはできません。また、ファイルに設定できる +x 権限がないため、Linux などの任意のファイルを実行できません。

  • Bash コマンド: 移植性を高めるため、Bash コマンドを直接アクションで実行しないでください。

    Bash は Unix 系システムで広く普及していますが、Windows では利用できないことが多いです。Bazel 自体は Bash(MSYS2)への依存度が低くなっているため、将来的には Bazel とともに MSYS2 をインストールする可能性が低くなります。Windows でルールを簡単に使用できるように、アクションで Bash コマンドを実行しないでください。

  • 末尾: Windows では CRLF(\r\n)を使用し、Unix 系システムでは LF(\n)を使用します。

    テキスト ファイルを比較する際は、この点に注意してください。チェックアウトまたは commit の際には、Git の設定、特に行末に注意してください。(Git の core.autocrlf 設定をご覧ください)。

解決策:

  • Bash 不使用のルールを使用します。

    native.genrule() は、Bash コマンドのラッパーであり、ファイルのコピーやテキスト ファイルの書き込みなどの簡単な問題の解決によく使用されます。Bash に頼ることなく(そしてホイールを再構築する必要もありません)、bazel-skylib がニーズに合ったルールを持っているかどうかを確認できます。Windows でビルドまたはテストしたときに Bash に依存しないものもあります。

    ビルドルールの例:

    • copy_file()ソースドキュメント): ファイルを別の場所にコピーします(必要に応じて実行可能にします)。

    • write_file()ソースドキュメント): 希望する行末(autounixwindows)を含むテキスト ファイルを書き込み、実行可能にします(スクリプトの場合)。

    • run_binary()ソースドキュメント): 指定された入力と想定される出力をビルド アクションとしてバイナリ(または *_binary ルール)を実行します(これは ctx.actions.run のビルドルールのラッパーです)。

    • native_binary()ソースドキュメント): *_binary ルールでネイティブ バイナリをラップします。これは、bazel run するか、run_binary()tool 属性または native.genrule()tools 属性で使用できます。

    テストルールの例:

  • Windows では、些細なことでも .bat スクリプトの使用を検討します。

    .sh スクリプトの代わりに、.bat スクリプトを使用して簡単なタスクを解決できます。

    たとえば、何もしないスクリプト、メッセージを出力するスクリプト、固定のエラーコードで終了するスクリプトが必要な場合は、シンプルな .bat ファイルで十分です。ルールが DefaultInfo() プロバイダを返す場合、executable フィールドは Windows 上のその .bat ファイルを参照します。

    macOS と Linux ではファイル拡張子は重要ではないため、シェル スクリプトであっても、いつでも .bat を拡張子として使用できます。

    空の .bat ファイルは実行できないことに注意してください。空のスクリプトが必要な場合は、そのスペースを 1 つ作成します。

  • 原則に基づいて Bash を使用する。

    Starlark のビルドルールとテストルールで、ctx.actions.run_shell を使用して Bash スクリプトと Bash コマンドを実行します。

    Starlark マクロでは、Bash スクリプトとコマンドを native.sh_binary() または native.genrule() でラップします。Bazel は Bash が利用可能かどうかを確認し、Bash でスクリプトまたはコマンドを実行します。

    Starlark リポジトリ ルールでは、Bash を一切回避してください。Bazel では現在、Bash コマンドを原則としてリポジトリ ルールで実行する方法がありません。

ファイルの削除

問題:

  • ファイルを開くと削除できません。

    開いているファイルは削除できません(デフォルトでは)。アクセスしようとすると「アクセス拒否」エラーが発生します。ファイルを削除できない場合、実行中のプロセスではファイルが開いたままになっている可能性があります。

  • 実行中のプロセスの作業ディレクトリは削除できません。

    プロセスには作業ディレクトリに対するオープン ハンドルがあり、プロセスが終了するまでディレクトリを削除できません。

解決策:

  • コード内で、ファイルの利用を終了するようにしてください。

    Java では、try-with-resources を使用します。Python では、with open(...) as f: を使用します。原則として、できるだけ早くハンドルを閉じるようにしてください。