Windows でのルールの記述

問題を報告 ソースを表示 Nightly · 7.4 .

このページでは、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 などのドライブ文字で始まります。ファイルシステムのルートは 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]: 厳密に言えば、ジャンクションはシンボリック リンクではありませんが、ビルド アクションのため、ジャンクションをディレクトリ シンボリック リンクとみなすことができます。

  • アクション / 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") は同じ結果になります。(これは他の言語にも適用されます)。

  • Hermeticity: アクションで使用するカスタム環境変数はできる限り少なくします。

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

ソリューション:

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

    これは 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 コマンドのラッパーであり、ファイルのコピーやテキスト ファイルの書き込みなどの簡単な問題の解決によく使用されます。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: を使用します。原則として、ハンドルはできるだけ早く閉じるようにしてください。