Laszlo Csomor | 9dfb1ee | 2018-02-26 09:17:02 -0800 | [diff] [blame] | 1 | // Copyright 2018 The Bazel Authors. All rights reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | // Runfiles lookup library for Bazel-built C++ binaries and tests. |
| 16 | // |
Laszlo Csomor | 44646c2 | 2018-06-27 05:09:38 -0700 | [diff] [blame] | 17 | // USAGE: |
| 18 | // 1. Depend on this runfiles library from your build rule: |
Laszlo Csomor | 1d69870 | 2018-03-19 02:14:33 -0700 | [diff] [blame] | 19 | // |
Laszlo Csomor | 44646c2 | 2018-06-27 05:09:38 -0700 | [diff] [blame] | 20 | // cc_binary( |
| 21 | // name = "my_binary", |
| 22 | // ... |
| 23 | // deps = ["@bazel_tools//tools/cpp/runfiles"], |
| 24 | // ) |
Laszlo Csomor | 819bf38 | 2018-04-30 03:29:21 -0700 | [diff] [blame] | 25 | // |
Laszlo Csomor | 44646c2 | 2018-06-27 05:09:38 -0700 | [diff] [blame] | 26 | // 2. Include the runfiles library. |
Laszlo Csomor | 1d69870 | 2018-03-19 02:14:33 -0700 | [diff] [blame] | 27 | // |
Laszlo Csomor | 44646c2 | 2018-06-27 05:09:38 -0700 | [diff] [blame] | 28 | // #include "tools/cpp/runfiles/runfiles.h" |
Laszlo Csomor | 1d69870 | 2018-03-19 02:14:33 -0700 | [diff] [blame] | 29 | // |
Laszlo Csomor | 44646c2 | 2018-06-27 05:09:38 -0700 | [diff] [blame] | 30 | // using bazel::tools::cpp::runfiles::Runfiles; |
Laszlo Csomor | 1d69870 | 2018-03-19 02:14:33 -0700 | [diff] [blame] | 31 | // |
Laszlo Csomor | 44646c2 | 2018-06-27 05:09:38 -0700 | [diff] [blame] | 32 | // 3. Create a Runfiles object and use rlocation to look up runfile paths: |
| 33 | // |
| 34 | // int main(int argc, char** argv) { |
| 35 | // std::string error; |
Laszlo Csomor | 131e31c | 2018-08-30 02:55:14 -0700 | [diff] [blame] | 36 | // std::unique_ptr<Runfiles> runfiles( |
| 37 | // Runfiles::Create(argv[0], &error)); |
Laszlo Csomor | 23bc3be | 2018-09-28 01:20:32 -0700 | [diff] [blame] | 38 | // |
| 39 | // // Important: |
| 40 | // // If this is a test, use Runfiles::CreateForTest(&error). |
| 41 | // // Otherwise, if you don't have the value for argv[0] for whatever |
| 42 | // // reason, then use Runfiles::Create(&error). |
| 43 | // |
Laszlo Csomor | 131e31c | 2018-08-30 02:55:14 -0700 | [diff] [blame] | 44 | // if (runfiles == nullptr) { |
Laszlo Csomor | 44646c2 | 2018-06-27 05:09:38 -0700 | [diff] [blame] | 45 | // ... // error handling |
| 46 | // } |
| 47 | // std::string path = |
Laszlo Csomor | 131e31c | 2018-08-30 02:55:14 -0700 | [diff] [blame] | 48 | // runfiles->Rlocation("my_workspace/path/to/my/data.txt"); |
Laszlo Csomor | 44646c2 | 2018-06-27 05:09:38 -0700 | [diff] [blame] | 49 | // ... |
| 50 | // |
| 51 | // The code above creates a Runfiles object and retrieves a runfile path. |
| 52 | // |
| 53 | // The Runfiles::Create function uses the runfiles manifest and the |
| 54 | // runfiles directory from the RUNFILES_MANIFEST_FILE and RUNFILES_DIR |
| 55 | // environment variables. If not present, the function looks for the |
| 56 | // manifest and directory near argv[0], the path of the main program. |
Laszlo Csomor | 72075bf | 2018-05-24 02:59:54 -0700 | [diff] [blame] | 57 | // |
| 58 | // To start child processes that also need runfiles, you need to set the right |
| 59 | // environment variables for them: |
Laszlo Csomor | 1d69870 | 2018-03-19 02:14:33 -0700 | [diff] [blame] | 60 | // |
Laszlo Csomor | 819bf38 | 2018-04-30 03:29:21 -0700 | [diff] [blame] | 61 | // std::unique_ptr<Runfiles> runfiles(Runfiles::Create(argv[0], &error)); |
Laszlo Csomor | 1d69870 | 2018-03-19 02:14:33 -0700 | [diff] [blame] | 62 | // |
Laszlo Csomor | 72075bf | 2018-05-24 02:59:54 -0700 | [diff] [blame] | 63 | // std::string path = runfiles->Rlocation("path/to/binary")); |
Laszlo Csomor | 1d69870 | 2018-03-19 02:14:33 -0700 | [diff] [blame] | 64 | // if (!path.empty()) { |
Laszlo Csomor | 22f4bb9 | 2018-05-30 02:47:38 -0700 | [diff] [blame] | 65 | // ... // create "args" argument vector for execv |
| 66 | // const auto envvars = runfiles->EnvVars(); |
Laszlo Csomor | 1d69870 | 2018-03-19 02:14:33 -0700 | [diff] [blame] | 67 | // pid_t child = fork(); |
Laszlo Csomor | 22f4bb9 | 2018-05-30 02:47:38 -0700 | [diff] [blame] | 68 | // if (child) { |
| 69 | // int status; |
| 70 | // waitpid(child, &status, 0); |
| 71 | // } else { |
| 72 | // for (const auto i : envvars) { |
| 73 | // setenv(i.first.c_str(), i.second.c_str(), 1); |
| 74 | // } |
| 75 | // execv(args[0], args); |
| 76 | // } |
Laszlo Csomor | 9dfb1ee | 2018-02-26 09:17:02 -0800 | [diff] [blame] | 77 | |
Laszlo Csomor | 819bf38 | 2018-04-30 03:29:21 -0700 | [diff] [blame] | 78 | #ifndef TOOLS_CPP_RUNFILES_RUNFILES_H_ |
| 79 | #define TOOLS_CPP_RUNFILES_RUNFILES_H_ 1 |
Laszlo Csomor | 9dfb1ee | 2018-02-26 09:17:02 -0800 | [diff] [blame] | 80 | |
Laszlo Csomor | 1d69870 | 2018-03-19 02:14:33 -0700 | [diff] [blame] | 81 | #include <functional> |
Laszlo Csomor | 72075bf | 2018-05-24 02:59:54 -0700 | [diff] [blame] | 82 | #include <map> |
Laszlo Csomor | 3bcad50 | 2018-03-05 06:35:20 -0800 | [diff] [blame] | 83 | #include <memory> |
Laszlo Csomor | 9dfb1ee | 2018-02-26 09:17:02 -0800 | [diff] [blame] | 84 | #include <string> |
Laszlo Csomor | 3bcad50 | 2018-03-05 06:35:20 -0800 | [diff] [blame] | 85 | #include <vector> |
Laszlo Csomor | 9dfb1ee | 2018-02-26 09:17:02 -0800 | [diff] [blame] | 86 | |
| 87 | namespace bazel { |
Laszlo Csomor | 819bf38 | 2018-04-30 03:29:21 -0700 | [diff] [blame] | 88 | namespace tools { |
| 89 | namespace cpp { |
Laszlo Csomor | 9dfb1ee | 2018-02-26 09:17:02 -0800 | [diff] [blame] | 90 | namespace runfiles { |
| 91 | |
| 92 | class Runfiles { |
| 93 | public: |
| 94 | virtual ~Runfiles() {} |
| 95 | |
Laszlo Csomor | 1d69870 | 2018-03-19 02:14:33 -0700 | [diff] [blame] | 96 | // Returns a new `Runfiles` instance. |
| 97 | // |
Laszlo Csomor | 23bc3be | 2018-09-28 01:20:32 -0700 | [diff] [blame] | 98 | // Use this from within `cc_test` rules. |
| 99 | // |
| 100 | // Returns nullptr on error. If `error` is provided, the method prints an |
| 101 | // error message into it. |
| 102 | // |
| 103 | // This method looks at the RUNFILES_MANIFEST_FILE and TEST_SRCDIR |
| 104 | // environment variables. |
| 105 | static Runfiles* CreateForTest(std::string* error = nullptr); |
| 106 | |
| 107 | // Returns a new `Runfiles` instance. |
| 108 | // |
| 109 | // Use this from `cc_binary` or `cc_library` rules. You may pass an empty |
| 110 | // `argv0` if `argv[0]` from the `main` method is unknown. |
| 111 | // |
Laszlo Csomor | 1d69870 | 2018-03-19 02:14:33 -0700 | [diff] [blame] | 112 | // Returns nullptr on error. If `error` is provided, the method prints an |
| 113 | // error message into it. |
Laszlo Csomor | 72075bf | 2018-05-24 02:59:54 -0700 | [diff] [blame] | 114 | // |
| 115 | // This method looks at the RUNFILES_MANIFEST_FILE and RUNFILES_DIR |
| 116 | // environment variables. If either is empty, the method looks for the |
Laszlo Csomor | 23bc3be | 2018-09-28 01:20:32 -0700 | [diff] [blame] | 117 | // manifest or directory using the other environment variable, or using argv0 |
| 118 | // (unless it's empty). |
Laszlo Csomor | 1d69870 | 2018-03-19 02:14:33 -0700 | [diff] [blame] | 119 | static Runfiles* Create(const std::string& argv0, |
| 120 | std::string* error = nullptr); |
| 121 | |
Laszlo Csomor | 72075bf | 2018-05-24 02:59:54 -0700 | [diff] [blame] | 122 | // Returns a new `Runfiles` instance. |
| 123 | // |
Laszlo Csomor | 23bc3be | 2018-09-28 01:20:32 -0700 | [diff] [blame] | 124 | // Use this from any `cc_*` rule if you want to manually specify the paths to |
| 125 | // the runfiles manifest and/or runfiles directory. You may pass an empty |
| 126 | // `argv0` if `argv[0]` from the `main` method is unknown. |
| 127 | // |
| 128 | // This method is the same as `Create(argv0, error)`, except it uses |
| 129 | // `runfiles_manifest_file` and `runfiles_dir` as the corresponding |
| 130 | // environment variable values, instead of looking up the actual environment |
| 131 | // variables. |
Laszlo Csomor | 72075bf | 2018-05-24 02:59:54 -0700 | [diff] [blame] | 132 | static Runfiles* Create(const std::string& argv0, |
| 133 | const std::string& runfiles_manifest_file, |
| 134 | const std::string& runfiles_dir, |
| 135 | std::string* error = nullptr); |
| 136 | |
Laszlo Csomor | 9dfb1ee | 2018-02-26 09:17:02 -0800 | [diff] [blame] | 137 | // Returns the runtime path of a runfile. |
| 138 | // |
| 139 | // Runfiles are data-dependencies of Bazel-built binaries and tests. |
| 140 | // |
Laszlo Csomor | 72075bf | 2018-05-24 02:59:54 -0700 | [diff] [blame] | 141 | // The returned path may not exist. The caller should verify the path's |
| 142 | // existence. |
Laszlo Csomor | 9dfb1ee | 2018-02-26 09:17:02 -0800 | [diff] [blame] | 143 | // |
Laszlo Csomor | 72075bf | 2018-05-24 02:59:54 -0700 | [diff] [blame] | 144 | // The function may return an empty string if it cannot find a runfile. |
Laszlo Csomor | 9dfb1ee | 2018-02-26 09:17:02 -0800 | [diff] [blame] | 145 | // |
| 146 | // Args: |
| 147 | // path: runfiles-root-relative path of the runfile; must not be empty and |
| 148 | // must not contain uplevel references. |
| 149 | // Returns: |
| 150 | // the path to the runfile, which the caller should check for existence, or |
| 151 | // an empty string if the method doesn't know about this runfile |
Laszlo Csomor | 72075bf | 2018-05-24 02:59:54 -0700 | [diff] [blame] | 152 | std::string Rlocation(const std::string& path) const; |
Laszlo Csomor | 9dfb1ee | 2018-02-26 09:17:02 -0800 | [diff] [blame] | 153 | |
Laszlo Csomor | 3bcad50 | 2018-03-05 06:35:20 -0800 | [diff] [blame] | 154 | // Returns environment variables for subprocesses. |
| 155 | // |
| 156 | // The caller should set the returned key-value pairs in the environment of |
Laszlo Csomor | 72075bf | 2018-05-24 02:59:54 -0700 | [diff] [blame] | 157 | // subprocesses, so that those subprocesses can also access runfiles (in case |
| 158 | // they are also Bazel-built binaries). |
| 159 | const std::vector<std::pair<std::string, std::string> >& EnvVars() const { |
| 160 | return envvars_; |
| 161 | } |
Laszlo Csomor | 9dfb1ee | 2018-02-26 09:17:02 -0800 | [diff] [blame] | 162 | |
| 163 | private: |
Laszlo Csomor | 72075bf | 2018-05-24 02:59:54 -0700 | [diff] [blame] | 164 | Runfiles(const std::map<std::string, std::string>&& runfiles_map, |
| 165 | const std::string&& directory, |
| 166 | const std::vector<std::pair<std::string, std::string> >&& envvars) |
| 167 | : runfiles_map_(std::move(runfiles_map)), |
| 168 | directory_(std::move(directory)), |
| 169 | envvars_(std::move(envvars)) {} |
Laszlo Csomor | 9dfb1ee | 2018-02-26 09:17:02 -0800 | [diff] [blame] | 170 | Runfiles(const Runfiles&) = delete; |
| 171 | Runfiles(Runfiles&&) = delete; |
| 172 | Runfiles& operator=(const Runfiles&) = delete; |
| 173 | Runfiles& operator=(Runfiles&&) = delete; |
Laszlo Csomor | 72075bf | 2018-05-24 02:59:54 -0700 | [diff] [blame] | 174 | |
| 175 | const std::map<std::string, std::string> runfiles_map_; |
| 176 | const std::string directory_; |
| 177 | const std::vector<std::pair<std::string, std::string> > envvars_; |
Laszlo Csomor | 9dfb1ee | 2018-02-26 09:17:02 -0800 | [diff] [blame] | 178 | }; |
| 179 | |
| 180 | // The "testing" namespace contains functions that allow unit testing the code. |
Laszlo Csomor | 3bcad50 | 2018-03-05 06:35:20 -0800 | [diff] [blame] | 181 | // Do not use these outside of runfiles_test.cc, they are only part of the |
| 182 | // public API for the benefit of the tests. |
| 183 | // These functions and their interface may change without notice. |
Laszlo Csomor | 9dfb1ee | 2018-02-26 09:17:02 -0800 | [diff] [blame] | 184 | namespace testing { |
| 185 | |
| 186 | // For testing only. |
Laszlo Csomor | 1d69870 | 2018-03-19 02:14:33 -0700 | [diff] [blame] | 187 | // |
Laszlo Csomor | 72075bf | 2018-05-24 02:59:54 -0700 | [diff] [blame] | 188 | // Computes the path of the runfiles manifest and the runfiles directory. |
Laszlo Csomor | 1d69870 | 2018-03-19 02:14:33 -0700 | [diff] [blame] | 189 | // |
Laszlo Csomor | 72075bf | 2018-05-24 02:59:54 -0700 | [diff] [blame] | 190 | // If the method finds both a valid manifest and valid directory according to |
| 191 | // `is_runfiles_manifest` and `is_runfiles_directory`, then the method sets |
| 192 | // the corresponding values to `out_manifest` and `out_directory` and returns |
| 193 | // true. |
| 194 | // |
| 195 | // If the method only finds a valid manifest or a valid directory, but not |
| 196 | // both, then it sets the corresponding output variable (`out_manifest` or |
| 197 | // `out_directory`) to the value while clearing the other output variable. The |
| 198 | // method still returns true in this case. |
| 199 | // |
| 200 | // If the method cannot find either a valid manifest or valid directory, it |
| 201 | // clears both output variables and returns false. |
| 202 | bool TestOnly_PathsFrom( |
| 203 | const std::string& argv0, std::string runfiles_manifest_file, |
| 204 | std::string runfiles_dir, |
| 205 | std::function<bool(const std::string&)> is_runfiles_manifest, |
| 206 | std::function<bool(const std::string&)> is_runfiles_directory, |
| 207 | std::string* out_manifest, std::string* out_directory); |
Laszlo Csomor | 1d69870 | 2018-03-19 02:14:33 -0700 | [diff] [blame] | 208 | |
| 209 | // For testing only. |
Laszlo Csomor | 9dfb1ee | 2018-02-26 09:17:02 -0800 | [diff] [blame] | 210 | // Returns true if `path` is an absolute Unix or Windows path. |
| 211 | // For Windows paths, this function does not regard drive-less absolute paths |
| 212 | // (i.e. absolute-on-current-drive, e.g. "\foo\bar") as absolute and returns |
| 213 | // false for these. |
| 214 | bool TestOnly_IsAbsolute(const std::string& path); |
| 215 | |
| 216 | } // namespace testing |
| 217 | } // namespace runfiles |
Laszlo Csomor | 819bf38 | 2018-04-30 03:29:21 -0700 | [diff] [blame] | 218 | } // namespace cpp |
| 219 | } // namespace tools |
Laszlo Csomor | 9dfb1ee | 2018-02-26 09:17:02 -0800 | [diff] [blame] | 220 | } // namespace bazel |
| 221 | |
Laszlo Csomor | 819bf38 | 2018-04-30 03:29:21 -0700 | [diff] [blame] | 222 | #endif // TOOLS_CPP_RUNFILES_RUNFILES_H_ |