shybovycha
shybovycha

Reputation: 12245

Access runtime files in application built with Bazel

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

Answers (3)

shybovycha
shybovycha

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:

  1. Depend on this runfiles library from your build rule:

    cc_binary(
      name = "my_binary",
      ...
      deps = ["@bazel_tools//tools/cpp/runfiles"],
    )
    
  2. Include the runfiles library.

    #include "tools/cpp/runfiles/runfiles.h"
    using bazel::tools::cpp::runfiles::Runfiles;
    
  3. 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

ahumesky
ahumesky

Reputation: 5006

In addition to László's answer for the design doc, there are a couple things you can try:

  1. 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.

  2. 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

L&#225;szl&#243;
L&#225;szl&#243;

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

Related Questions