Reputation: 12245
I am trying to build a C++ application with Bazel, which requires a number of files at run-time. I use the data
attribute of the build rule to include those files in the build target:
cc_binary(
name = "myapp",
srcs = [
"main.cpp",
],
data = glob([ "media/**" ], exclude = [ "media/BUILD", "media/.keep" ]),
)
The problem is that Bazel puts the runfiles under a weird path, build-system-dependant directory (<build target name>.runfiles/__main__/<build target name>/
).
Is there any sane (or flexible, if you wish) way to refer to the runfiles other than hard-coding these paths like this
// "myapp" is the build target name
FILE* f = fopen("myapp/myapp.runfiles/__main__/myapp/media/file.txt", "r");
or reading the paths from a manifest (which still is not the better option, since each file is prefixed with __main__/<build target name>/
)?
Upvotes: 2
Views: 5462
Reputation: 12245
Looks like Bazel 0.15 added support for what is called Rlocation
, which allows looking up the runtime files in the application code:
Depend on this runfiles library from your build rule:
cc_binary(
name = "my_binary",
...
deps = ["@bazel_tools//tools/cpp/runfiles"],
)
Include the runfiles library.
#include "tools/cpp/runfiles/runfiles.h"
using bazel::tools::cpp::runfiles::Runfiles;
Create a Runfiles
object and use Rlocation
to look up runfile paths:
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");
// ...
}
Upvotes: 4
Reputation: 5006
In addition to László's answer for the design doc, there are a couple things you can try:
Use the args attribute to tell the binary where the files are. This only works if you run the binary through bazel run though, and requires that the binary understands these flags.
Create a manifest using a genrule that contains the paths of the files you want. The manifest will be at a known location so you can read that at runtime.
You can see some examples here (they're for java but should be similar for cc rules):
https://groups.google.com/d/topic/bazel-discuss/UTeGdXjO_lQ/discussion
Another option is to use something like pkg_tar
or similar rule that repackages the binary and its runfiles into whatever structure you need:
https://docs.bazel.build/versions/master/be/pkg.html (As far as I know though, pkg_tar doesn't package the runfiles for binaries.)
Upvotes: 1
Reputation: 4271
Is there any sane (or flexible, if you wish) way to refer to the runfiles other than hard-coding these paths like this
Not yet. But we're working on it.
See https://github.com/bazelbuild/bazel/issues/4460 for design doc and progress.
Upvotes: 1