| // Copyright 2018 The Bazel Authors. All rights reserved. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| // Runfiles lookup library for Bazel-built C++ binaries and tests. | |
| // | |
| // USAGE: | |
| // 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"); | |
| // ... | |
| // | |
| // The code above creates a Runfiles object and retrieves a runfile path. | |
| // | |
| // The Runfiles::Create function uses the runfiles manifest and the | |
| // runfiles directory from the RUNFILES_MANIFEST_FILE and RUNFILES_DIR | |
| // environment variables. If not present, the function looks for the | |
| // manifest and directory near argv[0], the path of the main program. | |
| // | |
| // To start child processes that also need runfiles, you need to set the right | |
| // environment variables for them: | |
| // | |
| // std::unique_ptr<Runfiles> runfiles(Runfiles::Create(argv[0], &error)); | |
| // | |
| // std::string path = runfiles->Rlocation("path/to/binary")); | |
| // if (!path.empty()) { | |
| // ... // create "args" argument vector for execv | |
| // const auto envvars = runfiles->EnvVars(); | |
| // pid_t child = fork(); | |
| // if (child) { | |
| // int status; | |
| // waitpid(child, &status, 0); | |
| // } else { | |
| // for (const auto i : envvars) { | |
| // setenv(i.first.c_str(), i.second.c_str(), 1); | |
| // } | |
| // execv(args[0], args); | |
| // } | |
| #ifndef TOOLS_CPP_RUNFILES_RUNFILES_H_ | |
| #define TOOLS_CPP_RUNFILES_RUNFILES_H_ 1 | |
| #include <functional> | |
| #include <map> | |
| #include <memory> | |
| #include <string> | |
| #include <vector> | |
| namespace bazel { | |
| namespace tools { | |
| namespace cpp { | |
| namespace runfiles { | |
| class Runfiles { | |
| public: | |
| virtual ~Runfiles() {} | |
| // Returns a new `Runfiles` instance. | |
| // | |
| // Use this from within `cc_test` rules. | |
| // | |
| // Returns nullptr on error. If `error` is provided, the method prints an | |
| // error message into it. | |
| // | |
| // This method looks at the RUNFILES_MANIFEST_FILE and TEST_SRCDIR | |
| // environment variables. | |
| static Runfiles* CreateForTest(std::string* error = nullptr); | |
| // Returns a new `Runfiles` instance. | |
| // | |
| // Use this from `cc_binary` or `cc_library` rules. You may pass an empty | |
| // `argv0` if `argv[0]` from the `main` method is unknown. | |
| // | |
| // Returns nullptr on error. If `error` is provided, the method prints an | |
| // error message into it. | |
| // | |
| // This method looks at the RUNFILES_MANIFEST_FILE and RUNFILES_DIR | |
| // environment variables. If either is empty, the method looks for the | |
| // manifest or directory using the other environment variable, or using argv0 | |
| // (unless it's empty). | |
| static Runfiles* Create(const std::string& argv0, | |
| std::string* error = nullptr); | |
| // Returns a new `Runfiles` instance. | |
| // | |
| // Use this from any `cc_*` rule if you want to manually specify the paths to | |
| // the runfiles manifest and/or runfiles directory. You may pass an empty | |
| // `argv0` if `argv[0]` from the `main` method is unknown. | |
| // | |
| // This method is the same as `Create(argv0, error)`, except it uses | |
| // `runfiles_manifest_file` and `runfiles_dir` as the corresponding | |
| // environment variable values, instead of looking up the actual environment | |
| // variables. | |
| static Runfiles* Create(const std::string& argv0, | |
| const std::string& runfiles_manifest_file, | |
| const std::string& runfiles_dir, | |
| std::string* error = nullptr); | |
| // Returns the runtime path of a runfile. | |
| // | |
| // Runfiles are data-dependencies of Bazel-built binaries and tests. | |
| // | |
| // The returned path may not exist. The caller should verify the path's | |
| // existence. | |
| // | |
| // The function may return an empty string if it cannot find a runfile. | |
| // | |
| // Args: | |
| // path: runfiles-root-relative path of the runfile; must not be empty and | |
| // must not contain uplevel references. | |
| // Returns: | |
| // the path to the runfile, which the caller should check for existence, or | |
| // an empty string if the method doesn't know about this runfile | |
| std::string Rlocation(const std::string& path) const; | |
| // Returns environment variables for subprocesses. | |
| // | |
| // The caller should set the returned key-value pairs in the environment of | |
| // subprocesses, so that those subprocesses can also access runfiles (in case | |
| // they are also Bazel-built binaries). | |
| const std::vector<std::pair<std::string, std::string> >& EnvVars() const { | |
| return envvars_; | |
| } | |
| private: | |
| Runfiles(const std::map<std::string, std::string>&& runfiles_map, | |
| const std::string&& directory, | |
| const std::vector<std::pair<std::string, std::string> >&& envvars) | |
| : runfiles_map_(std::move(runfiles_map)), | |
| directory_(std::move(directory)), | |
| envvars_(std::move(envvars)) {} | |
| Runfiles(const Runfiles&) = delete; | |
| Runfiles(Runfiles&&) = delete; | |
| Runfiles& operator=(const Runfiles&) = delete; | |
| Runfiles& operator=(Runfiles&&) = delete; | |
| const std::map<std::string, std::string> runfiles_map_; | |
| const std::string directory_; | |
| const std::vector<std::pair<std::string, std::string> > envvars_; | |
| }; | |
| // The "testing" namespace contains functions that allow unit testing the code. | |
| // Do not use these outside of runfiles_test.cc, they are only part of the | |
| // public API for the benefit of the tests. | |
| // These functions and their interface may change without notice. | |
| namespace testing { | |
| // For testing only. | |
| // | |
| // Computes the path of the runfiles manifest and the runfiles directory. | |
| // | |
| // If the method finds both a valid manifest and valid directory according to | |
| // `is_runfiles_manifest` and `is_runfiles_directory`, then the method sets | |
| // the corresponding values to `out_manifest` and `out_directory` and returns | |
| // true. | |
| // | |
| // If the method only finds a valid manifest or a valid directory, but not | |
| // both, then it sets the corresponding output variable (`out_manifest` or | |
| // `out_directory`) to the value while clearing the other output variable. The | |
| // method still returns true in this case. | |
| // | |
| // If the method cannot find either a valid manifest or valid directory, it | |
| // clears both output variables and returns false. | |
| bool TestOnly_PathsFrom( | |
| const std::string& argv0, std::string runfiles_manifest_file, | |
| std::string runfiles_dir, | |
| std::function<bool(const std::string&)> is_runfiles_manifest, | |
| std::function<bool(const std::string&)> is_runfiles_directory, | |
| std::string* out_manifest, std::string* out_directory); | |
| // For testing only. | |
| // Returns true if `path` is an absolute Unix or Windows path. | |
| // For Windows paths, this function does not regard drive-less absolute paths | |
| // (i.e. absolute-on-current-drive, e.g. "\foo\bar") as absolute and returns | |
| // false for these. | |
| bool TestOnly_IsAbsolute(const std::string& path); | |
| } // namespace testing | |
| } // namespace runfiles | |
| } // namespace cpp | |
| } // namespace tools | |
| } // namespace bazel | |
| #endif // TOOLS_CPP_RUNFILES_RUNFILES_H_ |