// Copyright 2016 The Chromium 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 "tools/gn/visual_studio_writer.h" #include #include #include #include #include #include #include "base/containers/queue.h" #include "base/logging.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "tools/gn/builder.h" #include "tools/gn/commands.h" #include "tools/gn/config.h" #include "tools/gn/config_values_extractors.h" #include "tools/gn/deps_iterator.h" #include "tools/gn/filesystem_utils.h" #include "tools/gn/label_pattern.h" #include "tools/gn/parse_tree.h" #include "tools/gn/path_output.h" #include "tools/gn/source_file_type.h" #include "tools/gn/standard_out.h" #include "tools/gn/target.h" #include "tools/gn/variables.h" #include "tools/gn/visual_studio_utils.h" #include "tools/gn/xml_element_writer.h" #if defined(OS_WIN) #include "base/win/registry.h" #endif namespace { struct SemicolonSeparatedWriter { void operator()(const std::string& value, std::ostream& out) const { out << XmlEscape(value) + ';'; } }; struct IncludeDirWriter { explicit IncludeDirWriter(PathOutput& path_output) : path_output_(path_output) {} ~IncludeDirWriter() = default; void operator()(const SourceDir& dir, std::ostream& out) const { path_output_.WriteDir(out, dir, PathOutput::DIR_NO_LAST_SLASH); out << ";"; } PathOutput& path_output_; }; struct SourceFileWriter { SourceFileWriter(PathOutput& path_output, const SourceFile& source_file) : path_output_(path_output), source_file_(source_file) {} ~SourceFileWriter() = default; void operator()(std::ostream& out) const { path_output_.WriteFile(out, source_file_); } PathOutput& path_output_; const SourceFile& source_file_; }; const char kToolsetVersionVs2013[] = "v120"; // Visual Studio 2013 const char kToolsetVersionVs2015[] = "v140"; // Visual Studio 2015 const char kToolsetVersionVs2017[] = "v141"; // Visual Studio 2017 const char kProjectVersionVs2013[] = "12.0"; // Visual Studio 2013 const char kProjectVersionVs2015[] = "14.0"; // Visual Studio 2015 const char kProjectVersionVs2017[] = "15.0"; // Visual Studio 2017 const char kVersionStringVs2013[] = "Visual Studio 2013"; // Visual Studio 2013 const char kVersionStringVs2015[] = "Visual Studio 2015"; // Visual Studio 2015 const char kVersionStringVs2017[] = "Visual Studio 2017"; // Visual Studio 2017 const char kWindowsKitsVersion[] = "10"; // Windows 10 SDK const char kWindowsKitsDefaultVersion[] = "10.0.17134.0"; // Windows 10 SDK const char kGuidTypeProject[] = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}"; const char kGuidTypeFolder[] = "{2150E333-8FDC-42A3-9474-1A3956D46DE8}"; const char kGuidSeedProject[] = "project"; const char kGuidSeedFolder[] = "folder"; const char kGuidSeedFilter[] = "filter"; const char kConfigurationName[] = "GN"; const char kCharSetUnicode[] = "_UNICODE"; const char kCharSetMultiByte[] = "_MBCS"; std::string GetWindowsKitsIncludeDirs(const std::string& win_kit) { std::string kits_path; #if defined(OS_WIN) const base::char16* const subkeys[] = { L"SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", L"SOFTWARE\\Wow6432Node\\Microsoft\\Windows Kits\\Installed Roots"}; base::string16 value_name = base::ASCIIToUTF16("KitsRoot") + base::ASCIIToUTF16(kWindowsKitsVersion); for (const base::char16* subkey : subkeys) { base::win::RegKey key(HKEY_LOCAL_MACHINE, subkey, KEY_READ); base::string16 value; if (key.ReadValue(value_name.c_str(), &value) == ERROR_SUCCESS) { kits_path = base::UTF16ToUTF8(value); break; } } #endif // OS_WIN if (kits_path.empty()) { kits_path = std::string("C:\\Program Files (x86)\\Windows Kits\\") + kWindowsKitsVersion + "\\"; } const std::string kit_prefix = kits_path + "Include\\" + win_kit + "\\"; return kit_prefix + "shared;" + kit_prefix + "um;" + kit_prefix + "winrt;"; } std::string GetConfigurationType(const Target* target, Err* err) { switch (target->output_type()) { case Target::EXECUTABLE: return "Application"; case Target::SHARED_LIBRARY: case Target::LOADABLE_MODULE: return "DynamicLibrary"; case Target::STATIC_LIBRARY: case Target::SOURCE_SET: return "StaticLibrary"; case Target::GROUP: return "Utility"; default: *err = Err(Location(), "Visual Studio doesn't support '" + target->label().name() + "' target output type: " + Target::GetStringForOutputType(target->output_type())); return std::string(); } } void ParseCompilerOptions(const std::vector& cflags, CompilerOptions* options) { for (const std::string& flag : cflags) ParseCompilerOption(flag, options); } void ParseCompilerOptions(const Target* target, CompilerOptions* options) { for (ConfigValuesIterator iter(target); !iter.done(); iter.Next()) { ParseCompilerOptions(iter.cur().cflags(), options); ParseCompilerOptions(iter.cur().cflags_c(), options); ParseCompilerOptions(iter.cur().cflags_cc(), options); } } void ParseLinkerOptions(const std::vector& ldflags, LinkerOptions* options) { for (const std::string& flag : ldflags) ParseLinkerOption(flag, options); } void ParseLinkerOptions(const Target* target, LinkerOptions* options) { for (ConfigValuesIterator iter(target); !iter.done(); iter.Next()) { ParseLinkerOptions(iter.cur().ldflags(), options); } } // Returns a string piece pointing into the input string identifying the parent // directory path, excluding the last slash. Note that the input pointer must // outlive the output. base::StringPiece FindParentDir(const std::string* path) { DCHECK(path && !path->empty()); for (int i = static_cast(path->size()) - 2; i >= 0; --i) { if (IsSlash((*path)[i])) return base::StringPiece(path->data(), i); } return base::StringPiece(); } bool FilterTargets(const BuildSettings* build_settings, const Builder& builder, const std::string& filters, bool no_deps, std::vector* targets, Err* err) { if (filters.empty()) { *targets = builder.GetAllResolvedTargets(); return true; } std::vector patterns; if (!commands::FilterPatternsFromString(build_settings, filters, &patterns, err)) return false; commands::FilterTargetsByPatterns(builder.GetAllResolvedTargets(), patterns, targets); if (no_deps) return true; std::set