このページでは、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]: 厳密に言えば、ジャンクションはシンボリック リンクではありませんが、ビルド アクションの目的では、ジャンクションをディレクトリ シンボリック リンクと見なすことができます。
アクション / 環境変数のパスで
/
を `` に置き換えます。アクションのコマンドラインまたは環境変数を作成する場合は、パスを 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.run
のexecutable
として指定することはできません。ファイルに+x
権限を付与することもできないため、Linux のように任意のファイルを実行することはできません。Bash コマンド: 移植性を高めるため、アクションで Bash コマンドを直接実行しないでください。
Bash は Unix 系のシステムで広く使用されていますが、Windows では使用できないことがよくあります。Bazel 自体が Bash(MSYS2)への依存度を下げているため、今後、ユーザーが Bazel とともに MSYS2 をインストールする可能性は低くなります。Windows でルールを使いやすくするには、アクションで Bash コマンドを実行しないようにします。
行末: Windows では CRLF(
\r\n
)、Unix 系のシステムでは LF(\n
)が使用されます。テキスト ファイルを比較する際は、この点に注意してください。Git の設定、特にチェックアウトやコミット時の行末には注意してください。(Git の
core.autocrlf
設定をご覧ください)。
ソリューション:
Bash を使用しない専用のルールを使用します。
native.genrule()
は Bash コマンドのラッパーであり、ファイルのコピーやテキスト ファイルの書き込みなどの簡単な問題を解決するために使用されることがよくあります。Bash に依存する(車輪の再発明をする)ことを避けるには、bazel-skylib にニーズに合った専用のルールがあるかどうかを確認します。Windows でビルド/テストする場合、いずれも Bash に依存しません。ビルドルールの例:
copy_file()
(source, documentation): ファイルを別の場所にコピーします。必要に応じて、実行可能にすることもできます。write_file()
(source、documentation): 目的の行末(auto
、unix
、windows
)でテキスト ファイルを書き込みます。必要に応じて、実行可能にします(スクリプトの場合)。run_binary()
(source, documentation): 指定された入力と出力がビルド アクションとしてバイナリ(または*_binary
ルール)を実行します(これはctx.actions.run
のビルドルール ラッパーです)。native_binary()
(ソース、ドキュメント): ネイティブ バイナリを*_binary
ルールでラップします。このルールはbazel run
したり、run_binary()
のtool
属性やnative.genrule()
のtools
属性で使用したりできます。
テストルールの例:
diff_test()
(source、documentation): 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:
を使用します。原則として、できるだけ早くハンドルを閉じるようにしてください。