C++使用Bazel构建的项目及数据仓库

8

我有一个(基础的)C++项目:

├── bin
│   ├── BUILD
│   ├── example.cpp
├── data
│   └── someData.txt
└── WORKSPACE

可执行文件 example.cpp 使用了来自 data/ 目录的一些数据文件:

#include <fstream>
#include <iostream>

int main()
{
  std::ifstream in("data/someData.txt");

  if (!in)
  {
    std::cerr << "Can not open file!";
    return EXIT_FAILURE;
  }

  std::string message;

  if (!(in >> message))
  {
    std::cerr << "Can not read file content!";
    return EXIT_FAILURE;
  }

  std::cout << message << std::endl;

  return EXIT_SUCCESS;
}

我的Bazel设置是最小的:

  • WORKSPACE:空文件
  • bin/BUILDcc_binary(name = "example",srcs = ["example.cpp"])
  • data/someData.txt:包含Hello_world!

问题在于,Bazel将所有这些文件移动到特殊位置:

.
├── bazel-Bazel_with_Data -> ...
├── bazel-bin -> ...
├── bazel-genfiles -> ...
├── bazel-out -> ...
├── bazel-testlogs -> ...

特别是,示例可执行文件找不到data/someData.txt文件:

bazel run bin:example

将打印:

INFO: Analysed target //bin:example (0 packages loaded).
INFO: Found 1 target...
Target //bin:example up-to-date:
  bazel-bin/bin/example
INFO: Elapsed time: 0.101s, Critical Path: 0.00s
INFO: Build completed successfully, 1 total action

INFO: Running command line: bazel-bin/bin/example
Can not open file!ERROR: Non-zero return code '1' from command: Process exited with status 1

问题是如何进行管理?

我希望示例可执行文件能够找到Data/someData.txt文件。

3个回答

7

注意:根据评论,这种解决方案似乎在Windows下无效。

必须在data目录中创建一个额外的BUILD文件,定义必须导出哪些数据文件。项目结构现在如下:

├── bin
│   ├── BUILD
│   ├── example.cpp
├── data
│   ├── BUILD
│   └── someData.txt
└── WORKSPACE

这个新的data/BUILD文件是:

exports_files(["someData.txt"])

bin/BUILD 文件被修改以添加 someData.txt 依赖项:

cc_binary(
    name = "example",
    srcs = ["example.cpp"],
    data = ["//data:someData.txt"],
)

现在,如果你运行以下命令:
bazel run bin:example

你应该获得:

INFO: Analysed target //bin:example (2 packages loaded).
INFO: Found 1 target...
Target //bin:example up-to-date:
  bazel-bin/bin/example
INFO: Elapsed time: 0.144s, Critical Path: 0.01s
INFO: Build completed successfully, 3 total actions

INFO: Running command line: bazel-bin/bin/example
Hello_world!

这意味着示例可执行文件找到了data/someData.txt文件并打印了其内容。

还要注意,您可以使用相同的方案进行单元测试

 cc_test(...,data =["//data:someData.txt"], )

您可以从这个GitHub仓库中复制此笔记。

你刚刚尝试在Windows上使用bazel run来运行你从GitHub repo下载的示例了吗?如果你尝试了,那么在 https://github.com/vincent-picaud/Bazel_with_Data/blob/master/bin/example.cpp#L6 中打开的stream将会失败。但是在Linux中使用bazel来运行你的项目可以正常工作。 - thinlizzy
@thinlizzy 感谢您的反馈。我还没有在Windows下测试过它。如果它不能正常工作,我会更新我的帖子。 - Picaud Vincent
@thinlizzy 可能是路径"data/someData.txt"的问题。我认为Windows期望的是"data\someData.txt"。你试过了吗?(我无法访问Windows,只在Linux下运行) - Picaud Vincent
2
那肯定不是原因。我为了让这些文件通过bazel运行在Windows上打开,使用了一个丑陋的解决方法,就是在文件路径前添加"../../../../../../"。 :( - thinlizzy
@thinlizzy 很抱歉听到这个消息,我会在我的帖子中添加一条评论。我无法在Windows下调查问题。谢谢。 - Picaud Vincent
2
据我所见,这个解决方案只适用于每个特定文件,但当规则更通用时,exports_files(glob(['**'])) - 如何引用整个组?留下路径解析,因为这对程序来说只是黑魔法 =( - shybovycha

3

在Windows上尝试:

bazel run --enable_runfiles

更多详细信息请参见这里

你也可以将此添加到.bazelrc文件中:

build:myconfig --enable_runfiles

在 Windows 上进行构建的方法:

bazel build --config=myconfig //...

此外,runfile库也是一种选择。


0

我把这个问题发布到了 Bazel issues 上。建议使用 Runfiles 从相对路径中提取绝对路径,然后您应该能够将路径插入到 ifstream 中。需要注意的是,您的相对路径需要以 \__main__ 开头。

std::unique_ptr<Runfiles> runfiles(Runfiles::Create(argv[0], &error));
std::string path = runfiles->Rlocation("__main__/relative_path");
std::ifstream in(path);

请参阅文档,了解有关运行文件使用的信息。

GitHub问题在这里


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接