| // 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. |
| |
| |
| #ifndef DEVTOOLS_GOMA_CLIENT_COMPILER_INFO_H_ |
| #define DEVTOOLS_GOMA_CLIENT_COMPILER_INFO_H_ |
| |
| #include <ostream> |
| #include <string> |
| |
| #include "absl/time/time.h" |
| #include "absl/types/optional.h" |
| #include "basictypes.h" |
| #include "compiler_specific.h" |
| #include "file_stat.h" |
| #include "lockhelper.h" |
| #include "sha256_hash_cache.h" |
| |
| MSVC_PUSH_DISABLE_WARNING_FOR_PROTO() |
| #include "prototmp/compiler_info_data.pb.h" |
| MSVC_POP_WARNING() |
| |
| namespace devtools_goma { |
| |
| class CompilerFlags; |
| |
| // The type of CompilerInfo. If a new type of CompilerInfo is required, |
| // you can extend this enum class. |
| enum class CompilerInfoType { |
| Cxx, |
| Javac, |
| Java, |
| Rustc, |
| Fake, |
| }; |
| |
| inline std::ostream& operator<<(std::ostream& os, CompilerInfoType type) { |
| switch (type) { |
| case CompilerInfoType::Cxx: |
| return os << "cxx"; |
| case CompilerInfoType::Javac: |
| return os << "javac"; |
| case CompilerInfoType::Java: |
| return os << "java"; |
| case CompilerInfoType::Rustc: |
| return os << "rustc"; |
| case CompilerInfoType::Fake: |
| return os << "fake"; |
| } |
| |
| return os << "unknown compiler info type: " << static_cast<int>(type); |
| } |
| |
| // CompilerInfo represents how a compiler is configured. |
| // Used as const object. |
| // Most of the data is in CompilerInfoData, which is defined in |
| // compiler_info_data.proto. See also it. |
| class CompilerInfo { |
| public: |
| // SubprogramInfo is an information of subprograms. Subprogram means a program |
| // that is used during compile. For example: "as", "objdump". |
| struct SubprogramInfo { |
| SubprogramInfo() {} |
| static void FromData(const CompilerInfoData::SubprogramInfo& info_data, |
| SubprogramInfo* info); |
| bool IsValid() const { |
| return file_stat.IsValid() && !hash.empty() && |
| !user_specified_path.empty() && !abs_path.empty(); |
| } |
| bool operator==(const SubprogramInfo& rhs) const { |
| return user_specified_path == rhs.user_specified_path && |
| abs_path == rhs.abs_path && hash == rhs.hash && |
| file_stat == rhs.file_stat; |
| } |
| std::string DebugString() const; |
| |
| std::string abs_path; |
| std::string user_specified_path; |
| std::string hash; |
| FileStat file_stat; |
| }; |
| |
| // ResourceInfo is an information of compile resources. A resource means a |
| // file that might be used during compile implicitly. For example: |
| // asan_blacklist.txt for clang with address sanitizer. |
| struct ResourceInfo { |
| ResourceInfo() {} |
| static ResourceInfo FromData( |
| const CompilerInfoData::ResourceInfo& info_data); |
| bool IsValid() const { |
| return file_stat.IsValid() && !hash.empty() && !name.empty(); |
| } |
| bool operator==(const ResourceInfo& rhs) const { |
| return name == rhs.name && type == rhs.type && hash == rhs.hash && |
| file_stat == rhs.file_stat && is_executable == rhs.is_executable && |
| symlink_path == rhs.symlink_path; |
| } |
| std::string DebugString() const; |
| |
| // Returns true if this resource is up to date. |
| // Returns false if not, and set the reason to |reason|. |
| bool IsUpToDate(const std::string& cwd, std::string* reason) const; |
| |
| std::string name; |
| CompilerInfoData::ResourceType type; |
| std::string hash; |
| FileStat file_stat; |
| bool is_executable = false; |
| std::string symlink_path; |
| }; |
| |
| virtual ~CompilerInfo() = default; |
| // Returns compiler info type. |
| virtual CompilerInfoType type() const = 0; |
| |
| std::string DebugString() const; |
| |
| // Returns true if |abs_local_compiler_path| is up to date. |
| // i.e. FileStat of |abs_local_compiler_path| matches |local_compiler_stat|. |
| bool IsUpToDate(const std::string& abs_local_compiler_path) const; |
| |
| // Updates FileStat to the current FileStat when hash is matched. |
| // Returns false if hash doesn't match. |
| bool UpdateFileStatIfHashMatch(SHA256HashCache* sha256_cache); |
| |
| // Returns true if CompilerInfo has some error. |
| bool HasError() const { return data_->has_error_message(); } |
| |
| // Returns true if CompilerInfo content depends on cwd. |
| // compiler path, subprograms paths and resouce paths |
| // can be relative paths. In that case, CompilerInfo content depends on |
| // cwd. |
| // |
| // We say CompilerInfo depends on cwd when one of the followings is |
| // satisfied. |
| // (a) a path is relative |
| // (b) a path starts with cwd |
| // (b) is to cover a path like /path/to/cwd/../../somewhere/to/gcc. |
| virtual bool DependsOnCwd(const std::string& cwd) const; |
| |
| // See field's comment below. |
| const FileStat& local_compiler_stat() const { return local_compiler_stat_; } |
| // See field's comment below. |
| const std::string& local_compiler_path() const { |
| return data_->local_compiler_path(); |
| } |
| // Absolute path of local_compiler_path. Joined with cwd if |
| // local_compiler_path() is relative and resolve. |
| std::string abs_local_compiler_path() const; |
| // See field's comment below. |
| const std::string& local_compiler_hash() const { |
| return data_->local_compiler_hash(); |
| } |
| |
| // See field's comment below. |
| const FileStat& real_compiler_stat() const { return real_compiler_stat_; } |
| // See field's comment below. |
| const std::string& real_compiler_path() const { |
| return data_->real_compiler_path(); |
| } |
| // Absolute path of real_compiler_path. Joined with cwd if |
| // real_compiler_path() is relative and resolve. |
| std::string abs_real_compiler_path() const; |
| // See field's comment below. |
| const std::string& real_compiler_hash() const { return data_->hash(); } |
| |
| // compiler hash to identify the compiler in backend. |
| const std::string& request_compiler_hash() const; |
| |
| // compiler family name. (e.g. gcc, g++, clang, clang++). |
| // For example, if compiler's basename is "x86_64-linux-gcc-7", name will be |
| // "gcc". |
| const std::string& name() const { return data_->name(); } |
| // Returns true if name is defined. |
| bool HasName() const { return data_->has_name(); } |
| |
| // compiler's version. e.g. "4.2.1[clang version 7.0.0 (trunk 338452)]" |
| const std::string& version() const { return data_->version(); } |
| // compiler's target. e.g. "x86_64-pc-linux-gnu" |
| const std::string& target() const { return data_->target(); } |
| // input source's language. e.g. "c++". The compiler will treat the input |
| // language is this. |
| const std::string& lang() const { return data_->lang(); } |
| // If taking CopmilerInfo is failed, error message is stored here. |
| const std::string& error_message() const { return data_->error_message(); } |
| |
| // See field's comment below. |
| const std::vector<std::string>& additional_flags() const { |
| return additional_flags_; |
| } |
| // Returns true if additional flags exist. |
| bool HasAdditionalFlags() const { return !additional_flags_.empty(); } |
| const std::vector<SubprogramInfo>& subprograms() const { |
| return subprograms_; |
| } |
| const std::vector<ResourceInfo>& resource() const { |
| return resource_; |
| } |
| |
| absl::optional<absl::Time> failed_at() const { |
| if (data_->failed_at() == 0) { |
| return absl::nullopt; |
| } |
| return absl::FromTimeT(data_->failed_at()); |
| } |
| |
| absl::Time last_used_at() const; |
| void set_last_used_at(absl::Time t); |
| |
| bool found() const { return data_->found(); } |
| |
| bool IsSameCompiler(const CompilerInfo& ci) const { |
| return data_->target() == ci.data_->target() |
| && data_->version() == ci.data_->version() |
| && data_->lang() == ci.data_->lang() |
| && data_->hash() == ci.data_->hash() |
| && data_->real_compiler_path() == ci.data_->real_compiler_path(); |
| } |
| |
| const CompilerInfoData& data() const { return *data_; } |
| CompilerInfoData* mutable_data() { return data_.get(); } |
| |
| protected: |
| friend class CompilerInfoCacheTest; |
| |
| explicit CompilerInfo(std::unique_ptr<CompilerInfoData> data); |
| |
| // The internal data of CompilerInfo. |
| std::unique_ptr<CompilerInfoData> data_; |
| |
| // Note about "local compiler" and "real compiler". |
| // Some project uses a compiler wrapper (e.g. chromeos). |
| // |
| // For example, "gcc" might be just a python script, and it invokes |
| // a real "gcc". Even the compiler wrapper wasn't changed, the real |
| // compiler might be changed. We have to detect this case. |
| // |
| // When such a wrapper exists, we think the wrapper is "local compiler", |
| // and the real compiler as "real compiler". |
| // |
| // Otherwise, local_compiler and real_compiler are the same. |
| |
| // Local compiler's FileStat. |
| FileStat local_compiler_stat_; |
| // Real compiler's FileStat if real_compiler_path != local_compiler_path. |
| // Otherwise, real_compiler_stat is the same as local_compiler_stat. |
| FileStat real_compiler_stat_; |
| |
| // Additional flags to correct compile arguments in remote. |
| // These flags will be automatically added to compile flags. |
| // e.g. -resource-dir for clang. |
| std::vector<std::string> additional_flags_; |
| |
| // A list of subprograms specified by -B flag. |
| std::vector<SubprogramInfo> subprograms_; |
| |
| // Additional resources that a compiler will use during a compile. |
| // e.g. clang with address sanizier will use |
| // "<resource_dir>/share/asan_blacklist.txt" during a compile. |
| std::vector<ResourceInfo> resource_; |
| |
| // Protects data_->last_used_at. |
| mutable ReadWriteLock last_used_at_mu_; |
| |
| DISALLOW_COPY_AND_ASSIGN(CompilerInfo); |
| }; |
| |
| inline void SetFileStatToData(const FileStat& file_stat, |
| CompilerInfoData::FileStat* data) { |
| // TODO: Use protobuf/timestamp. |
| data->set_mtime(file_stat.mtime ? absl::ToTimeT(*file_stat.mtime) : 0); |
| data->set_size(file_stat.size); |
| data->set_is_directory(file_stat.is_directory); |
| } |
| |
| // NOTE |
| // The default value of CompilerInfoData::FileStat and devtools_goma::FileStat |
| // is incompatible. CompilerInfoData::FileStat is proto message, so the default |
| // values are all 0. However, devtools_goma::FileStat is not. |
| // Before calling this function, you have to check |
| // CompilerInfoData::FileStat really exists. |
| inline void GetFileStatFromData(const CompilerInfoData::FileStat& data, |
| FileStat* file_stat) { |
| file_stat->mtime = absl::FromTimeT(data.mtime()); |
| file_stat->size = data.size(); |
| file_stat->is_directory = data.is_directory(); |
| } |
| |
| } // namespace devtools_goma |
| |
| #endif // DEVTOOLS_GOMA_CLIENT_COMPILER_INFO_H_ |