Windows でのルールの記述

問題を報告 ソースを表示

このページでは、Windows 互換ルールの作成、ポータブル ルールの作成に関する一般的な問題、いくつかの解決策について説明します。

パス

問題:

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

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

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

  • 作業ディレクトリ: 長さも 259 文字に制限されています。

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

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

    アクションのコマンドラインを作成する場合は、この点に注意してください。

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

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

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

  • 絶対パス: 先頭にスラッシュ(/)を使用しないでください。

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

    パスが絶対パスであることを確認する場合は、この点に注意してください。絶対パスは移植できないことが多いため、使用しないでください。

解決策:

  • 経路を短くします。

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

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

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

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

アクション

問題:

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

    最も一般的な拡張機能は、.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)を使用します。

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

解決策:

  • Bash を使用しない目的ルールを使用する。

    native.genrule() は Bash コマンドのラッパーであり、ファイルのコピーやテキスト ファイルの書き込みなどの単純な問題を解決するためによく使用されます。bazel-skylib に独自のニーズに合ったルールがあるかどうかを確認します。Windows でビルド/テストする場合は、いずれも Bash に依存しません。

    ビルドルールの例:

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

    • write_file()ソースドキュメント): 目的の行の末尾(autounix、または windows)を含むテキスト ファイルを書き込む。スクリプトの場合は、必要に応じて実行可能にします。

    • 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: を使用します。原則として、ハンドルはできるだけ早く閉じるようにしてください。