我正在尝试使用 Bazel 构建一个 C++ 应用程序,它在运行时需要大量文件。我使用构建规则的 data
属性将这些文件包含在构建目标中:
cc_binary(
name = "myapp",
srcs = [
"main.cpp",
],
data = glob([ "media/**" ], exclude = [ "media/BUILD", "media/.keep" ]),
)
问题是 Bazel 将运行文件放在一个奇怪的路径下,即依赖于构建系统的目录 ( <build target name>.runfiles/__main__/<build target name>/
(。
除了像这样硬编码这些路径之外,是否有任何理智(或灵活,如果您愿意(的方式来引用运行文件
// "myapp" is the build target name
FILE* f = fopen("myapp/myapp.runfiles/__main__/myapp/media/file.txt", "r");
或者从清单中读取路径(这仍然不是更好的选择,因为每个文件都以 __main__/<build target name>/
为前缀(?
看起来 Bazel 0.15 增加了对所谓的 Rlocation
的支持,它允许通过在代码中添加 在代码中使用此类来循环运行时文件:
-
依赖于生成规则中的此运行文件库:
cc_binary( name = "my_binary", ... deps = ["@bazel_tools//tools/cpp/runfiles"], )
-
包括运行文件库。
#include "tools/cpp/runfiles/runfiles.h" using bazel::tools::cpp::runfiles::Runfiles;
-
创建一个
Runfiles
对象并使用Rlocation
查找运行文件路径:int main(int argc, char** argv) { std::string error; std::unique_ptr<Runfiles> runfiles(Runfiles::Create(argv[0], &error)); // Important: // If this is a test, use Runfiles::CreateForTest(&error). // Otherwise, if you don't have the value for argv[0] for whatever // reason, then use Runfiles::Create(&error). if (runfiles == nullptr) { // error handling } std::string path = runfiles->Rlocation("my_workspace/path/to/my/data.txt"); // ... }
除了像这样硬编码这些路径之外,是否有任何理智(或灵活,如果您愿意(的方式来引用运行文件
还没有。但我们正在努力。
有关设计文档和进度,请参阅 https://github.com/bazelbuild/bazel/issues/4460。
除了László对设计文档的回答之外,您还可以尝试以下几件事:
-
使用 args 属性告诉二进制文件的位置。这仅在通过 bazel run 运行二进制文件时才有效,并且要求二进制文件理解这些标志。
-
使用包含所需文件路径的 genrule 创建清单。清单将位于已知位置,以便您可以在运行时读取该位置。
你可以在这里看到一些例子(它们适用于java,但对于cc规则应该类似(:
https://groups.google.com/d/topic/bazel-discuss/UTeGdXjO_lQ/discussion
另一种选择是使用类似pkg_tar
或类似规则的内容,将二进制文件及其运行文件重新打包为所需的任何结构:https://docs.bazel.build/versions/master/be/pkg.html(据我所知,pkg_tar不会打包二进制文件的运行文件。