c++,runfiles: move runfiles library

Move the half-done C++ runfiles library to
`//tools/cpp/runfiles`. (The Python and
Bash runfiles libraries are already under
`//tools/<language>/runfiles`.)

See https://github.com/bazelbuild/bazel/issues/4460

Change-Id: I1006f7f81462ea0e4b1de1adcdba89e386d4f9e7

Closes #5107.

Change-Id: I1006f7f81462ea0e4b1de1adcdba89e386d4f9e7
PiperOrigin-RevId: 194763392
diff --git a/tools/cpp/runfiles/runfiles.h b/tools/cpp/runfiles/runfiles.h
new file mode 100644
index 0000000..2fad6df
--- /dev/null
+++ b/tools/cpp/runfiles/runfiles.h
@@ -0,0 +1,185 @@
+// 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:
+//
+//   #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) {
+//       ...  // error handling
+//     }
+//     std::string path(runfiles->Rlocation("io_bazel/src/bazel"));
+//     std::ifstream data(path);
+//     if (data.is_open()) {
+//       ...  // use the runfile
+//
+// The code above creates a manifest- or directory-based implementations
+// depending on it finding a runfiles manifest or -directory near argv[0] or
+// finding appropriate environment variables that tell it where to find the
+// manifest or directory. See `Runfiles::Create` for more info.
+//
+// If you want to explicitly create a manifest- or directory-based
+// implementation, you can do so as follows:
+//
+//   std::unique_ptr<Runfiles> runfiles1(
+//       Runfiles::CreateManifestBased(path/to/foo.runfiles/MANIFEST", &error));
+//
+//   std::unique_ptr<Runfiles> runfiles2(
+//       Runfiles::CreateDirectoryBased(path/to/foo.runfiles", &error));
+//
+// If you want 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));
+//
+//   for (const auto i : runfiles->EnvVars()) {
+//     setenv(i.first, i.second, 1);
+//   }
+//   std::string path(runfiles->Rlocation("path/to/binary"));
+//   if (!path.empty()) {
+//     pid_t child = fork();
+//     ...
+
+#ifndef TOOLS_CPP_RUNFILES_RUNFILES_H_
+#define TOOLS_CPP_RUNFILES_RUNFILES_H_ 1
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace bazel {
+namespace tools {
+namespace cpp {
+namespace runfiles {
+
+class Runfiles {
+ public:
+  virtual ~Runfiles() {}
+
+  // Returns a new `Runfiles` instance.
+  //
+  // The returned object is either:
+  // - manifest-based, meaning it looks up runfile paths from a manifest file,
+  //   or
+  // - directory-based, meaning it looks up runfile paths under a given
+  //   directory path
+  //
+  // This method:
+  // 1. checks the RUNFILES_MANIFEST_FILE or RUNFILES_DIR environment variables;
+  //    if either is non-empty, returns a manifest- or directory-based Runfiles
+  //    object; otherwise
+  // 2. checks if there's a runfiles manifest (argv0 + ".runfiles_manifest") or
+  //    runfiles directory (argv0 + ".runfiles") next to this binary; if so,
+  //    returns a manifest- or directory-based Runfiles object; otherwise
+  // 3. returns nullptr.
+  //
+  // The manifest-based Runfiles object eagerly reads and caches the whole
+  // manifest file upon instantiation; this may be relevant for performance
+  // consideration.
+  //
+  // Returns nullptr on error. If `error` is provided, the method prints an
+  // error message into it.
+  static Runfiles* Create(const std::string& argv0,
+                          std::string* error = nullptr);
+
+  // Returns a new manifest-based `Runfiles` instance.
+  // Returns nullptr on error. If `error` is provided, the method prints an
+  // error message into it.
+  static Runfiles* CreateManifestBased(const std::string& manifest_path,
+                                       std::string* error = nullptr);
+
+  // Returns a new directory-based `Runfiles` instance.
+  // Returns nullptr on error. If `error` is provided, the method prints an
+  // error message into it.
+  static Runfiles* CreateDirectoryBased(const std::string& directory_path,
+                                        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 be valid. The caller should check the path's
+  // validity and that the path exists.
+  //
+  // The function may return an empty string. In that case the caller can be
+  // sure that the Runfiles object does not know about this data-dependency.
+  //
+  // 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
+  virtual std::string Rlocation(const std::string& path) const = 0;
+
+  // Returns environment variables for subprocesses.
+  //
+  // The caller should set the returned key-value pairs in the environment of
+  // subprocesses in case those subprocesses are also Bazel-built binaries that
+  // need to use runfiles.
+  virtual std::vector<std::pair<std::string, std::string> > EnvVars() const = 0;
+
+ protected:
+  Runfiles() {}
+
+ private:
+  Runfiles(const Runfiles&) = delete;
+  Runfiles(Runfiles&&) = delete;
+  Runfiles& operator=(const Runfiles&) = delete;
+  Runfiles& operator=(Runfiles&&) = delete;
+};
+
+// 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.
+//
+// Create a new Runfiles instance, looking up environment variables using
+// `env_lookup`.
+//
+// Args:
+//   argv0: name of the binary; if this string is not empty, then the function
+//     looks for a runfiles manifest or directory next to this
+//   env_lookup: a function that returns envvar values if an envvar is known, or
+//     empty string otherwise
+Runfiles* TestOnly_CreateRunfiles(
+    const std::string& argv0,
+    std::function<std::string(const std::string&)> env_lookup,
+    std::string* error);
+
+// 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_