|  | // 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], BAZEL_CURRENT_REPOSITORY, &error)); | 
|  | // | 
|  | //         // Important: | 
|  | //         //   If this is a test, use | 
|  | //         //   Runfiles::CreateForTest(BAZEL_CURRENT_REPOSITORY, &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], BAZEL_CURRENT_REPOSITORY, &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. | 
|  | // | 
|  | // If source_repository is not provided, it defaults to the main repository | 
|  | // (also known as the workspace). | 
|  | static Runfiles* CreateForTest(std::string* error = nullptr); | 
|  | static Runfiles* CreateForTest(const std::string& source_repository, | 
|  | 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). | 
|  | // | 
|  | // If source_repository is not provided, it defaults to the main repository | 
|  | // (also known as the workspace). | 
|  | static Runfiles* Create(const std::string& argv0, | 
|  | std::string* error = nullptr); | 
|  | static Runfiles* Create(const std::string& argv0, | 
|  | const std::string& source_repository, | 
|  | 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); | 
|  | static Runfiles* Create(const std::string& argv0, | 
|  | const std::string& runfiles_manifest_file, | 
|  | const std::string& runfiles_dir, | 
|  | const std::string& source_repository, | 
|  | 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. | 
|  | //   source_repository: if provided, overrides the source repository set when | 
|  | //     this Runfiles instance was created. | 
|  | // 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; | 
|  | std::string Rlocation(const std::string& path, | 
|  | const std::string& source_repository) 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_; | 
|  | } | 
|  |  | 
|  | // Returns a new Runfiles instance that by default uses the provided source | 
|  | // repository as a default for all calls to Rlocation. | 
|  | // | 
|  | // The current instance remains valid. | 
|  | std::unique_ptr<Runfiles> WithSourceRepository( | 
|  | const std::string& source_repository) const { | 
|  | return std::unique_ptr<Runfiles>(new Runfiles( | 
|  | runfiles_map_, directory_, repo_mapping_, envvars_, source_repository)); | 
|  | } | 
|  |  | 
|  | private: | 
|  | Runfiles( | 
|  | std::map<std::string, std::string> runfiles_map, std::string directory, | 
|  | std::map<std::pair<std::string, std::string>, std::string> repo_mapping, | 
|  | std::vector<std::pair<std::string, std::string> > envvars, | 
|  | std::string source_repository) | 
|  | : runfiles_map_(std::move(runfiles_map)), | 
|  | directory_(std::move(directory)), | 
|  | repo_mapping_(std::move(repo_mapping)), | 
|  | envvars_(std::move(envvars)), | 
|  | source_repository_(std::move(source_repository)) {} | 
|  | Runfiles(const Runfiles&) = delete; | 
|  | Runfiles(Runfiles&&) = delete; | 
|  | Runfiles& operator=(const Runfiles&) = delete; | 
|  | Runfiles& operator=(Runfiles&&) = delete; | 
|  |  | 
|  | static std::string RlocationUnchecked( | 
|  | const std::string& path, | 
|  | const std::map<std::string, std::string>& runfiles_map, | 
|  | const std::string& directory); | 
|  |  | 
|  | const std::map<std::string, std::string> runfiles_map_; | 
|  | const std::string directory_; | 
|  | const std::map<std::pair<std::string, std::string>, std::string> | 
|  | repo_mapping_; | 
|  | const std::vector<std::pair<std::string, std::string> > envvars_; | 
|  | const std::string source_repository_; | 
|  | }; | 
|  |  | 
|  | // 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_ |