Windows でのルールの記述

問題を報告 ソースを表示

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

パス

問題:

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

    Windows は長いパス(最大 32,767 文字)もサポートしていますが、多くのプログラムは下限値を持って構築されています。

    アクションで実行するプログラムについては、注意が必要です。

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

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

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

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

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

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

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

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

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

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

解決策:

  • パスを短くします。

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

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

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

    --output_user_root=<path> フラグを使用して、Bazel 出力の短いパスを指定します。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") は同じ結果になります。(これは他の言語にも当てはまります)。

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

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

解決策:

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

    これは 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 属性で使用できます。

    テストルールの例:

    • diff_test()出典ドキュメント): 2 つのファイルの内容を比較するテスト

    • native_test()出典ドキュメント): *_test ルールでネイティブ バイナリをラップします。これにより、bazel test

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