| // Copyright 2010 The Goma Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| |
| #include "compiler_info.h" |
| |
| #include "absl/strings/str_cat.h" |
| #include "autolock_timer.h" |
| #include "compiler_info_builder.h" |
| #include "gcc_flags.h" |
| #include "glog/logging.h" |
| #include "path.h" |
| #include "path_util.h" |
| |
| namespace devtools_goma { |
| |
| /* static */ |
| void CompilerInfo::SubprogramInfo::FromData( |
| const CompilerInfoData::SubprogramInfo& info_data, |
| SubprogramInfo* info) { |
| info->name = info_data.name(); |
| info->hash = info_data.hash(); |
| GetFileStatFromData(info_data.file_stat(), &info->file_stat); |
| } |
| |
| string CompilerInfo::SubprogramInfo::DebugString() const { |
| std::stringstream ss; |
| ss << "name: " << name; |
| ss << ", valid:" << file_stat.IsValid(); |
| ss << ", hash: " << hash; |
| return ss.str(); |
| } |
| |
| /* static */ |
| CompilerInfo::ResourceInfo CompilerInfo::ResourceInfo::FromData( |
| const CompilerInfoData::ResourceInfo& info_data) { |
| ResourceInfo info; |
| info.name = info_data.name(); |
| info.type = info_data.type(); |
| info.hash = info_data.hash(); |
| GetFileStatFromData(info_data.file_stat(), &info.file_stat); |
| return info; |
| } |
| |
| string CompilerInfo::ResourceInfo::DebugString() const { |
| return absl::StrCat( |
| "name: ", name, ", valid:", file_stat.IsValid(), ", hash: ", hash); |
| } |
| |
| string CompilerInfo::DebugString() const { |
| return data_->DebugString(); |
| } |
| |
| CompilerInfo::CompilerInfo(std::unique_ptr<CompilerInfoData> data) |
| : data_(std::move(data)) { |
| CHECK(data_.get()); |
| GetFileStatFromData(data_->local_compiler_stat(), &local_compiler_stat_); |
| GetFileStatFromData(data_->real_compiler_stat(), &real_compiler_stat_); |
| |
| for (const auto& f : data_->additional_flags()) { |
| additional_flags_.push_back(f); |
| } |
| |
| for (const auto& data : data_->subprograms()) { |
| SubprogramInfo s; |
| SubprogramInfo::FromData(data, &s); |
| subprograms_.push_back(s); |
| } |
| |
| for (const auto& data : data_->resource()) { |
| resource_.emplace_back(ResourceInfo::FromData(data)); |
| } |
| } |
| |
| bool CompilerInfo::IsUpToDate(const string& local_compiler_path) const { |
| FileStat cur_local(local_compiler_path); |
| if (cur_local != local_compiler_stat_) { |
| LOG(INFO) << "compiler id is not matched:" |
| << " path=" << local_compiler_path |
| << " local_compiler_stat=" << local_compiler_stat_.DebugString() |
| << " cur_local=" << cur_local.DebugString(); |
| return false; |
| } |
| if (local_compiler_path != data_->real_compiler_path()) { |
| // Since |local_compiler_path| != |real_compiler_path|, |
| // We need to check that the real compiler is also the same. |
| FileStat cur_real(data_->real_compiler_path()); |
| if (cur_real != real_compiler_stat_) { |
| LOG(INFO) << "real compiler id is not matched:" |
| << " local_compiler_path=" << local_compiler_path |
| << " real_compiler_path=" << data_->real_compiler_path() |
| << " local_compiler_stat=" << local_compiler_stat_.DebugString() |
| << " real_compiler_stat=" << real_compiler_stat_.DebugString() |
| << " cur_real=" << cur_real.DebugString(); |
| return false; |
| } |
| } |
| |
| for (const auto& subprog : subprograms_) { |
| FileStat file_stat(subprog.name); |
| if (file_stat != subprog.file_stat) { |
| LOG(INFO) << "subprogram is not matched:" |
| << " local_compiler_path=" << local_compiler_path |
| << " subprogram=" << subprog.name |
| << " subprogram_file_stat=" << subprog.file_stat.DebugString() |
| << " file_stat=" << file_stat.DebugString(); |
| return false; |
| } |
| } |
| |
| for (const auto& r : resource_) { |
| FileStat file_stat(file::JoinPathRespectAbsolute(data_->cwd(), r.name)); |
| if (file_stat != r.file_stat) { |
| LOG(INFO) << "resouce file is not matched:" |
| << " local_compiler_path=" << local_compiler_path |
| << " resource=" << r.name |
| << " resource_file_stat=" << r.file_stat.DebugString() |
| << " file_stat=" << file_stat.DebugString(); |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| bool CompilerInfo::UpdateFileStatIfHashMatch(SHA256HashCache* sha256_cache) { |
| // Checks real compiler hash and subprogram hash. |
| // If they are all matched, we update FileStat. |
| |
| string local_hash; |
| if (!sha256_cache->GetHashFromCacheOrFile(abs_local_compiler_path(), |
| &local_hash)) { |
| LOG(WARNING) << "calculating local compiler hash failed: " |
| << "path=" << local_compiler_path(); |
| return false; |
| } |
| if (local_hash != local_compiler_hash()) { |
| LOG(INFO) << "local compiler hash didn't match:" |
| << " path=" << local_compiler_path() |
| << " prev=" << local_compiler_hash() |
| << " current=" << local_hash; |
| return false; |
| } |
| |
| string real_hash; |
| if (!sha256_cache->GetHashFromCacheOrFile(real_compiler_path(), &real_hash)) { |
| LOG(WARNING) << "calculating real compiler hash failed: " |
| << "path=" << real_compiler_path(); |
| return false; |
| } |
| if (real_hash != real_compiler_hash()) { |
| LOG(INFO) << "real compiler hash didn't match:" |
| << " path=" << real_compiler_path() |
| << " prev=" << real_compiler_hash() |
| << " current=" << real_hash; |
| return false; |
| } |
| |
| for (const auto& subprog : subprograms_) { |
| string subprogram_hash; |
| if (!sha256_cache->GetHashFromCacheOrFile(subprog.name, &subprogram_hash)) { |
| LOG(WARNING) << "calculating subprogram hash failed: " |
| << "name=" << subprog.name; |
| return false; |
| } |
| if (subprogram_hash != subprog.hash) { |
| LOG(INFO) << "subprogram hash didn't match:" |
| << " path=" << real_compiler_path() |
| << " subprogram=" << subprog.name |
| << " prev=" << subprog.hash |
| << " current=" << subprogram_hash; |
| return false; |
| } |
| } |
| |
| if (subprograms().size() != |
| static_cast<size_t>(data_->subprograms().size())) { |
| LOG(ERROR) << "CompilerInfo subprograms and data subprograms size differs: " |
| << " Inconsistent state: " << data_->real_compiler_path(); |
| return false; |
| } |
| |
| for (size_t i = 0; i < subprograms_.size(); ++i) { |
| const auto& subprog = subprograms_[i]; |
| const auto& data_subprog = data_->subprograms(i); |
| if (subprog.name != data_subprog.name()) { |
| LOG(ERROR) << "CompilerInfo subprogram and its data subprograms" |
| << " is inconsistent: compiler=" << data_->real_compiler_path() |
| << " inconsistent subprogram: " |
| << subprog.name << " != " << data_subprog.name(); |
| return false; |
| } |
| } |
| |
| for (const auto& r : resource_) { |
| string r_hash; |
| if (!sha256_cache->GetHashFromCacheOrFile( |
| file::JoinPathRespectAbsolute(data_->cwd(), r.name), &r_hash)) { |
| LOG(WARNING) << "calculating file hash failed: " |
| << "name=" << r.name; |
| return false; |
| } |
| if (r_hash != r.hash) { |
| LOG(INFO) << "file hash didn't match:" |
| << " path=" << real_compiler_path() |
| << " name=" << r.name |
| << " prev=" << r.hash |
| << " current=" << r_hash; |
| return false; |
| } |
| } |
| |
| if (resource_.size() != |
| static_cast<size_t>(data_->resource().size())) { |
| LOG(ERROR) << "CompilerInfo resource and data resource size differs: " |
| << " Inconsistent state: " << data_->real_compiler_path(); |
| return false; |
| } |
| |
| for (size_t i = 0; i < resource_.size(); ++i) { |
| const auto& r = resource_[i]; |
| const auto& data_r = data_->resource(i); |
| if (r.name != data_r.name()) { |
| LOG(ERROR) << "CompilerInfo resource and its data resource" |
| << " is inconsistent: compiler=" << data_->real_compiler_path() |
| << " inconsistent resource: " |
| << r.name << " != " << data_r.name(); |
| return false; |
| } |
| } |
| |
| // OK. all hash matched. Let's update FileStat. |
| |
| FileStat cur_local(local_compiler_path()); |
| if (cur_local != local_compiler_stat_) { |
| LOG(INFO) << "local_compiler_stat_ is updated:" |
| << " old=" << local_compiler_stat_.DebugString() |
| << " new=" << cur_local.DebugString(); |
| local_compiler_stat_ = cur_local; |
| SetFileStatToData(cur_local, data_->mutable_local_compiler_stat()); |
| } |
| |
| // When |local_compiler_path| == |real_compiler_path|, |
| // local_compiler_stat and real_compiler_stat should be the same. |
| // Otherwise, we take FileStat for real_compiler_path(). |
| FileStat cur_real(cur_local); |
| if (local_compiler_path() != real_compiler_path()) { |
| cur_real = FileStat(real_compiler_path()); |
| } |
| if (cur_real != real_compiler_stat_) { |
| LOG(INFO) << "real_compiler_stat_ is updated:" |
| << " old=" << real_compiler_stat_.DebugString() |
| << " new=" << cur_real.DebugString(); |
| real_compiler_stat_ = cur_real; |
| SetFileStatToData(cur_real, data_->mutable_real_compiler_stat()); |
| } |
| |
| for (size_t i = 0; i < subprograms_.size(); ++i) { |
| auto& subprog = subprograms_[i]; |
| auto* data_subprog = data_->mutable_subprograms(i); |
| |
| FileStat file_stat(subprog.name); |
| if (file_stat != subprog.file_stat) { |
| LOG(INFO) << "subprogram id is updated:" |
| << " name=" << subprog.name |
| << " old=" << subprog.file_stat.DebugString() |
| << " new=" << file_stat.DebugString(); |
| subprog.file_stat = file_stat; |
| SetFileStatToData(file_stat, data_subprog->mutable_file_stat()); |
| } |
| } |
| |
| return true; |
| } |
| |
| bool CompilerInfo::IsCwdRelative(const string& cwd) const { |
| if (HasPrefixDir(data_->real_compiler_path(), cwd)) { |
| VLOG(1) << "real_compiler_path is cwd relative:" |
| << data_->real_compiler_path() |
| << " @" << cwd; |
| return true; |
| } |
| for (size_t i = 0; i < subprograms_.size(); ++i) { |
| const string& name = subprograms_[i].name; |
| if (HasPrefixDir(name, cwd)) { |
| VLOG(1) << "subprograms[" << i << "] is cwd relative: " |
| << name << " @" << cwd; |
| return true; |
| } |
| } |
| for (size_t i = 0; i < resource_.size(); ++i) { |
| if (!file::IsAbsolutePath(resource_[i].name) || |
| HasPrefixDir(resource_[i].name, cwd)) { |
| VLOG(1) << "resource[" << i << "].name is cwd relative:" |
| << resource_[i].name << " @" << cwd; |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| string CompilerInfo::abs_local_compiler_path() const { |
| return file::JoinPathRespectAbsolute( |
| data_->cwd(), data_->local_compiler_path()); |
| } |
| |
| const string& CompilerInfo::request_compiler_hash() const { |
| if (GCCFlags::IsPNaClClangCommand(data_->local_compiler_path())) { |
| return data_->local_compiler_hash(); |
| } |
| return data_->hash(); |
| } |
| |
| time_t CompilerInfo::last_used_at() const { |
| AUTO_SHARED_LOCK(lock, &last_used_at_mu_); |
| return data_->last_used_at(); |
| } |
| |
| void CompilerInfo::set_last_used_at(time_t t) { |
| AUTO_EXCLUSIVE_LOCK(lock, &last_used_at_mu_); |
| data_->set_last_used_at(t); |
| } |
| |
| } // namespace devtools_goma |