diff options
author | Laszlo Csomor <laszlocsomor@google.com> | 2018-05-30 02:47:38 -0700 |
---|---|---|
committer | Copybara-Service <copybara-piper@google.com> | 2018-05-30 02:48:59 -0700 |
commit | 22f4bb9afa6a8454a15fbd21edbb69c4518fbbf2 (patch) | |
tree | 8bf36113542c4ae40e730e25b6a827401368d411 /src/test/py | |
parent | 2cbcde33478756d265a57e88c89732126f33879a (diff) |
runfiles,cc: C++ runfiles library in @bazel_tools
Add the C++ runfiles library to
@bazel_tools//tools/cpp/runfiles:runfiles.
RELNOTES[NEW]: C++,runfiles: to access data-dependencies (runfiles) in C++ programs, use the runfiles library built into Bazel. For usage info, see https://github.com/bazelbuild/bazel/blob/master/tools/cpp/runfiles/runfiles.h
Change-Id: I5057a9f477289eea7244c60105e77fc71652a817
Closes #5293.
Change-Id: I90cba6fa4c6595c838ae42f9d2c17548c8387e5d
PiperOrigin-RevId: 198531849
Diffstat (limited to 'src/test/py')
9 files changed, 301 insertions, 26 deletions
diff --git a/src/test/py/bazel/runfiles_test.py b/src/test/py/bazel/runfiles_test.py index 86c40b9cbb..9131cd2072 100644 --- a/src/test/py/bazel/runfiles_test.py +++ b/src/test/py/bazel/runfiles_test.py @@ -32,20 +32,24 @@ class RunfilesTest(test_base.TestBase): "\n".join(stderr)) def _AssertRunfilesLibraryInBazelToolsRepo(self, family, lang_name): - for s, t, exe in [ - ("WORKSPACE.mock", "WORKSPACE", False), - ("foo/BUILD.mock", "foo/BUILD", False), - ("foo/foo.py", "foo/foo.py", True), - ("foo/Foo.java", "foo/Foo.java", False), - ("foo/foo.sh", "foo/foo.sh", True), - ("foo/datadep/hello.txt", "foo/datadep/hello.txt", False), - ("bar/BUILD.mock", "bar/BUILD", False), - ("bar/bar.py", "bar/bar.py", True), - ("bar/bar-py-data.txt", "bar/bar-py-data.txt", False), - ("bar/Bar.java", "bar/Bar.java", False), - ("bar/bar-java-data.txt", "bar/bar-java-data.txt", False), - ("bar/bar.sh", "bar/bar.sh", True), - ("bar/bar-sh-data.txt", "bar/bar-sh-data.txt", False)]: + for s, t, exe in [("WORKSPACE.mock", "WORKSPACE", + False), ("foo/BUILD.mock", "foo/BUILD", + False), ("foo/foo.py", "foo/foo.py", True), + ("foo/Foo.java", "foo/Foo.java", + False), ("foo/foo.sh", "foo/foo.sh", + True), ("foo/foo.cc", "foo/foo.cc", False), + ("foo/datadep/hello.txt", "foo/datadep/hello.txt", + False), ("bar/BUILD.mock", "bar/BUILD", + False), ("bar/bar.py", "bar/bar.py", True), + ("bar/bar-py-data.txt", "bar/bar-py-data.txt", + False), ("bar/Bar.java", "bar/Bar.java", + False), ("bar/bar-java-data.txt", + "bar/bar-java-data.txt", False), + ("bar/bar.sh", "bar/bar.sh", + True), ("bar/bar-sh-data.txt", "bar/bar-sh-data.txt", + False), ("bar/bar.cc", "bar/bar.cc", + False), ("bar/bar-cc-data.txt", + "bar/bar-cc-data.txt", False)]: self.CopyFile( self.Rlocation("io_bazel/src/test/py/bazel/testdata/runfiles_test/" + s), t, exe) @@ -54,7 +58,10 @@ class RunfilesTest(test_base.TestBase): self.AssertExitCode(exit_code, 0, stderr) bazel_bin = stdout[0] - exit_code, _, stderr = self.RunBazel(["build", "//foo:runfiles-" + family]) + exit_code, _, stderr = self.RunBazel([ + "build", "--verbose_failures", "--experimental_shortened_obj_file_path", + "//foo:runfiles-" + family + ]) self.AssertExitCode(exit_code, 0, stderr) if test_base.TestBase.IsWindows(): @@ -67,7 +74,8 @@ class RunfilesTest(test_base.TestBase): exit_code, stdout, stderr = self.RunProgram( [bin_path], env_add={"TEST_SRCDIR": "__ignore_me__"}) self.AssertExitCode(exit_code, 0, stderr) - if len(stdout) != 8: + # 10 output lines: 2 from foo-<family>, and 2 from each of bar-<lang>. + if len(stdout) != 10: self.fail("stdout: %s" % stdout) self.assertEqual(stdout[0], "Hello %s Foo!" % lang_name) @@ -82,7 +90,7 @@ class RunfilesTest(test_base.TestBase): i = 2 for lang in [("py", "Python", "bar.py"), ("java", "Java", "Bar.java"), - ("sh", "Bash", "bar.sh")]: + ("sh", "Bash", "bar.sh"), ("cc", "C++", "bar.cc")]: self.assertEqual(stdout[i], "Hello %s Bar!" % lang[1]) six.assertRegex(self, stdout[i + 1], "^rloc=.*/bar/bar-%s-data.txt" % lang[0]) @@ -105,6 +113,9 @@ class RunfilesTest(test_base.TestBase): def testBashRunfilesLibraryInBazelToolsRepo(self): self._AssertRunfilesLibraryInBazelToolsRepo("sh", "Bash") + def testCppRunfilesLibraryInBazelToolsRepo(self): + self._AssertRunfilesLibraryInBazelToolsRepo("cc", "C++") + def testRunfilesLibrariesFindRunfilesWithoutEnvvars(self): for s, t, exe in [ ("WORKSPACE.mock", "WORKSPACE", False), @@ -115,6 +126,8 @@ class RunfilesTest(test_base.TestBase): ("bar/bar-java-data.txt", "bar/bar-java-data.txt", False), ("bar/bar.sh", "bar/bar.sh", True), ("bar/bar-sh-data.txt", "bar/bar-sh-data.txt", False), + ("bar/bar.cc", "bar/bar.cc", False), + ("bar/bar-cc-data.txt", "bar/bar-cc-data.txt", False), ]: self.CopyFile( self.Rlocation("io_bazel/src/test/py/bazel/testdata/runfiles_test/" + @@ -124,12 +137,14 @@ class RunfilesTest(test_base.TestBase): self.AssertExitCode(exit_code, 0, stderr) bazel_bin = stdout[0] - exit_code, _, stderr = self.RunBazel( - ["build", "//bar:bar-py", "//bar:bar-java", "//bar:bar-sh"]) + exit_code, _, stderr = self.RunBazel([ + "build", "--verbose_failures", "--experimental_shortened_obj_file_path", + "//bar:bar-py", "//bar:bar-java", "//bar:bar-sh", "//bar:bar-cc" + ]) self.AssertExitCode(exit_code, 0, stderr) for lang in [("py", "Python", "bar.py"), ("java", "Java", "Bar.java"), - ("sh", "Bash", "bar.sh")]: + ("sh", "Bash", "bar.sh"), ("cc", "C++", "bar.cc")]: if test_base.TestBase.IsWindows(): bin_path = os.path.join(bazel_bin, "bar/bar-%s.exe" % lang[0]) else: @@ -171,6 +186,8 @@ class RunfilesTest(test_base.TestBase): ("bar/bar-java-data.txt", "bar/bar-java-data.txt", False), ("bar/bar.sh", "bar/bar.sh", True), ("bar/bar-sh-data.txt", "bar/bar-sh-data.txt", False), + ("bar/bar.cc", "bar/bar.cc", False), + ("bar/bar-cc-data.txt", "bar/bar-cc-data.txt", False), ]: self.CopyFile( self.Rlocation("io_bazel/src/test/py/bazel/testdata/runfiles_test/" + @@ -180,10 +197,11 @@ class RunfilesTest(test_base.TestBase): self.AssertExitCode(exit_code, 0, stderr) bazel_bin = stdout[0] - for lang in [("java", "Java"), - ("sh", "Bash")]: # TODO(laszlocsomor): add "cc" when ready. + for lang in [("java", "Java"), ("sh", "Bash"), ("cc", "C++")]: exit_code, _, stderr = self.RunBazel([ - "build", "--experimental_enable_runfiles=no", "//bar:bar-" + lang[0] + "build", "--verbose_failures", + "--experimental_shortened_obj_file_path", + "--experimental_enable_runfiles=no", "//bar:bar-" + lang[0] ]) self.AssertExitCode(exit_code, 0, stderr) diff --git a/src/test/py/bazel/testdata/runfiles_test/bar/BUILD.mock b/src/test/py/bazel/testdata/runfiles_test/bar/BUILD.mock index ab97f8d9eb..930884b45a 100644 --- a/src/test/py/bazel/testdata/runfiles_test/bar/BUILD.mock +++ b/src/test/py/bazel/testdata/runfiles_test/bar/BUILD.mock @@ -22,3 +22,10 @@ sh_binary( data = ["bar-sh-data.txt"], deps = ["@bazel_tools//tools/bash/runfiles"], ) + +cc_binary( + name = "bar-cc", + srcs = ["bar.cc"], + data = ["bar-cc-data.txt"], + deps = ["@bazel_tools//tools/cpp/runfiles"], +) diff --git a/src/test/py/bazel/testdata/runfiles_test/bar/bar-cc-data.txt b/src/test/py/bazel/testdata/runfiles_test/bar/bar-cc-data.txt new file mode 100644 index 0000000000..09db5f47ce --- /dev/null +++ b/src/test/py/bazel/testdata/runfiles_test/bar/bar-cc-data.txt @@ -0,0 +1 @@ +data for bar.cc diff --git a/src/test/py/bazel/testdata/runfiles_test/bar/bar.cc b/src/test/py/bazel/testdata/runfiles_test/bar/bar.cc new file mode 100644 index 0000000000..1101b1df11 --- /dev/null +++ b/src/test/py/bazel/testdata/runfiles_test/bar/bar.cc @@ -0,0 +1,59 @@ +// 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. + +// Mock C++ binary, only used in tests. + +#include <fstream> +#include <iostream> +#include <memory> +#include <string> + +#include "tools/cpp/runfiles/runfiles.h" + +namespace { + +using bazel::tools::cpp::runfiles::Runfiles; +using std::cerr; +using std::cout; +using std::endl; +using std::ifstream; +using std::string; +using std::unique_ptr; + +bool is_file(const string& path) { + if (path.empty()) { + return false; + } + return ifstream(path).is_open(); +} + +int _main(int argc, char** argv) { + cout << "Hello C++ Bar!" << endl; + string error; + unique_ptr<Runfiles> runfiles(Runfiles::Create(argv[0], &error)); + if (runfiles == nullptr) { + cerr << "ERROR[" << __FILE__ << "]: " << error << endl; + return 1; + } + string path = runfiles->Rlocation("foo_ws/bar/bar-cc-data.txt"); + if (!is_file(path)) { + return 1; + } + cout << "rloc=" << path << endl; + return 0; +} + +} // namespace + +int main(int argc, char** argv) { return _main(argc, argv); } diff --git a/src/test/py/bazel/testdata/runfiles_test/foo/BUILD.mock b/src/test/py/bazel/testdata/runfiles_test/foo/BUILD.mock index f35b840887..42c7d84241 100644 --- a/src/test/py/bazel/testdata/runfiles_test/foo/BUILD.mock +++ b/src/test/py/bazel/testdata/runfiles_test/foo/BUILD.mock @@ -6,6 +6,7 @@ py_binary( "//bar:bar-java", "//bar:bar-py", "//bar:bar-sh", + "//bar:bar-cc", ], main = "foo.py", deps = ["@bazel_tools//tools/python/runfiles"], @@ -19,6 +20,7 @@ java_binary( "//bar:bar-py", "//bar:bar-java", "//bar:bar-sh", + "//bar:bar-cc", ], main_class = "Foo", deps = ["@bazel_tools//tools/runfiles:java-runfiles"], @@ -32,6 +34,24 @@ sh_binary( "//bar:bar-java", "//bar:bar-py", "//bar:bar-sh", + "//bar:bar-cc", ], deps = ["@bazel_tools//tools/bash/runfiles"], ) + +cc_binary( + name = "runfiles-cc", + srcs = ["foo.cc"], + data = [ + "datadep/hello.txt", + "//bar:bar-java", + "//bar:bar-py", + "//bar:bar-sh", + "//bar:bar-cc", + ], + copts = select({ + "@bazel_tools//src/conditions:windows": ["/DIS_WINDOWS=1"], + "//conditions:default": [], + }), + deps = ["@bazel_tools//tools/cpp/runfiles"], +) diff --git a/src/test/py/bazel/testdata/runfiles_test/foo/Foo.java b/src/test/py/bazel/testdata/runfiles_test/foo/Foo.java index 3571de1942..898cb03d76 100644 --- a/src/test/py/bazel/testdata/runfiles_test/foo/Foo.java +++ b/src/test/py/bazel/testdata/runfiles_test/foo/Foo.java @@ -28,7 +28,7 @@ public class Foo { Runfiles r = Runfiles.create(); System.out.println("rloc=" + r.rlocation("foo_ws/foo/datadep/hello.txt")); - for (String lang : new String[] {"py", "java", "sh"}) { + for (String lang : new String[] {"py", "java", "sh", "cc"}) { String path = r.rlocation(childBinaryName(lang)); if (path == null || path.isEmpty()) { throw new IOException("cannot find child binary for " + lang); diff --git a/src/test/py/bazel/testdata/runfiles_test/foo/foo.cc b/src/test/py/bazel/testdata/runfiles_test/foo/foo.cc new file mode 100644 index 0000000000..07ec268e3c --- /dev/null +++ b/src/test/py/bazel/testdata/runfiles_test/foo/foo.cc @@ -0,0 +1,170 @@ +// 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. + +// Mock C++ binary, only used in tests. + +#include "tools/cpp/runfiles/runfiles.h" + +#ifdef IS_WINDOWS +#include <windows.h> +#else // not IS_WINDOWS +#include <stdlib.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#endif // IS_WINDOWS + +#include <string.h> + +#include <fstream> +#include <iostream> +#include <memory> +#include <string> + +namespace { + +using bazel::tools::cpp::runfiles::Runfiles; +using std::cerr; +using std::cout; +using std::endl; +using std::ifstream; +using std::string; +using std::unique_ptr; + +string child_binary_name(const char* lang) { +#ifdef IS_WINDOWS + return string("foo_ws/bar/bar-") + lang + ".exe"; +#else + return string("foo_ws/bar/bar-") + lang; +#endif // IS_WINDOWS +} + +bool is_file(const string& path) { + if (path.empty()) { + return false; + } + return ifstream(path).is_open(); +} + +#ifdef IS_WINDOWS +unique_ptr<char[]> create_env_block(const Runfiles& runfiles) { + char systemroot[MAX_PATH]; + DWORD systemroot_size = + GetEnvironmentVariable("SYSTEMROOT", systemroot, MAX_PATH); + if (!systemroot_size || systemroot_size == MAX_PATH) { + cerr << "ERROR[" << __FILE__ << "]: %SYSTEMROOT% is too long" << endl; + return std::move(unique_ptr<char[]>()); + } + + size_t total_envblock_size = + 10 /* the string "SYSTEMROOT" */ + 1 /* equals-sign */ + systemroot_size + + 1 /* null-terminator */ + + 2 /* two null-terminator at the end of the environment block */; + + // count total size of the environment block + const auto envvars = runfiles.EnvVars(); + for (const auto i : envvars) { + total_envblock_size += i.first.size() + 1 /* equals-sign */ + + i.second.size() + 1 /* null-terminator */; + } + + // copy environment variables from `envvars` + unique_ptr<char[]> result(new char[total_envblock_size]); + char* p = result.get(); + for (const auto i : envvars) { + strncpy(p, i.first.c_str(), i.first.size()); + p += i.first.size(); + *p++ = '='; + strncpy(p, i.second.c_str(), i.second.size()); + p += i.second.size(); + *p++ = '\0'; + } + + // SYSTEMROOT environment variable + strncpy(p, "SYSTEMROOT=", 11); + p += 11; + strncpy(p, systemroot, systemroot_size); + p += systemroot_size; + *p++ = '\0'; + + // final two null-terminators + p[0] = '\0'; + p[1] = '\0'; + + return std::move(result); +} +#endif + +int _main(int argc, char** argv) { + cout << "Hello C++ Foo!" << endl; + string error; + unique_ptr<Runfiles> runfiles(Runfiles::Create(argv[0], &error)); + if (runfiles == nullptr) { + cerr << "ERROR[" << __FILE__ << "]: " << error << endl; + return 1; + } + string path = runfiles->Rlocation("foo_ws/foo/datadep/hello.txt"); + if (!is_file(path)) { + return 1; + } + cout << "rloc=" << path << endl; + +#ifdef IS_WINDOWS + auto envvars = create_env_block(*runfiles); +#else + const auto envvars = runfiles->EnvVars(); +#endif + + // Run a subprocess, propagate the runfiles envvar to it. The subprocess will + // use this process's runfiles manifest or runfiles directory. + for (const char* lang : {"py", "java", "sh", "cc"}) { + const string bar = runfiles->Rlocation(child_binary_name(lang)); + + unique_ptr<char[]> argv0(new char[bar.size() + 1]); + strncpy(argv0.get(), bar.c_str(), bar.size()); + argv0.get()[bar.size()] = 0; + +#ifdef IS_WINDOWS + PROCESS_INFORMATION processInfo; + STARTUPINFOA startupInfo = {0}; + BOOL ok = CreateProcessA(NULL, argv0.get(), NULL, NULL, FALSE, 0, + envvars.get(), NULL, &startupInfo, &processInfo); + if (!ok) { + DWORD err = GetLastError(); + fprintf(stderr, "ERROR: CreateProcessA error: %d\n", err); + return 1; + } + WaitForSingleObject(processInfo.hProcess, INFINITE); + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); +#else + char* args[2] = {argv0.get(), NULL}; + 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); + } +#endif + } + return 0; +} + +} // namespace + +int main(int argc, char** argv) { return _main(argc, argv); } diff --git a/src/test/py/bazel/testdata/runfiles_test/foo/foo.py b/src/test/py/bazel/testdata/runfiles_test/foo/foo.py index d526531c9a..e6422b7ddb 100644 --- a/src/test/py/bazel/testdata/runfiles_test/foo/foo.py +++ b/src/test/py/bazel/testdata/runfiles_test/foo/foo.py @@ -53,7 +53,7 @@ def main(): else: env = {} env.update(r.EnvVars()) - for lang in ["py", "java", "sh"]: + for lang in ["py", "java", "sh", "cc"]: p = subprocess.Popen( [r.Rlocation(ChildBinaryName(lang))], env=env, diff --git a/src/test/py/bazel/testdata/runfiles_test/foo/foo.sh b/src/test/py/bazel/testdata/runfiles_test/foo/foo.sh index ec934ed498..687d6121c2 100755 --- a/src/test/py/bazel/testdata/runfiles_test/foo/foo.sh +++ b/src/test/py/bazel/testdata/runfiles_test/foo/foo.sh @@ -68,7 +68,7 @@ function main() { if is_windows; then export SYSTEMROOT="${SYSTEMROOT:-}" fi - for lang in py java sh; do + for lang in py java sh cc; do child_bin="$(rlocation "$(child_binary_name $lang)")" if ! "$child_bin"; then echo >&2 "ERROR: error running bar-$lang" |