我可以在 Bazel 中生成 BUILD 文件吗?

Can I generate a BUILD file in Bazel?

我想使用go lint工具为bazel生成一个BUILD文件。

我会有一个 go 二进制文件来执行类似这样的事情 bash 脚本:

#!/bin/bash

cat <<EOF > BUILD
# THIS FILE IS AUTOGENERATED

package(default_visibility = ["//visibility:public"])

load("//go:def.bzl", "go_prefix", "go_library", "go_binary", "go_test")
EOF

for pkg in `go list -f {{.ImportPath}} ./...`; do
    go list -f "`cat test.in`" $pkg >> "BUILD";
done

buildifier -mode fix BUILD

test.in 文件包含:

{{ if eq .Name "main" }}
go_binary
{{else}}
go_library
{{end}}
("{{.Name}}",
    srcs=[
        {{range .GoFiles}}
            "{{.}}",
        {{end}} 
    ],
    deps=[
        {{range .Imports}}
            "{{.}}",
        {{end}} 
    ],
    csrcs=[
        {{range .CgoFiles}}
            "{{.}}",
        {{end}} 
    ],
    swig_srcs=[
        {{range .SwigFiles}}
            "{{.}}",
        {{end}} 
    ],
    cxxswig=[
        {{range .SwigCXXFiles}}
            "{{.}}",
        {{end}} 
    ],
    cflags=[
        {{range .CgoCFLAGS}}
            "{{.}}",
        {{end}} 
    ],
    cxxflags=[
        {{range .CgoCXXFLAGS}}
            "{{.}}",
        {{end}} 
    ],
    cppflags=[
        {{range .CgoCPPFLAGS}}
            "{{.}}",
        {{end}} 
    ],           
    {{ with $ctx := context}}
        {{$ctx.InstallSuffix}}
    {{end}}    
)

这会生成:

# THIS FILE IS AUTOGENERATED

package(default_visibility = ["//visibility:public"])

load("//go:def.bzl", "go_prefix", "go_library", "go_binary", "go_test")

go_library

(
    "tensorflow",
    srcs = [
        "doc.go",
        "gen.go",
        "graph.go",
        "session.go",
    ],
    deps = [
        "C",
        "encoding/binary",
        "fmt",
        "github.com/golang/protobuf/proto",
        "github.com/tensorflow/tensorflow/tensorflow/contrib/go/proto",
        "math",
        "reflect",
        "runtime",
        "strings",
        "unsafe",
    ],
    csrcs = [
        "lib.go",
        "tensor.go",
    ],
    swig_srcs = [
    ],
    cxxswig = [
        "tensorflow.swigcxx",
    ],
    cflags = [
        "-I/Users/fmilo/workspace/gopath/src/github.com/tensorflow/tensorflow/tensorflow/contrib/go/../../../",
    ],
    cxxflags = [
        "-I/Users/fmilo/workspace/gopath/src/github.com/tensorflow/tensorflow/tensorflow/contrib/go/../../../",
        "-std=c++11",
    ],
    cppflags = [
    ],
)

go_library

(
    "tensorflow",
    srcs = [
        "allocation_description.pb.go",
        "attr_value.pb.go",
        "config.pb.go",
        "cost_graph.pb.go",
        "device_attributes.pb.go",
        "event.pb.go",
        "function.pb.go",
        "graph.pb.go",
        "kernel_def.pb.go",
        "log_memory.pb.go",
        "master.pb.go",
        "memmapped_file_system.pb.go",
        "meta_graph.pb.go",
        "named_tensor.pb.go",
        "op_def.pb.go",
        "queue_runner.pb.go",
        "saved_tensor_slice.pb.go",
        "saver.pb.go",
        "step_stats.pb.go",
        "summary.pb.go",
        "tensor.pb.go",
        "tensor_description.pb.go",
        "tensor_shape.pb.go",
        "tensor_slice.pb.go",
        "tensorflow_server.pb.go",
        "test_log.pb.go",
        "tf_ops_def.go",
        "types.pb.go",
        "variable.pb.go",
        "versions.pb.go",
        "worker.pb.go",
    ],
    deps = [
        "fmt",
        "github.com/golang/protobuf/proto",
        "github.com/golang/protobuf/ptypes/any",
        "math",
    ],
    csrcs = [
    ],
    swig_srcs = [
    ],
    cxxswig = [
    ],
    cflags = [
    ],
    cxxflags = [
    ],
    cppflags = [
    ],
)

go_library

(
    "tensorflow_error",
    srcs = [
        "error_codes.pb.go",
    ],
    deps = [
        "fmt",
        "github.com/golang/protobuf/proto",
        "math",
    ],
    csrcs = [
    ],
    swig_srcs = [
    ],
    cxxswig = [
    ],
    cflags = [
    ],
    cxxflags = [
    ],
    cppflags = [
    ],
)

go_library

(
    "tensorflow_grpc",
    srcs = [
        "master_service.pb.go",
        "worker_service.pb.go",
    ],
    deps = [
        "fmt",
        "github.com/golang/protobuf/proto",
        "math",
        "tensorflow/core/protobuf",
    ],
    csrcs = [
    ],
    swig_srcs = [
    ],
    cxxswig = [
    ],
    cflags = [
    ],
    cxxflags = [
    ],
    cppflags = [
    ],
)

当然上面的 BUILD 文件还不能工作,但我想首先确定我所追求的方法是有效的。

一般情况下,您不能生成 BUILD 文件,它们必须在构建开始时就存在。 Bazel 的一般构建阶段是:

  • 解析您在命令行中指定的目标。
  • 在指定的每个目录中查找 BUILD 文件。
  • 解析那些目标提到的构建文件(等等)。
  • 生成要执行的操作树(例如,"Run shell script")。
  • 实际执行动作。

因此,当您的脚本执行时,读取 BUILD 文件的时间早已结束。

此外,输出被放在它们自己的目录中(在 bazel-out 下),因此如果不进行修改,它们甚至不会出现在您的源代码树中。

也就是说...

Skylark 远程存储库允许您执行代码以在其他存储库中写入文件,包括 BUILD 文件。所以从理论上讲,你可以有类似(未经测试)的东西:

def _gen_repo_impl(repo_ctx):
  # Writes external/reponame/BUILD
  repo_ctx.execute("/your/bash/script.sh")
  for path in repo_ctx.attr.paths:
    repo_ctx.symlink(path, path.basename)

generated_repo = repository_rule(
    implementation = _gen_repo_impl,
    attrs = {"paths": attr.label_list(allow_files = True)}
)

然后在您的 WORKSPACE 文件中,执行如下操作:

load('//path/to/your:genrepo.bzl', 'generated_repo')
generated_repo(
    name = "pwd",
    paths = ["src", "test", "third_party"],
)

然后你可以在 @pwd//... 上 build/depend 并且存储库规则将生成一个外部存储库,其中包含指向 src、测试和 third_party 的符号链接(理论上......我的代码可能已经一些错别字)。