【问题标题】:Bazel Make variable substitution for the package root?Bazel 为包根目录进行变量替换?
【发布时间】:2025-12-15 00:10:01
【问题描述】:

假设我有一个这样的 Bazel 项目:

tree .
.
├── foo
│   ├── BUILD.bazel
│   └── foo.txt
└── WORKSPACE

1 directory, 3 files

foo/BUILD.bazel:

genrule(
  name = "bar",
  srcs = [
    "foo.txt",
  ],
  cmd = "cp foo.txt $@",
  outs = [
    "bar.txt",
  ],
)

我无法构建bazel build //foo:bar

bazel build //foo:bar

...

cp: cannot stat 'foo.txt': No such file or directory

看来cmd 中的路径必须相对于WORKSPACE 根,而不是BUILD 根。

这行得通:

genrule(
  name = "bar",
  srcs = [
    "foo.txt",
  ],
  # cmd = "cp foo.txt $@",
  cmd = "cp foo/foo.txt $@",
  outs = [
    "bar.txt",
  ],
)

必须指定完整路径很不方便,尤其是当BUILD 文件可能被移动时。

很高兴能够编写脚本就好像它们从它们在源树中的位置运行(当然它们实际上在沙箱中运行! )

是否有一个 Make 变量替换可以让我更清楚地指定它?

例如:

genrule(
  name = "bar",
  srcs = [
    "foo.txt",
  ],
  cmd = "cd $(SRCDIR) && cp foo.txt $@",
  outs = [
    "bar.txt",
  ],
)

这里的$(SRCDIR) 可以扩展为./foo

请注意,这是一个人为的示例。我不能使用$(SRCS),因为我需要以不同的方式使用输入文件。我也不能使用$<,因为我不止一次使用srcs

【问题讨论】:

    标签: bazel


    【解决方案1】:

    是的,有这样的 Make 变量。在这种特殊情况下,$< 是最方便的,因此规则声明将如下所示:

        genrule(
          name = "bar",
          srcs = ["foo.txt"],
          outs = ["bar.txt"],
          cmd = "cp $< $@",
        )
    

    $&lt;在srcs只有一个文件的情况下可以使用。如果它们更多,则考虑使用$(SRCS),它将扩展来自 srcs 的以空格分隔的输入。

    此外,还有预定义的路径替换,例如 $(execpath)$(rootpath),它们将标签扩展到它们的完整路径。所以,上面提到的 sn-p 看起来会是这样的:

        genrule(
          name = "bar",
          srcs = ["foo.txt"],
          outs = ["bar.txt"],
          cmd = "cp $(execpath foo.txt) $@",
        )
    

    还有$(location) 扩展,它是execpathrootpath 的同义词(取决于上下文),但它是遗留的,不推荐使用。

    您可以在此处查看有关在 Bazel 中生成变量的官方文档:https://docs.bazel.build/versions/2.0.0/be/make-variables.html

    【讨论】:

    • 我不能使用$(SRCS),因为我需要以不同的方式使用输入文件。抱歉应该说得更清楚。
    • “还有 $(location) 扩展,它是 execpath 或 rootpath 的同义词(取决于上下文),但它是遗留的,不推荐使用它。” - 你有这个信息的来源吗?
    • @Jin,全部来自official docs。这就是他们所说的: > locationexecpathrootpath 的同义词,具体取决于所扩展的属性。这是 Starlark 之前的遗留行为,除非您真的知道它对特定规则的作用,否则不建议这样做。详情请见#2475
    • BUILD文件的路径没有宏吗?这将使我能够cd 到正确的位置,然后原封不动地运行脚本。将其移植到 Bazel 时会方便得多。
    • 我不认为有这样的宏,但我想你可以像这样使用 smth 从路径中提取目录:$$(dirname $(SRCS)[0])