aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/tools/runfiles
diff options
context:
space:
mode:
authorGravatar Laszlo Csomor <laszlocsomor@google.com>2018-02-26 09:17:02 -0800
committerGravatar Copybara-Service <copybara-piper@google.com>2018-02-26 09:19:02 -0800
commit9dfb1ee2fc1b6e312105ad2062ec963d28b916e6 (patch)
tree23253b4f732d460512003242d663a07452661f88 /src/tools/runfiles
parent726df7e1cbf29422964e826d90019846a5c092fb (diff)
runfiles,C++: implement runfiles lib foundations
Implement the foundation of the C++ runfiles library, along with a directory-based Runfiles implementation. Subsequent commits will add more feataures: - manifest-based runfiles handling - creating list of envvars to pass to child processes - automatic Runfiles creation based on argv[0] and the envvars of this process See https://github.com/bazelbuild/bazel/issues/4460 Change-Id: Id5a38619a1ae874499f04523863081559360410c PiperOrigin-RevId: 187031518
Diffstat (limited to 'src/tools/runfiles')
-rw-r--r--src/tools/runfiles/BUILD30
-rw-r--r--src/tools/runfiles/runfiles.cc101
-rw-r--r--src/tools/runfiles/runfiles.h88
-rw-r--r--src/tools/runfiles/runfiles_test.cc53
4 files changed, 272 insertions, 0 deletions
diff --git a/src/tools/runfiles/BUILD b/src/tools/runfiles/BUILD
index 5ac490d1e2..c6ec162139 100644
--- a/src/tools/runfiles/BUILD
+++ b/src/tools/runfiles/BUILD
@@ -20,6 +20,8 @@ filegroup(
name = "embedded_tools",
srcs = [
"BUILD.tools",
+ "runfiles.cc",
+ "runfiles.h",
"runfiles.py",
"//src/tools/runfiles/java/com/google/devtools/build/runfiles:embedded_tools",
],
@@ -38,6 +40,34 @@ py_test(
deps = [":py-runfiles"],
)
+cc_library(
+ name = "cc-runfiles",
+ srcs = ["runfiles.cc"],
+ hdrs = ["runfiles.h"],
+ # This library is available to clients under
+ # @bazel_tools//tools/runfiles:cc-runfiles, with the same source files.
+ # The include statement in runfiles.cc that includes runfiles.h must work
+ # both here in the //src/tools/runfiles package, and in the
+ # @bazel_tools//tools/runfiles package.
+ # runfiles.cc includes "tools/runfiles/runfiles.h" so we need to tell the
+ # compiler to prepend "src" to it so the include path is valid.
+ # Alternatively we could omit this "copts" attribute here and add some
+ # include path manipulating attributes to
+ # @bazel_tools//tools/runfiles:cc-runfiles instead -- that would work too,
+ # but I (laszlocsomor@) find this solution (i.e. the "copts" attribute on
+ # this rule) to be simpler.
+ copts = ["-Isrc"],
+)
+
+cc_test(
+ name = "cc-runfiles-test",
+ srcs = ["runfiles_test.cc"],
+ deps = [
+ ":cc-runfiles",
+ "//third_party:gtest",
+ ],
+)
+
sh_library(
name = "runfiles_sh_lib",
srcs = ["runfiles.sh"],
diff --git a/src/tools/runfiles/runfiles.cc b/src/tools/runfiles/runfiles.cc
new file mode 100644
index 0000000000..9ff1f3f4c5
--- /dev/null
+++ b/src/tools/runfiles/runfiles.cc
@@ -0,0 +1,101 @@
+// 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.
+#include "tools/runfiles/runfiles.h"
+
+namespace bazel {
+namespace runfiles {
+
+using std::string;
+
+namespace {
+
+class RunfilesImpl : public Runfiles {
+ public:
+ // TODO(laszlocsomor): implement Create(
+ // const string& argv0, function<string(const string&)> env_lookup, string*
+ // error);
+
+ string Rlocation(const string& path) const override;
+
+ // Returns the runtime-location of a given runfile.
+ //
+ // This method assumes that the caller already validated the `path`. See
+ // Runfiles::Rlocation for requirements.
+ virtual string RlocationChecked(const string& path) const = 0;
+
+ protected:
+ RunfilesImpl() {}
+ virtual ~RunfilesImpl() {}
+};
+
+// TODO(laszlocsomor): derive a ManifestBased class from RunfilesImpl.
+
+// Runfiles implementation that appends runfiles paths to the runfiles root.
+class DirectoryBased : public RunfilesImpl {
+ public:
+ DirectoryBased(string runfiles_path)
+ : runfiles_path_(std::move(runfiles_path)) {}
+ string RlocationChecked(const string& path) const override;
+
+ private:
+ DirectoryBased(const DirectoryBased&) = delete;
+ DirectoryBased(DirectoryBased&&) = delete;
+ DirectoryBased& operator=(const DirectoryBased&) = delete;
+ DirectoryBased& operator=(DirectoryBased&&) = delete;
+
+ const string runfiles_path_;
+};
+
+bool IsAbsolute(const string& path) {
+ if (path.empty()) {
+ return false;
+ }
+ char c = path.front();
+ return (c == '/') || (path.size() >= 3 &&
+ ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) &&
+ path[1] == ':' && (path[2] == '\\' || path[2] == '/'));
+}
+
+string RunfilesImpl::Rlocation(const string& path) const {
+ if (path.empty() || path.find("..") != string::npos) {
+ return std::move(string());
+ }
+ if (IsAbsolute(path)) {
+ return path;
+ }
+ return RlocationChecked(path);
+}
+
+string DirectoryBased::RlocationChecked(const string& path) const {
+ return std::move(runfiles_path_ + "/" + path);
+}
+
+} // namespace
+
+namespace testing {
+
+bool TestOnly_IsAbsolute(const string& path) { return IsAbsolute(path); }
+
+} // namespace testing
+
+Runfiles* Runfiles::CreateDirectoryBased(const string& directory_path,
+ string* error) {
+ // Note: `error` is intentionally unused because we don't expect any errors
+ // here. We expect an `error` pointer so that we may use it in the future if
+ // need be, without having to change the API.
+ return new DirectoryBased(directory_path);
+}
+
+} // namespace runfiles
+} // namespace bazel
diff --git a/src/tools/runfiles/runfiles.h b/src/tools/runfiles/runfiles.h
new file mode 100644
index 0000000000..c15dec39e0
--- /dev/null
+++ b/src/tools/runfiles/runfiles.h
@@ -0,0 +1,88 @@
+// 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.
+//
+// TODO(laszlocsomor): add usage information and examples.
+
+#ifndef BAZEL_SRC_TOOLS_RUNFILES_RUNFILES_H_
+#define BAZEL_SRC_TOOLS_RUNFILES_RUNFILES_H_ 1
+
+#include <string>
+
+namespace bazel {
+namespace runfiles {
+
+class Runfiles {
+ public:
+ virtual ~Runfiles() {}
+
+ // TODO(laszlocsomor): implement:
+ // Runfiles* Create(const string& argv0, string* error);
+ // TODO(laszlocsomor): implement:
+ // vector<pair<string, string>> EnvVars();
+ // TODO(laszlocsomor): implement:
+ // Runfiles* CreateManifestBased(const string& path, string* error);
+
+ // 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;
+
+ 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, because they may change without
+// notice.
+namespace testing {
+
+// 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 bazel
+
+#endif // BAZEL_SRC_TOOLS_RUNFILES_RUNFILES_H_
diff --git a/src/tools/runfiles/runfiles_test.cc b/src/tools/runfiles/runfiles_test.cc
new file mode 100644
index 0000000000..e286fa370f
--- /dev/null
+++ b/src/tools/runfiles/runfiles_test.cc
@@ -0,0 +1,53 @@
+// 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.
+
+#include "src/tools/runfiles/runfiles.h"
+
+#include <memory>
+#include <string>
+
+#include "gtest/gtest.h"
+
+#define _T(x) #x
+#define T(x) _T(x)
+#define LINE() T(__LINE__)
+
+namespace bazel {
+namespace runfiles {
+namespace {
+
+using std::string;
+using std::unique_ptr;
+
+TEST(RunfilesTest, DirectoryBasedRunfilesRlocation) {
+ string error;
+ unique_ptr<Runfiles> r(Runfiles::CreateDirectoryBased("whatever", &error));
+ ASSERT_NE(r, nullptr);
+ EXPECT_TRUE(error.empty());
+
+ EXPECT_EQ(r->Rlocation("a/b"), "whatever/a/b");
+ EXPECT_EQ(r->Rlocation("c/d"), "whatever/c/d");
+ EXPECT_EQ(r->Rlocation(""), "");
+ EXPECT_EQ(r->Rlocation("foo"), "whatever/foo");
+ EXPECT_EQ(r->Rlocation("foo/"), "whatever/foo/");
+ EXPECT_EQ(r->Rlocation("foo/bar"), "whatever/foo/bar");
+ EXPECT_EQ(r->Rlocation("foo/.."), "");
+ EXPECT_EQ(r->Rlocation("/Foo"), "/Foo");
+ EXPECT_EQ(r->Rlocation("c:/Foo"), "c:/Foo");
+ EXPECT_EQ(r->Rlocation("c:\\Foo"), "c:\\Foo");
+}
+
+} // namespace
+} // namespace runfiles
+} // namespace bazel