如何将参数从命令行传递到 bazel 文件
How to pass argument from command line to bazel file
我在 .bzl 文件示例中声明了一个变量:VERSION_NUMBER = "00"
。
当我构建不同版本的项目时,我想从命令行覆盖这个变量。
示例:bazel 构建目标 --sunbversion_number= "99"
我想更改此变量,因为它在某些函数中被调用以创建输出路径的名称。
示例:对于版本“00”,输出文件将为:name_00.extension
对于版本“99”,输出文件将是:name_99.extension
这是我的例子:
在 .bzl 文件中我声明:
SUBVERSION_NUMBER = "99"
return 与 SUBVERSION_NUMBER
有关的文件名的函数
def get_name(SUBVERSION_NUMBER):
return "test-"+SUBVERSION_NUMBER
OUTPUT_NAME = get_name("99")
然后我的genrule():
genrule(name = "test",
srcs = [srcs]
,
outs = [OUTPUT_NAME+".tek"],
cmd = "cmd to generate the file" )
当我构建此规则时,我得到输出文件 test-99.tek
我想要的是当我 运行 bazel build test --//version=01
或任何其他建议的解决方案时,我想得到输出 test-01.tek
谢谢
没有办法像那样从命令行获取值到 bzl 文件,但是有几个选项,具体取决于您想要做什么。
一种方法是使用“stamping”设置版本,然后将版本化文件放入一个已知名称的 zip 文件中,例如使用一个genrule。 Build stamping 通常用于将版本号和其他信息嵌入到输出文件本身中,但也可以在这里使用。 zip 文件是必需的,因为在加载时必须知道输出文件名(即在分析时处理来自命令行的任何配置数据之前)。
像这样:
# out.txt is the original unversioned file
genrule(
name = "gen_out",
outs = ["out.txt"],
cmd = "echo foo > $@",
)
genrule(
name = "gen_versioned_out",
outs = ["out_versioned.zip"],
srcs = [":out.txt"],
tools = ["@bazel_tools//tools/zip:zipper"],
stamp = True,
cmd = """
# bazel-out/stable-status.txt is created when stamp = True
# Value of BUILD_EMBED_LABEL key comes from --embed_label on the command line
version="$$(grep BUILD_EMBED_LABEL bazel-out/stable-status.txt | cut -d ' ' -f 2)"
# Set a reasonable default if --embed_label was not specified
if [ -z "$$version" ]; then version="0"; fi
file="$$(basename $<)"
name="$${file%%.*}"
ext="$${file#*.}"
versioned_file="$${name}_$${version}.$${ext}"
# zipper allows specifying the name of the file in the zip directly, unlike the
# regular zip tool.
# c = create
# $@ = output file from "outs"
# $< = input file from "srcs"
# $$versioned_file=$< = "put this file in to the archive with this name"
$(location @bazel_tools//tools/zip:zipper) c "$@" "$$versioned_file=$<"
""",
)
然后:
$ bazel build out_versioned.zip --embed_label=99
INFO: Analyzed target //:out_versioned.zip (7 packages loaded, 19 targets configured).
INFO: Found 1 target...
Target //:out_versioned.zip up-to-date:
bazel-bin/out_versioned.zip
INFO: Elapsed time: 0.340s, Critical Path: 0.10s
INFO: 3 processes: 1 internal, 2 linux-sandbox.
INFO: Build completed successfully, 3 total actions
$ unzip -l bazel-bin/out_versioned.zip
Archive: bazel-bin/out_versioned.zip
Length Date Time Name
--------- ---------- ----- ----
4 2010-01-01 00:00 out_99.txt
--------- -------
4 1 file
这样会生成一个包含版本控制文件的已知名称的 zip 文件。
另一种方法是使用“用户定义的构建设置”:
https://docs.bazel.build/versions/master/skylark/config.html#user-defined-build-settings
像这样:
defs.bzl
:
def _version_file_impl(ctx):
version = ctx.attr._version[VersionProvider].version
name, extension = ctx.file.file.basename.rsplit(".", 1)
versioned_file = ctx.actions.declare_file(
"%s_%s.%s" % (name, version, extension))
copy_args = ctx.actions.args()
copy_args.add_all([ctx.file.file, versioned_file])
ctx.actions.run_shell(
inputs = [ctx.file.file],
outputs = [versioned_file],
command = 'cp "" ""',
arguments = [copy_args])
return DefaultInfo(files = depset([versioned_file]))
version_file = rule(
implementation = _version_file_impl,
attrs = {
"file": attr.label(mandatory = True, allow_single_file = True),
"_version": attr.label(default = "//:version"),
}
)
VersionProvider = provider(fields = ["version"])
def _version_flag_impl(ctx):
return VersionProvider(version = ctx.build_setting_value)
version_flag = rule(
implementation = _version_flag_impl,
build_setting = config.int(flag = True),
)
BUILD
:
load(":defs.bzl", "version_flag", "version_file")
version_flag(
name = "version",
build_setting_default = 0,
)
genrule(
name = "gen_out",
outs = ["out.txt"],
cmd = "echo foo > $@",
)
version_file(
name = "versioned_out",
file = ":out.txt",
)
然后:
$ bazel build :versioned_out --//:version=99
INFO: Analyzed target //:versioned_out (5 packages loaded, 10 targets configured).
INFO: Found 1 target...
Target //:versioned_out up-to-date:
bazel-bin/out_99.txt
INFO: Elapsed time: 0.322s, Critical Path: 0.06s
INFO: 3 processes: 1 internal, 2 linux-sandbox.
INFO: Build completed successfully, 3 total actions
这样会生成名称中包含版本的文件。虽然没有引用版本文件本身的标签,所以 bazel build :out_99.txt
和 srcs = [":out_99.txt"]
都不起作用,你必须通过 versioned_out
目标。
更新:
这是一个可以控制多个输出的版本:
defs.bzl
:
def _versioned_files_impl(ctx):
version = ctx.attr._version[VersionProvider].version
versioned_files = []
for f in ctx.attr.src.files.to_list():
name, extension = f.basename.rsplit(".", 1)
versioned_file = ctx.actions.declare_file(
"%s_%s.%s" % (name, version, extension))
versioned_files.append(versioned_file)
copy_args = ctx.actions.args()
copy_args.add_all([f, versioned_file])
ctx.actions.run_shell(
inputs = [f],
outputs = [versioned_file],
command = 'cp "" ""',
arguments = [copy_args])
return DefaultInfo(files = depset(versioned_files))
versioned_files = rule(
implementation = _versioned_files_impl,
attrs = {
"src": attr.label(mandatory = True),
"_version": attr.label(default = "//:version"),
}
)
VersionProvider = provider(fields = ["version"])
def _version_flag_impl(ctx):
return VersionProvider(version = ctx.build_setting_value)
version_flag = rule(
implementation = _version_flag_impl,
build_setting = config.int(flag = True),
)
BUILD
:
load(":defs.bzl", "version_flag", "versioned_files")
version_flag(
name = "version",
build_setting_default = 0,
)
genrule(
name = "gen_out",
outs = ["foo.txt", "bar.txt", "baz.txt"],
cmd = """
echo foo > $(location foo.txt)
echo bar > $(location bar.txt)
echo baz > $(location baz.txt)
""",
)
versioned_files(
name = "versioned_files",
src = ":gen_out",
)
用法:
$ bazel build versioned_files --//:version=123
INFO: Analyzed target //:versioned_files (5 packages loaded, 9 targets configured).
INFO: Found 1 target...
Target //:versioned_files up-to-date:
bazel-bin/foo_123.txt
bazel-bin/bar_123.txt
bazel-bin/baz_123.txt
INFO: Elapsed time: 0.491s, Critical Path: 0.06s
INFO: 5 processes: 1 internal, 4 linux-sandbox.
INFO: Build completed successfully, 5 total actions
更新:
将版本放入 cc 目标定义的示例:
BUILD
:
cc_binary(
name = "main",
srcs = ["main.cc"],
defines = ["VERSION=\\"$(VERSION)\\""],
)
main.cc
:
#include <iostream>
#ifndef VERSION
#define VERSION "0.0.0"
#endif
int main() {
std::cout << "version: " << VERSION << std::endl;
return 0;
}
构建和运行:
$ bazel run main --define=VERSION=1.2.3
INFO: Analyzed target //:main (15 packages loaded, 52 targets configured).
INFO: Found 1 target...
Target //:main up-to-date:
bazel-bin/main
INFO: Elapsed time: 0.524s, Critical Path: 0.26s
INFO: 6 processes: 4 internal, 2 linux-sandbox.
INFO: Build completed successfully, 6 total actions
INFO: Build completed successfully, 6 total actions
version: 1.2.3
结合上述方法,您必须在命令行中同时指定 --//:version=1.2.3
和 --define=VERSION=1.2.3
。有一种方法只有 --//:version
,但它需要另一个像 versioned_files
这样的 Starlark 规则,它要么
生成一个文件,其中包含 data
属性中的版本,程序在 运行 时间读取,或
一个 Starlark 规则,它生成一个包含版本的 C++ 文件,然后将其放入 cc_library
的源代码中,您的程序的其余部分可以依赖并使用它在编译时。
这些方法可能需要重构您的程序。
我在 .bzl 文件示例中声明了一个变量:VERSION_NUMBER = "00"
。
当我构建不同版本的项目时,我想从命令行覆盖这个变量。
示例:bazel 构建目标 --sunbversion_number= "99"
我想更改此变量,因为它在某些函数中被调用以创建输出路径的名称。
示例:对于版本“00”,输出文件将为:name_00.extension
对于版本“99”,输出文件将是:name_99.extension
这是我的例子:
在 .bzl 文件中我声明:
SUBVERSION_NUMBER = "99"
return 与 SUBVERSION_NUMBER
有关的文件名的函数
def get_name(SUBVERSION_NUMBER):
return "test-"+SUBVERSION_NUMBER
OUTPUT_NAME = get_name("99")
然后我的genrule():
genrule(name = "test",
srcs = [srcs]
,
outs = [OUTPUT_NAME+".tek"],
cmd = "cmd to generate the file" )
当我构建此规则时,我得到输出文件 test-99.tek
我想要的是当我 运行 bazel build test --//version=01
或任何其他建议的解决方案时,我想得到输出 test-01.tek
谢谢
没有办法像那样从命令行获取值到 bzl 文件,但是有几个选项,具体取决于您想要做什么。
一种方法是使用“stamping”设置版本,然后将版本化文件放入一个已知名称的 zip 文件中,例如使用一个genrule。 Build stamping 通常用于将版本号和其他信息嵌入到输出文件本身中,但也可以在这里使用。 zip 文件是必需的,因为在加载时必须知道输出文件名(即在分析时处理来自命令行的任何配置数据之前)。
像这样:
# out.txt is the original unversioned file
genrule(
name = "gen_out",
outs = ["out.txt"],
cmd = "echo foo > $@",
)
genrule(
name = "gen_versioned_out",
outs = ["out_versioned.zip"],
srcs = [":out.txt"],
tools = ["@bazel_tools//tools/zip:zipper"],
stamp = True,
cmd = """
# bazel-out/stable-status.txt is created when stamp = True
# Value of BUILD_EMBED_LABEL key comes from --embed_label on the command line
version="$$(grep BUILD_EMBED_LABEL bazel-out/stable-status.txt | cut -d ' ' -f 2)"
# Set a reasonable default if --embed_label was not specified
if [ -z "$$version" ]; then version="0"; fi
file="$$(basename $<)"
name="$${file%%.*}"
ext="$${file#*.}"
versioned_file="$${name}_$${version}.$${ext}"
# zipper allows specifying the name of the file in the zip directly, unlike the
# regular zip tool.
# c = create
# $@ = output file from "outs"
# $< = input file from "srcs"
# $$versioned_file=$< = "put this file in to the archive with this name"
$(location @bazel_tools//tools/zip:zipper) c "$@" "$$versioned_file=$<"
""",
)
然后:
$ bazel build out_versioned.zip --embed_label=99
INFO: Analyzed target //:out_versioned.zip (7 packages loaded, 19 targets configured).
INFO: Found 1 target...
Target //:out_versioned.zip up-to-date:
bazel-bin/out_versioned.zip
INFO: Elapsed time: 0.340s, Critical Path: 0.10s
INFO: 3 processes: 1 internal, 2 linux-sandbox.
INFO: Build completed successfully, 3 total actions
$ unzip -l bazel-bin/out_versioned.zip
Archive: bazel-bin/out_versioned.zip
Length Date Time Name
--------- ---------- ----- ----
4 2010-01-01 00:00 out_99.txt
--------- -------
4 1 file
这样会生成一个包含版本控制文件的已知名称的 zip 文件。
另一种方法是使用“用户定义的构建设置”: https://docs.bazel.build/versions/master/skylark/config.html#user-defined-build-settings
像这样:
defs.bzl
:
def _version_file_impl(ctx):
version = ctx.attr._version[VersionProvider].version
name, extension = ctx.file.file.basename.rsplit(".", 1)
versioned_file = ctx.actions.declare_file(
"%s_%s.%s" % (name, version, extension))
copy_args = ctx.actions.args()
copy_args.add_all([ctx.file.file, versioned_file])
ctx.actions.run_shell(
inputs = [ctx.file.file],
outputs = [versioned_file],
command = 'cp "" ""',
arguments = [copy_args])
return DefaultInfo(files = depset([versioned_file]))
version_file = rule(
implementation = _version_file_impl,
attrs = {
"file": attr.label(mandatory = True, allow_single_file = True),
"_version": attr.label(default = "//:version"),
}
)
VersionProvider = provider(fields = ["version"])
def _version_flag_impl(ctx):
return VersionProvider(version = ctx.build_setting_value)
version_flag = rule(
implementation = _version_flag_impl,
build_setting = config.int(flag = True),
)
BUILD
:
load(":defs.bzl", "version_flag", "version_file")
version_flag(
name = "version",
build_setting_default = 0,
)
genrule(
name = "gen_out",
outs = ["out.txt"],
cmd = "echo foo > $@",
)
version_file(
name = "versioned_out",
file = ":out.txt",
)
然后:
$ bazel build :versioned_out --//:version=99
INFO: Analyzed target //:versioned_out (5 packages loaded, 10 targets configured).
INFO: Found 1 target...
Target //:versioned_out up-to-date:
bazel-bin/out_99.txt
INFO: Elapsed time: 0.322s, Critical Path: 0.06s
INFO: 3 processes: 1 internal, 2 linux-sandbox.
INFO: Build completed successfully, 3 total actions
这样会生成名称中包含版本的文件。虽然没有引用版本文件本身的标签,所以 bazel build :out_99.txt
和 srcs = [":out_99.txt"]
都不起作用,你必须通过 versioned_out
目标。
更新:
这是一个可以控制多个输出的版本:
defs.bzl
:
def _versioned_files_impl(ctx):
version = ctx.attr._version[VersionProvider].version
versioned_files = []
for f in ctx.attr.src.files.to_list():
name, extension = f.basename.rsplit(".", 1)
versioned_file = ctx.actions.declare_file(
"%s_%s.%s" % (name, version, extension))
versioned_files.append(versioned_file)
copy_args = ctx.actions.args()
copy_args.add_all([f, versioned_file])
ctx.actions.run_shell(
inputs = [f],
outputs = [versioned_file],
command = 'cp "" ""',
arguments = [copy_args])
return DefaultInfo(files = depset(versioned_files))
versioned_files = rule(
implementation = _versioned_files_impl,
attrs = {
"src": attr.label(mandatory = True),
"_version": attr.label(default = "//:version"),
}
)
VersionProvider = provider(fields = ["version"])
def _version_flag_impl(ctx):
return VersionProvider(version = ctx.build_setting_value)
version_flag = rule(
implementation = _version_flag_impl,
build_setting = config.int(flag = True),
)
BUILD
:
load(":defs.bzl", "version_flag", "versioned_files")
version_flag(
name = "version",
build_setting_default = 0,
)
genrule(
name = "gen_out",
outs = ["foo.txt", "bar.txt", "baz.txt"],
cmd = """
echo foo > $(location foo.txt)
echo bar > $(location bar.txt)
echo baz > $(location baz.txt)
""",
)
versioned_files(
name = "versioned_files",
src = ":gen_out",
)
用法:
$ bazel build versioned_files --//:version=123
INFO: Analyzed target //:versioned_files (5 packages loaded, 9 targets configured).
INFO: Found 1 target...
Target //:versioned_files up-to-date:
bazel-bin/foo_123.txt
bazel-bin/bar_123.txt
bazel-bin/baz_123.txt
INFO: Elapsed time: 0.491s, Critical Path: 0.06s
INFO: 5 processes: 1 internal, 4 linux-sandbox.
INFO: Build completed successfully, 5 total actions
更新:
将版本放入 cc 目标定义的示例:
BUILD
:
cc_binary(
name = "main",
srcs = ["main.cc"],
defines = ["VERSION=\\"$(VERSION)\\""],
)
main.cc
:
#include <iostream>
#ifndef VERSION
#define VERSION "0.0.0"
#endif
int main() {
std::cout << "version: " << VERSION << std::endl;
return 0;
}
构建和运行:
$ bazel run main --define=VERSION=1.2.3
INFO: Analyzed target //:main (15 packages loaded, 52 targets configured).
INFO: Found 1 target...
Target //:main up-to-date:
bazel-bin/main
INFO: Elapsed time: 0.524s, Critical Path: 0.26s
INFO: 6 processes: 4 internal, 2 linux-sandbox.
INFO: Build completed successfully, 6 total actions
INFO: Build completed successfully, 6 total actions
version: 1.2.3
结合上述方法,您必须在命令行中同时指定 --//:version=1.2.3
和 --define=VERSION=1.2.3
。有一种方法只有 --//:version
,但它需要另一个像 versioned_files
这样的 Starlark 规则,它要么
生成一个文件,其中包含
data
属性中的版本,程序在 运行 时间读取,或一个 Starlark 规则,它生成一个包含版本的 C++ 文件,然后将其放入
cc_library
的源代码中,您的程序的其余部分可以依赖并使用它在编译时。
这些方法可能需要重构您的程序。