From db1426b75d7721554a8b139696b5b4c400a260a5 Mon Sep 17 00:00:00 2001 From: kmb Date: Sat, 21 Oct 2017 04:07:24 +0200 Subject: 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 --- src/tools/singlejar/desugar_checking.cc | 153 ++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 src/tools/singlejar/desugar_checking.cc (limited to 'src/tools/singlejar/desugar_checking.cc') 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(malloc(data_size)); + buffer_->CopyOut(reinterpret_cast(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 .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 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; +} -- cgit v1.2.3