如何将文件写入当前目录而不是 bazel-out

How to write files to current directory instead of bazel-out

我的目录结构如下:

my_dir
|
 --> src
|    |
|     --> foo.cc
|     --> BUILD
|
 --> WORKSPACE
|
 --> bazel-out/ (symlink)
| 
| ...

src/BUILD 包含以下代码:

cc_binary(
    name = "foo",
    srcs = ["foo.cc"]
)

文件 foo.cc 使用 <fstream> 实用程序以常规方式创建一个名为 bar.txt 的文件。

但是,当我使用 bazel run //src:foo 调用 Bazel 时,文件 bar.txt 被创建并放置在 bazel-out/darwin-fastbuild/bin/src/foo.runfiles/foo/bar.txt 而不是 my_dir/src/bar.txt 中,原始源所在的位置。

我尝试将 outs 字段添加到 foo 规则,但 Bazel 抱怨说 outs 不是 cc_binary 的可识别属性。

我也想过创建一个 filegroup 规则,但是没有 deps 字段,我可以在其中声明 foo 作为这些文件的依赖项。

如何确保 运行 和 cc_binary 规则生成的文件放置在 my_dir/src/bar.txt 而不是 bazel-out/...

Bazel 不允许您修改工作区的状态,这是设计使然。

简短的回答是您不希望过去构建的结果修改您的工作区状态,因此可能会修改未来构建的结果。如果 运行 Bazel 在同一个工作空间上多次导致不同的输出,这将违反可重复性。

举你的例子:想象调用 bazel run //src:foo 插入

#define true false
#define false true

src/foo.cc 的顶部。如果您再次调用 bazel run //src:foo 会怎样?

长答案:https://docs.bazel.build/versions/master/rule-challenges.html#assumption-aim-for-correctness-throughput-ease-of-use-latency

这里有关于输出目录的更多信息:https://docs.bazel.build/versions/master/output_directories.html#documentation-of-the-current-bazel-output-directory-layout

使用 genrule 可能有一个解决方法。下面是我使用 genrule 将文件复制到 .git 文件夹的示例。

genrule(
    name = "precommit",
    srcs = glob(["git/**"]),
    outs = ["precommit.txt"],
    # folder contain this BUILD.bazel file is tool which will be symbol linked, we use cd -P to get to the physical path
    cmd = "echo 'setup pre-commit.sh' > $(OUTS) && cd -P tools && ./path/to/your-script.sh",
    local = 1,  # required
)

如果您在 运行 中传递输出文件的名称,您可以简单地使用绝对路径。如果您在 linux 中,则可以使用 realpath 实用程序使这更容易。如果您在 mac 上,它包含在 brew install coreutils 中。然后 运行 它看起来像:

bazel run my_app_dir:binary_target -- --output_file=`realpath relative/path/to.output

这已被讨论和解释 in a Bazel issue。建议使用 Bazel 外部工具:

As I understand the use-case, this is out-of-scope for building and in the scope of, perhaps, workspace configuration. What I'm sure of is that an external tool would be both easier and safer to write for this purpose, than to introduce such a deep design change to Bazel.

The tool would copy the files from the output tree into the source tree, and update a manifest file (also in the source tree) that lists the path-digest pairs. The sources and the manifest file would all be versioned. A genrule or a sh_test would depend on the file-generating genrules, as well as on this manifest file, and compare the file-generating genrules' outputs' digests (in the output tree) to those in the manifest file, and would fail if there's a mismatch. In that case the user would need to run the external tool, thus update the source tree and the manifest, then rerun the build, which is the same workflow as you described, except you'd run this tool instead of bazel regenerate-autogenerated-sources.