aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/tools
diff options
context:
space:
mode:
authorGravatar kmb <kmb@google.com>2017-10-21 04:07:24 +0200
committerGravatar Dmitry Lomov <dslomov@google.com>2017-10-23 17:16:19 +0200
commitdb1426b75d7721554a8b139696b5b4c400a260a5 (patch)
tree03d407f62851fa8e179e1f6c2745ad5826d71a4c /src/tools
parent9cc97513839442ac13fe10ab84e103e127e36987 (diff)
Exclude Android dependency checking from Bazel's singlejar build.
This should also address https://github.com/bazelbuild/bazel/issues/3903 RELNOTES: None. PiperOrigin-RevId: 172963663
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/singlejar/BUILD1
-rw-r--r--src/tools/singlejar/combiners.cc137
-rw-r--r--src/tools/singlejar/combiners.h57
-rw-r--r--src/tools/singlejar/combiners_test.cc71
-rw-r--r--src/tools/singlejar/desugar_checking.cc153
-rw-r--r--src/tools/singlejar/desugar_checking.h85
-rw-r--r--src/tools/singlejar/desugar_checking_test.cc102
-rw-r--r--src/tools/singlejar/output_jar.cc11
-rw-r--r--src/tools/singlejar/output_jar.h2
-rw-r--r--src/tools/singlejar/singlejar_main.cc9
10 files changed, 353 insertions, 275 deletions
diff --git a/src/tools/singlejar/BUILD b/src/tools/singlejar/BUILD
index e986ab06c6..1b0cfd2444 100644
--- a/src/tools/singlejar/BUILD
+++ b/src/tools/singlejar/BUILD
@@ -286,7 +286,6 @@ cc_library(
],
hdrs = ["combiners.h"],
deps = [
- "//src/main/protobuf:desugar_deps_cc_proto",
"//third_party/zlib",
],
)
diff --git a/src/tools/singlejar/combiners.cc b/src/tools/singlejar/combiners.cc
index aaddd79aaa..8fd2a0fdfe 100644
--- a/src/tools/singlejar/combiners.cc
+++ b/src/tools/singlejar/combiners.cc
@@ -14,7 +14,6 @@
#include "src/tools/singlejar/combiners.h"
#include "src/tools/singlejar/diag.h"
-#include "src/main/protobuf/desugar_deps.pb.h"
Combiner::~Combiner() {}
@@ -175,139 +174,3 @@ PropertyCombiner::~PropertyCombiner() {}
bool PropertyCombiner::Merge(const CDH *cdh, const LH *lh) {
return false; // This should not be called.
}
-
-bool Java8DesugarDepsChecker::Merge(const CDH *cdh, const LH *lh) {
- // Throw away anything previously read, no need to concatenate
- buffer_.reset(new TransientBytes());
- if (Z_NO_COMPRESSION == lh->compression_method()) {
- buffer_->ReadEntryContents(lh);
- } else if (Z_DEFLATED == lh->compression_method()) {
- if (!inflater_.get()) {
- inflater_.reset(new Inflater());
- }
- buffer_->DecompressEntryContents(cdh, lh, inflater_.get());
- } else {
- errx(2, "META-INF/desugar_deps is neither stored nor deflated");
- }
-
- // TODO(kmb): Wrap buffer_ as ZeroCopyInputStream to avoid copying out.
- // Note we only copy one file at a time, so overhead should be modest.
- uint32_t checksum;
- const size_t data_size = buffer_->data_size();
- uint8_t *buf = reinterpret_cast<uint8_t *>(malloc(data_size));
- buffer_->CopyOut(reinterpret_cast<uint8_t *>(buf), &checksum);
- buffer_.reset(); // release buffer eagerly
-
- bazel::tools::desugar::DesugarDepsInfo deps_info;
- google::protobuf::io::CodedInputStream content(buf, data_size);
- if (!deps_info.ParseFromCodedStream(&content)) {
- errx(2, "META-INF/desugar_deps: unable to parse");
- }
- if (!content.ConsumedEntireMessage()) {
- errx(2, "META-INF/desugar_deps: unexpected trailing content");
- }
- free(buf);
-
- for (const auto &assume_present : deps_info.assume_present()) {
- // This means we need file named <target>.class in the output. Remember
- // the first origin of this requirement for error messages, drop others.
- needed_deps_.emplace(assume_present.target().binary_name() + ".class",
- assume_present.origin().binary_name());
- }
-
- for (const auto &missing : deps_info.missing_interface()) {
- // Remember the first origin of this requirement for error messages, drop
- // subsequent ones.
- missing_interfaces_.emplace(missing.target().binary_name(),
- missing.origin().binary_name());
- }
-
- for (const auto &extends : deps_info.interface_with_supertypes()) {
- // Remember interface hierarchy the first time we see this interface, drop
- // subsequent ones for consistency with how singlejar will keep the first
- // occurrence of the file defining the interface. We'll lazily derive
- // whether missing_interfaces_ inherit default methods with this data later.
- if (extends.extended_interface_size() > 0) {
- std::vector<std::string> extended;
- extended.reserve(extends.extended_interface_size());
- for (const auto &itf : extends.extended_interface()) {
- extended.push_back(itf.binary_name());
- }
- extended_interfaces_.emplace(extends.origin().binary_name(),
- std::move(extended));
- }
- }
-
- for (const auto &companion : deps_info.interface_with_companion()) {
- // Only remember interfaces that definitely have default methods for now.
- // For all other interfaces we'll transitively check extended interfaces
- // in HasDefaultMethods.
- if (companion.num_default_methods() > 0) {
- has_default_methods_[companion.origin().binary_name()] = true;
- }
- }
- return true;
-}
-
-void *Java8DesugarDepsChecker::OutputEntry(bool compress) {
- if (verbose_) {
- fprintf(stderr, "Needed deps: %lu\n", needed_deps_.size());
- fprintf(stderr, "Interfaces to check: %lu\n", missing_interfaces_.size());
- fprintf(stderr, "Sub-interfaces: %lu\n", extended_interfaces_.size());
- fprintf(stderr, "Interfaces w/ default methods: %lu\n",
- has_default_methods_.size());
- }
- for (auto needed : needed_deps_) {
- if (verbose_) {
- fprintf(stderr, "Looking for %s\n", needed.first.c_str());
- }
- if (!known_member_(needed.first)) {
- if (fail_on_error_) {
- errx(2, "%s referenced by %s but not found. Is the former defined in "
- "a neverlink library?",
- needed.first.c_str(), needed.second.c_str());
- } else {
- error_ = true;
- }
- }
- }
-
- for (auto missing : missing_interfaces_) {
- if (verbose_) {
- fprintf(stderr, "Checking %s\n", missing.first.c_str());
- }
- if (HasDefaultMethods(missing.first)) {
- if (fail_on_error_) {
- errx(2, "%s needed on the classpath for desugaring %s. Please add the "
- "missing dependency to the target containing the latter.",
- missing.first.c_str(), missing.second.c_str());
- } else {
- error_ = true;
- }
- }
- }
-
- // We don't want these files in the output, just check them for consistency
- return nullptr;
-}
-
-bool Java8DesugarDepsChecker::HasDefaultMethods(
- const std::string &interface_name) {
- auto cached = has_default_methods_.find(interface_name);
- if (cached != has_default_methods_.end()) {
- return cached->second;
- }
-
- // Prime with false in case there's a cycle. We'll update with the true value
- // (ignoring the cycle) below.
- has_default_methods_.emplace(interface_name, false);
-
- for (const std::string &extended : extended_interfaces_[interface_name]) {
- if (HasDefaultMethods(extended)) {
- has_default_methods_[interface_name] = true;
- return true;
- }
- }
- has_default_methods_[interface_name] = false;
- return false;
-}
diff --git a/src/tools/singlejar/combiners.h b/src/tools/singlejar/combiners.h
index f7d4cc7be9..4963d336b3 100644
--- a/src/tools/singlejar/combiners.h
+++ b/src/tools/singlejar/combiners.h
@@ -136,61 +136,4 @@ class PropertyCombiner : public Concatenator {
}
};
-// Combiner that checks META-INF/desugar_deps files (b/65645388) to ensure
-// correct bytecode desugaring, specifically of default and static interface
-// methods, across an entire binary. Two checks are performed:
-// 1. Make sure that any dependency assumed by the desugaring process is in
-// fact part of the binary. This protects against ill-advised uses of
-// neverlink, where a library is only on the compile-time classpath but not
-// the runtime classpath.
-// 2. To paper over incomplete classpaths during desugaring (b/65211436), check
-// that interfaces that couldn't be found don't declare or inherit default
-// methods. Desugar emits extra metadata to avoid us having to open up and
-// parse .class files for this purpose.
-class Java8DesugarDepsChecker : public Combiner {
- public:
- Java8DesugarDepsChecker(std::function<bool(const std::string &)> known_member,
- bool verbose)
- : Java8DesugarDepsChecker(std::move(known_member), verbose, true) {}
- ~Java8DesugarDepsChecker() override {}
-
- bool Merge(const CDH *cdh, const LH *lh) override;
-
- void *OutputEntry(bool compress) override;
-
- private:
- Java8DesugarDepsChecker(std::function<bool(const std::string &)> known_member,
- bool verbose, bool fail_on_error)
- : known_member_(std::move(known_member)),
- verbose_(verbose),
- fail_on_error_(fail_on_error),
- error_(false) {}
- /// Computes and caches whether the given interface has default methods.
- /// \param interface_name interface name as it would appear in bytecode, e.g.,
- /// "java/lang/Runnable"
- bool HasDefaultMethods(const std::string &interface_name);
-
- const std::function<bool(const std::string &)> known_member_;
- const bool verbose_;
- const bool fail_on_error_; // For testing
-
- std::unique_ptr<TransientBytes> buffer_;
- std::unique_ptr<Inflater> inflater_;
- /// Reverse mapping from needed dependencies to one of the users.
- std::map<std::string, std::string> needed_deps_;
- /// Reverse mapping from missing interfaces to one of the classes that missed
- /// them.
- std::map<std::string, std::string> missing_interfaces_;
- std::unordered_map<std::string, std::vector<std::string> >
- extended_interfaces_;
- /// Cache of interfaces known to definitely define or inherit default methods
- /// or definitely not define and not inherit default methods. Merge()
- /// populates initial entries and HasDefaultMethods() adds to the cache as
- /// needed.
- std::unordered_map<std::string, bool> has_default_methods_;
- bool error_;
-
- friend class CombinersTest;
-};
-
#endif // SRC_TOOLS_SINGLEJAR_COMBINERS_H_
diff --git a/src/tools/singlejar/combiners_test.cc b/src/tools/singlejar/combiners_test.cc
index effdf265be..b1dd75f7b1 100644
--- a/src/tools/singlejar/combiners_test.cc
+++ b/src/tools/singlejar/combiners_test.cc
@@ -19,6 +19,8 @@
#include "src/tools/singlejar/zlib_interface.h"
#include "gtest/gtest.h"
+namespace {
+
static const char kTag1Contents[] = "<tag1>Contents1</tag1>";
static const char kTag2Contents[] = "<tag2>Contents2</tag2>";
static const char kCombinedXmlContents[] =
@@ -49,67 +51,6 @@ class CombinersTest : public ::testing::Test {
}
return true;
}
-
- static void TestJava8DesugarDepsChecker_HasDefaultMethods() {
- Java8DesugarDepsChecker checker([](const std::string &) { return false; },
- /*verbose=*/false);
- checker.has_default_methods_["a"] = true;
- checker.extended_interfaces_["c"] = {"b", "a"};
-
- // Induce cycle (shouldn't happen but make sure we don't crash)
- checker.extended_interfaces_["d"] = {"e"};
- checker.extended_interfaces_["e"] = {"d", "a"};
-
- EXPECT_TRUE(checker.HasDefaultMethods("a"));
- EXPECT_FALSE(checker.HasDefaultMethods("b"));
- EXPECT_TRUE(checker.HasDefaultMethods("c")); // Transitivly through a
- EXPECT_TRUE(checker.HasDefaultMethods("d")); // Transitivly through a
- EXPECT_FALSE(checker.error_);
- }
-
- static void TestJava8DesugarDepsChecker_OutputEntry() {
- bool checkedA = false;
- Java8DesugarDepsChecker checker(
- [&checkedA](const std::string &binary_name) {
- checkedA = true;
- return binary_name == "a$$CC.class";
- },
- /*verbose=*/false);
- checker.has_default_methods_["a"] = true;
- checker.extended_interfaces_["b"] = {"c", "d"};
- checker.extended_interfaces_["c"] = {"e"};
- checker.needed_deps_["a$$CC.class"] = "f";
- checker.missing_interfaces_["b"] = "g";
- EXPECT_EQ(nullptr, checker.OutputEntry(/*compress=*/true));
- EXPECT_TRUE(checkedA);
-
- // Make sure we checked b and its extended interfaces for default methods
- EXPECT_FALSE(checker.has_default_methods_.at("b")); // should be cached
- EXPECT_FALSE(checker.has_default_methods_.at("c")); // should be cached
- EXPECT_FALSE(checker.has_default_methods_.at("d")); // should be cached
- EXPECT_FALSE(checker.has_default_methods_.at("e")); // should be cached
- EXPECT_FALSE(checker.error_);
- }
-
- static void TestJava8DesugarDepsChecker_NeededDepMissing() {
- Java8DesugarDepsChecker checker([](const std::string &) { return false; },
- /*verbose=*/false,
- /*fail_on_error=*/false);
- checker.needed_deps_["a$$CC.class"] = "b";
- EXPECT_EQ(nullptr, checker.OutputEntry(/*compress=*/true));
- EXPECT_TRUE(checker.error_);
- }
-
- static void TestJava8DesugarDepsChecker_MissedDefaultMethods() {
- Java8DesugarDepsChecker checker([](const std::string &) { return true; },
- /*verbose=*/false,
- /*fail_on_error=*/false);
- checker.has_default_methods_["b"] = true;
- checker.extended_interfaces_["a"] = {"b", "a"};
- checker.missing_interfaces_["a"] = "g";
- EXPECT_EQ(nullptr, checker.OutputEntry(/*compress=*/true));
- EXPECT_TRUE(checker.error_);
- }
};
// Test Concatenator.
@@ -305,10 +246,4 @@ TEST_F(CombinersTest, PropertyCombiner) {
free(reinterpret_cast<void *>(entry));
}
-TEST_F(CombinersTest, Java8DesugarDepsChecker) {
- // Tests are instance methods of CombinersTest to avoid gUnit dep in .h file.
- TestJava8DesugarDepsChecker_HasDefaultMethods();
- TestJava8DesugarDepsChecker_OutputEntry();
- TestJava8DesugarDepsChecker_NeededDepMissing();
- TestJava8DesugarDepsChecker_MissedDefaultMethods();
-}
+} // anonymous namespace
diff --git a/src/tools/singlejar/desugar_checking.cc b/src/tools/singlejar/desugar_checking.cc
new file mode 100644
index 0000000000..13f45f9583
--- /dev/null
+++ b/src/tools/singlejar/desugar_checking.cc
@@ -0,0 +1,153 @@
+// Copyright 2017 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/singlejar/desugar_checking.h"
+#include "src/tools/singlejar/diag.h"
+#include "src/main/protobuf/desugar_deps.pb.h"
+
+bool Java8DesugarDepsChecker::Merge(const CDH *cdh, const LH *lh) {
+ // Throw away anything previously read, no need to concatenate
+ buffer_.reset(new TransientBytes());
+ if (Z_NO_COMPRESSION == lh->compression_method()) {
+ buffer_->ReadEntryContents(lh);
+ } else if (Z_DEFLATED == lh->compression_method()) {
+ if (!inflater_.get()) {
+ inflater_.reset(new Inflater());
+ }
+ buffer_->DecompressEntryContents(cdh, lh, inflater_.get());
+ } else {
+ errx(2, "META-INF/desugar_deps is neither stored nor deflated");
+ }
+
+ // TODO(kmb): Wrap buffer_ as ZeroCopyInputStream to avoid copying out.
+ // Note we only copy one file at a time, so overhead should be modest.
+ uint32_t checksum;
+ const size_t data_size = buffer_->data_size();
+ uint8_t *buf = reinterpret_cast<uint8_t *>(malloc(data_size));
+ buffer_->CopyOut(reinterpret_cast<uint8_t *>(buf), &checksum);
+ buffer_.reset(); // release buffer eagerly
+
+ bazel::tools::desugar::DesugarDepsInfo deps_info;
+ google::protobuf::io::CodedInputStream content(buf, data_size);
+ if (!deps_info.ParseFromCodedStream(&content)) {
+ errx(2, "META-INF/desugar_deps: unable to parse");
+ }
+ if (!content.ConsumedEntireMessage()) {
+ errx(2, "META-INF/desugar_deps: unexpected trailing content");
+ }
+ free(buf);
+
+ for (const auto &assume_present : deps_info.assume_present()) {
+ // This means we need file named <target>.class in the output. Remember
+ // the first origin of this requirement for error messages, drop others.
+ needed_deps_.emplace(assume_present.target().binary_name() + ".class",
+ assume_present.origin().binary_name());
+ }
+
+ for (const auto &missing : deps_info.missing_interface()) {
+ // Remember the first origin of this requirement for error messages, drop
+ // subsequent ones.
+ missing_interfaces_.emplace(missing.target().binary_name(),
+ missing.origin().binary_name());
+ }
+
+ for (const auto &extends : deps_info.interface_with_supertypes()) {
+ // Remember interface hierarchy the first time we see this interface, drop
+ // subsequent ones for consistency with how singlejar will keep the first
+ // occurrence of the file defining the interface. We'll lazily derive
+ // whether missing_interfaces_ inherit default methods with this data later.
+ if (extends.extended_interface_size() > 0) {
+ std::vector<std::string> extended;
+ extended.reserve(extends.extended_interface_size());
+ for (const auto &itf : extends.extended_interface()) {
+ extended.push_back(itf.binary_name());
+ }
+ extended_interfaces_.emplace(extends.origin().binary_name(),
+ std::move(extended));
+ }
+ }
+
+ for (const auto &companion : deps_info.interface_with_companion()) {
+ // Only remember interfaces that definitely have default methods for now.
+ // For all other interfaces we'll transitively check extended interfaces
+ // in HasDefaultMethods.
+ if (companion.num_default_methods() > 0) {
+ has_default_methods_[companion.origin().binary_name()] = true;
+ }
+ }
+ return true;
+}
+
+void *Java8DesugarDepsChecker::OutputEntry(bool compress) {
+ if (verbose_) {
+ fprintf(stderr, "Needed deps: %lu\n", needed_deps_.size());
+ fprintf(stderr, "Interfaces to check: %lu\n", missing_interfaces_.size());
+ fprintf(stderr, "Sub-interfaces: %lu\n", extended_interfaces_.size());
+ fprintf(stderr, "Interfaces w/ default methods: %lu\n",
+ has_default_methods_.size());
+ }
+ for (auto needed : needed_deps_) {
+ if (verbose_) {
+ fprintf(stderr, "Looking for %s\n", needed.first.c_str());
+ }
+ if (!known_member_(needed.first)) {
+ if (fail_on_error_) {
+ errx(2, "%s referenced by %s but not found. Is the former defined in "
+ "a neverlink library?",
+ needed.first.c_str(), needed.second.c_str());
+ } else {
+ error_ = true;
+ }
+ }
+ }
+
+ for (auto missing : missing_interfaces_) {
+ if (verbose_) {
+ fprintf(stderr, "Checking %s\n", missing.first.c_str());
+ }
+ if (HasDefaultMethods(missing.first)) {
+ if (fail_on_error_) {
+ errx(2, "%s needed on the classpath for desugaring %s. Please add the "
+ "missing dependency to the target containing the latter.",
+ missing.first.c_str(), missing.second.c_str());
+ } else {
+ error_ = true;
+ }
+ }
+ }
+
+ // We don't want these files in the output, just check them for consistency
+ return nullptr;
+}
+
+bool Java8DesugarDepsChecker::HasDefaultMethods(
+ const std::string &interface_name) {
+ auto cached = has_default_methods_.find(interface_name);
+ if (cached != has_default_methods_.end()) {
+ return cached->second;
+ }
+
+ // Prime with false in case there's a cycle. We'll update with the true value
+ // (ignoring the cycle) below.
+ has_default_methods_.emplace(interface_name, false);
+
+ for (const std::string &extended : extended_interfaces_[interface_name]) {
+ if (HasDefaultMethods(extended)) {
+ has_default_methods_[interface_name] = true;
+ return true;
+ }
+ }
+ has_default_methods_[interface_name] = false;
+ return false;
+}
diff --git a/src/tools/singlejar/desugar_checking.h b/src/tools/singlejar/desugar_checking.h
new file mode 100644
index 0000000000..0f913a7816
--- /dev/null
+++ b/src/tools/singlejar/desugar_checking.h
@@ -0,0 +1,85 @@
+// Copyright 2017 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.
+
+#ifndef SRC_TOOLS_SINGLEJAR_DESUGAR_CHECKING_H_
+#define SRC_TOOLS_SINGLEJAR_DESUGAR_CHECKING_H_ 1
+
+#include <functional>
+#include <map>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "src/tools/singlejar/combiners.h"
+#include "src/tools/singlejar/transient_bytes.h"
+#include "src/tools/singlejar/zip_headers.h"
+
+// Combiner that checks META-INF/desugar_deps files (b/65645388) to ensure
+// correct bytecode desugaring, specifically of default and static interface
+// methods, across an entire binary. Two checks are performed:
+// 1. Make sure that any dependency assumed by the desugaring process is in
+// fact part of the binary. This protects against ill-advised uses of
+// neverlink, where a library is only on the compile-time classpath but not
+// the runtime classpath.
+// 2. To paper over incomplete classpaths during desugaring (b/65211436), check
+// that interfaces that couldn't be found don't declare or inherit default
+// methods. Desugar emits extra metadata to avoid us having to open up and
+// parse .class files for this purpose.
+class Java8DesugarDepsChecker : public Combiner {
+ public:
+ Java8DesugarDepsChecker(std::function<bool (const std::string&)> known_member,
+ bool verbose)
+ : Java8DesugarDepsChecker(std::move(known_member), verbose, true) {}
+ ~Java8DesugarDepsChecker() override {}
+
+ bool Merge(const CDH *cdh, const LH *lh) override;
+
+ void *OutputEntry(bool compress) override;
+
+ private:
+ Java8DesugarDepsChecker(std::function<bool (const std::string&)> known_member,
+ bool verbose, bool fail_on_error)
+ : known_member_(std::move(known_member)),
+ verbose_(verbose),
+ fail_on_error_(fail_on_error),
+ error_(false) {}
+ /// Computes and caches whether the given interface has default methods.
+ /// \param interface_name interface name as it would appear in bytecode, e.g.,
+ /// "java/lang/Runnable"
+ bool HasDefaultMethods(const std::string &interface_name);
+
+ const std::function<bool (const std::string&)> known_member_;
+ const bool verbose_;
+ const bool fail_on_error_; // For testing
+
+ std::unique_ptr<TransientBytes> buffer_;
+ std::unique_ptr<Inflater> inflater_;
+ /// Reverse mapping from needed dependencies to one of the users.
+ std::map<std::string, std::string> needed_deps_;
+ /// Reverse mapping from missing interfaces to one of the classes that missed
+ /// them.
+ std::map<std::string, std::string> missing_interfaces_;
+ std::unordered_map<std::string, std::vector<std::string> >
+ extended_interfaces_;
+ /// Cache of interfaces known to definitely define or inherit default methods
+ /// or definitely not define and not inherit default methods. Merge()
+ /// populates initial entries and HasDefaultMethods() adds to the cache as
+ /// needed.
+ std::unordered_map<std::string, bool> has_default_methods_;
+ bool error_;
+
+ friend class Java8DesugarDepsCheckerTest;
+};
+
+#endif // SRC_TOOLS_SINGLEJAR_DESUGAR_CHECKING_H_
diff --git a/src/tools/singlejar/desugar_checking_test.cc b/src/tools/singlejar/desugar_checking_test.cc
new file mode 100644
index 0000000000..faa6686178
--- /dev/null
+++ b/src/tools/singlejar/desugar_checking_test.cc
@@ -0,0 +1,102 @@
+// Copyright 2017 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/singlejar/desugar_checking.h"
+
+#include "src/tools/singlejar/input_jar.h"
+#include "src/tools/singlejar/zip_headers.h"
+#include "src/tools/singlejar/zlib_interface.h"
+#include "gtest/gtest.h"
+
+// A test fixture is used because friend access to class under test is needed.
+// Tests are instance methods to avoid gUnit dep in .h file.
+class Java8DesugarDepsCheckerTest : public ::testing::Test {
+ protected:
+ static void TestHasDefaultMethods() {
+ Java8DesugarDepsChecker checker([](const std::string &) { return false; },
+ /*verbose=*/false);
+ checker.has_default_methods_["a"] = true;
+ checker.extended_interfaces_["c"] = {"b", "a"};
+
+ // Induce cycle (shouldn't happen but make sure we don't crash)
+ checker.extended_interfaces_["d"] = {"e"};
+ checker.extended_interfaces_["e"] = {"d", "a"};
+
+ EXPECT_TRUE(checker.HasDefaultMethods("a"));
+ EXPECT_FALSE(checker.HasDefaultMethods("b"));
+ EXPECT_TRUE(checker.HasDefaultMethods("c")); // Transitivly through a
+ EXPECT_TRUE(checker.HasDefaultMethods("d")); // Transitivly through a
+ EXPECT_FALSE(checker.error_);
+ }
+
+ static void TestOutputEntry() {
+ bool checkedA = false;
+ Java8DesugarDepsChecker checker(
+ [&checkedA](const std::string &binary_name) {
+ checkedA = true;
+ return binary_name == "a$$CC.class";
+ },
+ /*verbose=*/false);
+ checker.has_default_methods_["a"] = true;
+ checker.extended_interfaces_["b"] = {"c", "d"};
+ checker.extended_interfaces_["c"] = {"e"};
+ checker.needed_deps_["a$$CC.class"] = "f";
+ checker.missing_interfaces_["b"] = "g";
+ EXPECT_EQ(nullptr, checker.OutputEntry(/*compress=*/true));
+ EXPECT_TRUE(checkedA);
+
+ // Make sure we checked b and its extended interfaces for default methods
+ EXPECT_FALSE(checker.has_default_methods_.at("b")); // should be cached
+ EXPECT_FALSE(checker.has_default_methods_.at("c")); // should be cached
+ EXPECT_FALSE(checker.has_default_methods_.at("d")); // should be cached
+ EXPECT_FALSE(checker.has_default_methods_.at("e")); // should be cached
+ EXPECT_FALSE(checker.error_);
+ }
+
+ static void TestNeededDepMissing() {
+ Java8DesugarDepsChecker checker([](const std::string &) { return false; },
+ /*verbose=*/false,
+ /*fail_on_error=*/false);
+ checker.needed_deps_["a$$CC.class"] = "b";
+ EXPECT_EQ(nullptr, checker.OutputEntry(/*compress=*/true));
+ EXPECT_TRUE(checker.error_);
+ }
+
+ static void TestMissedDefaultMethods() {
+ Java8DesugarDepsChecker checker([](const std::string &) { return true; },
+ /*verbose=*/false,
+ /*fail_on_error=*/false);
+ checker.has_default_methods_["b"] = true;
+ checker.extended_interfaces_["a"] = {"b", "a"};
+ checker.missing_interfaces_["a"] = "g";
+ EXPECT_EQ(nullptr, checker.OutputEntry(/*compress=*/true));
+ EXPECT_TRUE(checker.error_);
+ }
+};
+
+TEST_F(Java8DesugarDepsCheckerTest, HasDefaultMethods) {
+ TestHasDefaultMethods();
+}
+
+TEST_F(Java8DesugarDepsCheckerTest, OutputEntry) {
+ TestOutputEntry();
+}
+
+TEST_F(Java8DesugarDepsCheckerTest, NeededDepMissing) {
+ TestNeededDepMissing();
+}
+
+TEST_F(Java8DesugarDepsCheckerTest, MissingDefaultMethods) {
+ TestMissedDefaultMethods();
+}
diff --git a/src/tools/singlejar/output_jar.cc b/src/tools/singlejar/output_jar.cc
index 3674d27aee..df158749a6 100644
--- a/src/tools/singlejar/output_jar.cc
+++ b/src/tools/singlejar/output_jar.cc
@@ -89,17 +89,6 @@ int OutputJar::Doit(Options *options) {
EntryInfo{&build_properties_});
}
- // Process or drop Java 8 desugaring metadata, see b/65645388. We don't want
- // or need these files afterwards so make sure we drop them either way.
- Combiner *desugar_checker = options_->check_desugar_deps
- ? new Java8DesugarDepsChecker(
- [this](const std::string &filename) {
- return !NewEntry(filename);
- },
- options_->verbose)
- : (Combiner *)new NullCombiner();
- ExtraCombiner("META-INF/desugar_deps", desugar_checker);
-
build_properties_.AddProperty("build.target", options_->output_jar.c_str());
if (options_->verbose) {
fprintf(stderr, "combined_file_name=%s\n", options_->output_jar.c_str());
diff --git a/src/tools/singlejar/output_jar.h b/src/tools/singlejar/output_jar.h
index 58ae09150a..5917c864e1 100644
--- a/src/tools/singlejar/output_jar.h
+++ b/src/tools/singlejar/output_jar.h
@@ -34,7 +34,7 @@ class OutputJar {
// Constructor.
OutputJar();
// Do all that needs to be done. Can be called only once.
- int Doit(Options *options);
+ virtual int Doit(Options *options);
// Destructor.
virtual ~OutputJar();
// Add a combiner to handle the entries with given name. OutputJar will
diff --git a/src/tools/singlejar/singlejar_main.cc b/src/tools/singlejar/singlejar_main.cc
index 12c52aa094..bc7100f55b 100644
--- a/src/tools/singlejar/singlejar_main.cc
+++ b/src/tools/singlejar/singlejar_main.cc
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tools/singlejar/combiners.h"
+#include "src/tools/singlejar/diag.h"
#include "src/tools/singlejar/options.h"
#include "src/tools/singlejar/output_jar.h"
@@ -19,5 +21,12 @@ int main(int argc, char *argv[]) {
Options options;
options.ParseCommandLine(argc - 1, argv + 1);
OutputJar output_jar;
+ // TODO(b/67733424): support desugar deps checking in Bazel
+ if (options.check_desugar_deps) {
+ diag_errx(1, "%s:%d: Desugar checking not currently supported in Bazel.",
+ __FILE__, __LINE__);
+ } else {
+ output_jar.ExtraCombiner("META-INF/desugar_deps", new NullCombiner());
+ }
return output_jar.Doit(&options);
}