Search code examples
c++bazel

Why can't my programs find resource files when using bazel run //package


I apologise if the title is a bit vague - I didn't know how else to phrase it.

I am quite new to Bazel but one thing that I don't quite understand is why my program fails to find the resource files I specify using the data attribute for the cc_binary rule

For context I am trying to follow Lazy Foo's SDL2 tutorials and I have a directory structure somewhat like this

gltuts
|
+---lazy-foo-02
|   |
|   +---media
|       |
|       +---hello_world.bmp
|
+---lazy-foo-03

Here is what my BUILD file looks like inside of the lazy-foo-02 directory

cc_binary(
name = "lazy-foo-02",
  srcs = [
    "main.cpp",
  ],
  data = glob(["media/*"]),
  deps = [
    "//subprojects:sdl2",
  ],
)

When I use the bazel run command (I use bazelisk)

bazelisk run //lazy-foo-02

I get an error saying my hello_world isn't found. I managed to find an executable in bazel-bin (well a symlink to the executable somewhere in the .cache/bazel/... directory structure.

Now the directory where the symlink is located has the media directory and when I execute from this symlink location, it works as expected.

Why would this not work using the bazel run command? Am I missing anything from the BUILD file?

I am happy to provide more information if needed.

Thanks


Solution

  • Use the C++ runfiles library to find them. Add the dependency in your BUILD file:

    cc_binary(
      name = "lazy-foo-02",
      srcs = [
        "main.cpp",
      ],
      data = glob(["media/*"]),
      deps = [
        "//subprojects:sdl2",
        "@bazel_tools//tools/cpp/runfiles",
      ],
    )
    

    and then where your code needs to find the file:

    #include <string>
    #include <memory>
    #include "tools/cpp/runfiles/runfiles.h"
    
    using bazel::tools::cpp::runfiles::Runfiles;
    
    int main(int argc, char** argv) {
      std::string error;
      std::unique_ptr<Runfiles> runfiles(
          Runfiles::Create(argv[0], &error));
    
      if (runfiles == nullptr) {
        return 1  // error handling
      }
    
      std::string path =
          runfiles->Rlocation("gltuts/lazy-foo-02/media/hello_world.bmp");
    }
    

    See the header file for API docs and some notes on how to handle child processes, accessing them without argv[0], etc. @bazel_tools is a special repository name which is automatically provided by bazel itself, so no need for any WORKSPACE changes.