OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "tools/gn/visual_studio_writer.h" | 5 #include "tools/gn/visual_studio_writer.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <map> | 8 #include <map> |
9 #include <set> | 9 #include <set> |
10 #include <string> | 10 #include <string> |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
175 | 175 |
176 } // namespace | 176 } // namespace |
177 | 177 |
178 VisualStudioWriter::SolutionEntry::SolutionEntry(const std::string& _name, | 178 VisualStudioWriter::SolutionEntry::SolutionEntry(const std::string& _name, |
179 const std::string& _path, | 179 const std::string& _path, |
180 const std::string& _guid) | 180 const std::string& _guid) |
181 : name(_name), path(_path), guid(_guid), parent_folder(nullptr) {} | 181 : name(_name), path(_path), guid(_guid), parent_folder(nullptr) {} |
182 | 182 |
183 VisualStudioWriter::SolutionEntry::~SolutionEntry() = default; | 183 VisualStudioWriter::SolutionEntry::~SolutionEntry() = default; |
184 | 184 |
| 185 VisualStudioWriter::SolutionProject::SolutionProject( |
| 186 const std::string& _name, |
| 187 const std::string& _path, |
| 188 const std::string& _guid, |
| 189 const std::string& _label_dir_path, |
| 190 const std::string& _config_platform) |
| 191 : SolutionEntry(_name, _path, _guid), |
| 192 label_dir_path(_label_dir_path), |
| 193 config_platform(_config_platform) {} |
| 194 |
| 195 VisualStudioWriter::SolutionProject::~SolutionProject() = default; |
| 196 |
185 VisualStudioWriter::VisualStudioWriter(const BuildSettings* build_settings) | 197 VisualStudioWriter::VisualStudioWriter(const BuildSettings* build_settings) |
186 : build_settings_(build_settings) { | 198 : build_settings_(build_settings) { |
187 const Value* value = build_settings->build_args().GetArgOverride("is_debug"); | 199 const Value* value = build_settings->build_args().GetArgOverride("is_debug"); |
188 is_debug_config_ = value == nullptr || value->boolean_value(); | 200 is_debug_config_ = value == nullptr || value->boolean_value(); |
189 config_platform_ = "Win32"; | 201 config_platform_ = "Win32"; |
190 value = build_settings->build_args().GetArgOverride(variables::kTargetCpu); | 202 value = build_settings->build_args().GetArgOverride(variables::kTargetCpu); |
191 if (value != nullptr && value->string_value() == "x64") | 203 if (value != nullptr && value->string_value() == "x64") |
192 config_platform_ = "x64"; | 204 config_platform_ = "x64"; |
193 | 205 |
194 windows_kits_include_dirs_ = GetWindowsKitsIncludeDirs(); | 206 windows_kits_include_dirs_ = GetWindowsKitsIncludeDirs(); |
195 } | 207 } |
196 | 208 |
197 VisualStudioWriter::~VisualStudioWriter() { | 209 VisualStudioWriter::~VisualStudioWriter() { |
198 STLDeleteContainerPointers(projects_.begin(), projects_.end()); | 210 STLDeleteContainerPointers(projects_.begin(), projects_.end()); |
199 STLDeleteContainerPointers(folders_.begin(), folders_.end()); | 211 STLDeleteContainerPointers(folders_.begin(), folders_.end()); |
200 } | 212 } |
201 | 213 |
202 // static | 214 // static |
203 bool VisualStudioWriter::RunAndWriteFiles(const BuildSettings* build_settings, | 215 bool VisualStudioWriter::RunAndWriteFiles(const BuildSettings* build_settings, |
204 Builder* builder, | 216 Builder* builder, |
205 Err* err) { | 217 Err* err) { |
206 std::vector<const Target*> targets = builder->GetAllResolvedTargets(); | 218 std::vector<const Target*> targets = builder->GetAllResolvedTargets(); |
207 | 219 |
208 VisualStudioWriter writer(build_settings); | 220 VisualStudioWriter writer(build_settings); |
209 writer.projects_.reserve(targets.size()); | 221 writer.projects_.reserve(targets.size()); |
210 writer.folders_.reserve(targets.size()); | 222 writer.folders_.reserve(targets.size()); |
211 | 223 |
212 std::set<std::string> processed_targets; | |
213 for (const Target* target : targets) { | 224 for (const Target* target : targets) { |
214 // Skip targets which are duplicated in vector. | |
215 std::string target_path = | |
216 target->label().dir().value() + target->label().name(); | |
217 if (processed_targets.find(target_path) != processed_targets.end()) | |
218 continue; | |
219 | |
220 // Skip actions and groups. | 225 // Skip actions and groups. |
221 if (target->output_type() == Target::GROUP || | 226 if (target->output_type() == Target::GROUP || |
222 target->output_type() == Target::COPY_FILES || | 227 target->output_type() == Target::COPY_FILES || |
223 target->output_type() == Target::ACTION || | 228 target->output_type() == Target::ACTION || |
224 target->output_type() == Target::ACTION_FOREACH) { | 229 target->output_type() == Target::ACTION_FOREACH) { |
225 continue; | 230 continue; |
226 } | 231 } |
227 | 232 |
228 if (!writer.WriteProjectFiles(target, err)) | 233 if (!writer.WriteProjectFiles(target, err)) |
229 return false; | 234 return false; |
230 | |
231 processed_targets.insert(target_path); | |
232 } | 235 } |
233 | 236 |
234 if (writer.projects_.empty()) { | 237 if (writer.projects_.empty()) { |
235 *err = Err(Location(), "No Visual Studio projects generated."); | 238 *err = Err(Location(), "No Visual Studio projects generated."); |
236 return false; | 239 return false; |
237 } | 240 } |
238 | 241 |
239 writer.ResolveSolutionFolders(); | 242 writer.ResolveSolutionFolders(); |
240 return writer.WriteSolutionFile(err); | 243 return writer.WriteSolutionFile(err); |
241 } | 244 } |
242 | 245 |
243 bool VisualStudioWriter::WriteProjectFiles(const Target* target, Err* err) { | 246 bool VisualStudioWriter::WriteProjectFiles(const Target* target, Err* err) { |
| 247 std::string project_name = target->label().name(); |
| 248 std::string project_config_platform = config_platform_; |
| 249 if (!target->settings()->is_default()) { |
| 250 project_name += "_" + target->toolchain()->label().name(); |
| 251 project_config_platform = target->toolchain() |
| 252 ->settings() |
| 253 ->build_settings() |
| 254 ->build_args() |
| 255 .GetArgOverride(variables::kCurrentCpu) |
| 256 ->string_value(); |
| 257 if (project_config_platform == "x86") |
| 258 project_config_platform = "Win32"; |
| 259 } |
| 260 |
244 SourceFile target_file = GetTargetOutputDir(target).ResolveRelativeFile( | 261 SourceFile target_file = GetTargetOutputDir(target).ResolveRelativeFile( |
245 Value(nullptr, target->label().name() + ".vcxproj"), err); | 262 Value(nullptr, project_name + ".vcxproj"), err); |
246 if (target_file.is_null()) | 263 if (target_file.is_null()) |
247 return false; | 264 return false; |
248 | 265 |
249 base::FilePath vcxproj_path = build_settings_->GetFullPath(target_file); | 266 base::FilePath vcxproj_path = build_settings_->GetFullPath(target_file); |
250 std::string vcxproj_path_str = FilePathToUTF8(vcxproj_path); | 267 std::string vcxproj_path_str = FilePathToUTF8(vcxproj_path); |
251 | 268 |
252 projects_.push_back( | 269 projects_.push_back(new SolutionProject( |
253 new SolutionEntry(target->label().name(), vcxproj_path_str, | 270 project_name, vcxproj_path_str, |
254 MakeGuid(vcxproj_path_str, kGuidSeedProject))); | 271 MakeGuid(vcxproj_path_str, kGuidSeedProject), |
255 projects_.back()->label_dir_path = | 272 FilePathToUTF8(build_settings_->GetFullPath(target->label().dir())), |
256 FilePathToUTF8(build_settings_->GetFullPath(target->label().dir())); | 273 project_config_platform)); |
257 | 274 |
258 std::stringstream vcxproj_string_out; | 275 std::stringstream vcxproj_string_out; |
259 if (!WriteProjectFileContents(vcxproj_string_out, *projects_.back(), target, | 276 if (!WriteProjectFileContents(vcxproj_string_out, *projects_.back(), target, |
260 err)) { | 277 err)) { |
261 projects_.pop_back(); | 278 projects_.pop_back(); |
262 return false; | 279 return false; |
263 } | 280 } |
264 | 281 |
265 // Only write the content to the file if it's different. That is | 282 // Only write the content to the file if it's different. That is |
266 // both a performance optimization and more importantly, prevents | 283 // both a performance optimization and more importantly, prevents |
(...skipping 21 matching lines...) Expand all Loading... |
288 ".vcxproj.filters for writing"); | 305 ".vcxproj.filters for writing"); |
289 return false; | 306 return false; |
290 } | 307 } |
291 } | 308 } |
292 | 309 |
293 return true; | 310 return true; |
294 } | 311 } |
295 | 312 |
296 bool VisualStudioWriter::WriteProjectFileContents( | 313 bool VisualStudioWriter::WriteProjectFileContents( |
297 std::ostream& out, | 314 std::ostream& out, |
298 const SolutionEntry& solution_project, | 315 const SolutionProject& solution_project, |
299 const Target* target, | 316 const Target* target, |
300 Err* err) { | 317 Err* err) { |
301 PathOutput path_output(GetTargetOutputDir(target), | 318 PathOutput path_output(GetTargetOutputDir(target), |
302 build_settings_->root_path_utf8(), | 319 build_settings_->root_path_utf8(), |
303 EscapingMode::ESCAPE_NONE); | 320 EscapingMode::ESCAPE_NONE); |
304 | 321 |
305 out << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << std::endl; | 322 out << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << std::endl; |
306 XmlElementWriter project( | 323 XmlElementWriter project( |
307 out, "Project", | 324 out, "Project", |
308 XmlAttributes("DefaultTargets", "Build") | 325 XmlAttributes("DefaultTargets", "Build") |
309 .add("ToolsVersion", kVisualStudioVersion) | 326 .add("ToolsVersion", kVisualStudioVersion) |
310 .add("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003")); | 327 .add("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003")); |
311 | 328 |
312 { | 329 { |
313 scoped_ptr<XmlElementWriter> configurations = project.SubElement( | 330 scoped_ptr<XmlElementWriter> configurations = project.SubElement( |
314 "ItemGroup", XmlAttributes("Label", "ProjectConfigurations")); | 331 "ItemGroup", XmlAttributes("Label", "ProjectConfigurations")); |
315 std::string config_name = is_debug_config_ ? "Debug" : "Release"; | 332 std::string config_name = is_debug_config_ ? "Debug" : "Release"; |
316 scoped_ptr<XmlElementWriter> project_config = configurations->SubElement( | 333 scoped_ptr<XmlElementWriter> project_config = configurations->SubElement( |
317 "ProjectConfiguration", | 334 "ProjectConfiguration", |
318 XmlAttributes("Include", config_name + '|' + config_platform_)); | 335 XmlAttributes("Include", |
| 336 config_name + '|' + solution_project.config_platform)); |
319 project_config->SubElement("Configuration")->Text(config_name); | 337 project_config->SubElement("Configuration")->Text(config_name); |
320 project_config->SubElement("Platform")->Text(config_platform_); | 338 project_config->SubElement("Platform") |
| 339 ->Text(solution_project.config_platform); |
321 } | 340 } |
322 | 341 |
323 { | 342 { |
324 scoped_ptr<XmlElementWriter> globals = | 343 scoped_ptr<XmlElementWriter> globals = |
325 project.SubElement("PropertyGroup", XmlAttributes("Label", "Globals")); | 344 project.SubElement("PropertyGroup", XmlAttributes("Label", "Globals")); |
326 globals->SubElement("ProjectGuid")->Text(solution_project.guid); | 345 globals->SubElement("ProjectGuid")->Text(solution_project.guid); |
327 globals->SubElement("Keyword")->Text("Win32Proj"); | 346 globals->SubElement("Keyword")->Text("Win32Proj"); |
328 globals->SubElement("RootNamespace")->Text(target->label().name()); | 347 globals->SubElement("RootNamespace")->Text(target->label().name()); |
329 globals->SubElement("IgnoreWarnCompileDuplicatedFilename")->Text("true"); | 348 globals->SubElement("IgnoreWarnCompileDuplicatedFilename")->Text("true"); |
330 globals->SubElement("PreferredToolArchitecture")->Text("x64"); | 349 globals->SubElement("PreferredToolArchitecture")->Text("x64"); |
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
618 out << "Project(\"" << kGuidTypeProject << "\") = \"" << project->name | 637 out << "Project(\"" << kGuidTypeProject << "\") = \"" << project->name |
619 << "\", \"" << RebasePath(project->path, solution_dir, "/") << "\", \"" | 638 << "\", \"" << RebasePath(project->path, solution_dir, "/") << "\", \"" |
620 << project->guid << "\"" << std::endl; | 639 << project->guid << "\"" << std::endl; |
621 out << "EndProject" << std::endl; | 640 out << "EndProject" << std::endl; |
622 } | 641 } |
623 | 642 |
624 out << "Global" << std::endl; | 643 out << "Global" << std::endl; |
625 | 644 |
626 out << "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution" | 645 out << "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution" |
627 << std::endl; | 646 << std::endl; |
628 const std::string config_mode = | 647 const std::string config_mode_prefix = |
629 std::string(is_debug_config_ ? "Debug" : "Release") + '|' + | 648 std::string(is_debug_config_ ? "Debug" : "Release") + '|'; |
630 config_platform_; | 649 const std::string config_mode = config_mode_prefix + config_platform_; |
631 out << "\t\t" << config_mode << " = " << config_mode << std::endl; | 650 out << "\t\t" << config_mode << " = " << config_mode << std::endl; |
632 out << "\tEndGlobalSection" << std::endl; | 651 out << "\tEndGlobalSection" << std::endl; |
633 | 652 |
634 out << "\tGlobalSection(ProjectConfigurationPlatforms) = postSolution" | 653 out << "\tGlobalSection(ProjectConfigurationPlatforms) = postSolution" |
635 << std::endl; | 654 << std::endl; |
636 for (const SolutionEntry* project : projects_) { | 655 for (const SolutionProject* project : projects_) { |
| 656 const std::string project_config_mode = |
| 657 config_mode_prefix + project->config_platform; |
637 out << "\t\t" << project->guid << '.' << config_mode | 658 out << "\t\t" << project->guid << '.' << config_mode |
638 << ".ActiveCfg = " << config_mode << std::endl; | 659 << ".ActiveCfg = " << project_config_mode << std::endl; |
639 out << "\t\t" << project->guid << '.' << config_mode | 660 out << "\t\t" << project->guid << '.' << config_mode |
640 << ".Build.0 = " << config_mode << std::endl; | 661 << ".Build.0 = " << project_config_mode << std::endl; |
641 } | 662 } |
642 out << "\tEndGlobalSection" << std::endl; | 663 out << "\tEndGlobalSection" << std::endl; |
643 | 664 |
644 out << "\tGlobalSection(SolutionProperties) = preSolution" << std::endl; | 665 out << "\tGlobalSection(SolutionProperties) = preSolution" << std::endl; |
645 out << "\t\tHideSolutionNode = FALSE" << std::endl; | 666 out << "\t\tHideSolutionNode = FALSE" << std::endl; |
646 out << "\tEndGlobalSection" << std::endl; | 667 out << "\tEndGlobalSection" << std::endl; |
647 | 668 |
648 out << "\tGlobalSection(NestedProjects) = preSolution" << std::endl; | 669 out << "\tGlobalSection(NestedProjects) = preSolution" << std::endl; |
649 for (const SolutionEntry* folder : folders_) { | 670 for (const SolutionEntry* folder : folders_) { |
650 if (folder->parent_folder) { | 671 if (folder->parent_folder) { |
651 out << "\t\t" << folder->guid << " = " << folder->parent_folder->guid | 672 out << "\t\t" << folder->guid << " = " << folder->parent_folder->guid |
652 << std::endl; | 673 << std::endl; |
653 } | 674 } |
654 } | 675 } |
655 for (const SolutionEntry* project : projects_) { | 676 for (const SolutionEntry* project : projects_) { |
656 out << "\t\t" << project->guid << " = " << project->parent_folder->guid | 677 out << "\t\t" << project->guid << " = " << project->parent_folder->guid |
657 << std::endl; | 678 << std::endl; |
658 } | 679 } |
659 out << "\tEndGlobalSection" << std::endl; | 680 out << "\tEndGlobalSection" << std::endl; |
660 | 681 |
661 out << "EndGlobal" << std::endl; | 682 out << "EndGlobal" << std::endl; |
662 } | 683 } |
663 | 684 |
664 void VisualStudioWriter::ResolveSolutionFolders() { | 685 void VisualStudioWriter::ResolveSolutionFolders() { |
665 root_folder_path_.clear(); | 686 root_folder_path_.clear(); |
666 | 687 |
667 // Get all project directories. Create solution folder for each directory. | 688 // Get all project directories. Create solution folder for each directory. |
668 std::map<base::StringPiece, SolutionEntry*> processed_paths; | 689 std::map<base::StringPiece, SolutionEntry*> processed_paths; |
669 for (SolutionEntry* project : projects_) { | 690 for (SolutionProject* project : projects_) { |
670 base::StringPiece folder_path = project->label_dir_path; | 691 base::StringPiece folder_path = project->label_dir_path; |
671 if (IsSlash(folder_path[folder_path.size() - 1])) | 692 if (IsSlash(folder_path[folder_path.size() - 1])) |
672 folder_path = folder_path.substr(0, folder_path.size() - 1); | 693 folder_path = folder_path.substr(0, folder_path.size() - 1); |
673 auto it = processed_paths.find(folder_path); | 694 auto it = processed_paths.find(folder_path); |
674 if (it != processed_paths.end()) { | 695 if (it != processed_paths.end()) { |
675 project->parent_folder = it->second; | 696 project->parent_folder = it->second; |
676 } else { | 697 } else { |
677 std::string folder_path_str = folder_path.as_string(); | 698 std::string folder_path_str = folder_path.as_string(); |
678 SolutionEntry* folder = new SolutionEntry( | 699 SolutionEntry* folder = new SolutionEntry( |
679 FindLastDirComponent(SourceDir(folder_path)).as_string(), | 700 FindLastDirComponent(SourceDir(folder_path)).as_string(), |
(...skipping 20 matching lines...) Expand all Loading... |
700 if (common_prefix_len < root_folder_path_.size()) { | 721 if (common_prefix_len < root_folder_path_.size()) { |
701 if (IsSlash(root_folder_path_[common_prefix_len - 1])) | 722 if (IsSlash(root_folder_path_[common_prefix_len - 1])) |
702 --common_prefix_len; | 723 --common_prefix_len; |
703 root_folder_path_ = root_folder_path_.substr(0, common_prefix_len); | 724 root_folder_path_ = root_folder_path_.substr(0, common_prefix_len); |
704 } | 725 } |
705 } | 726 } |
706 } | 727 } |
707 } | 728 } |
708 | 729 |
709 // Create also all parent folders up to |root_folder_path_|. | 730 // Create also all parent folders up to |root_folder_path_|. |
710 SolutionEntries additional_folders; | 731 SolutionFolders additional_folders; |
711 for (SolutionEntry* folder : folders_) { | 732 for (SolutionEntry* folder : folders_) { |
712 if (folder->path == root_folder_path_) | 733 if (folder->path == root_folder_path_) |
713 continue; | 734 continue; |
714 | 735 |
715 base::StringPiece parent_path; | 736 base::StringPiece parent_path; |
716 while ((parent_path = FindParentDir(&folder->path)) != root_folder_path_) { | 737 while ((parent_path = FindParentDir(&folder->path)) != root_folder_path_) { |
717 auto it = processed_paths.find(parent_path); | 738 auto it = processed_paths.find(parent_path); |
718 if (it != processed_paths.end()) { | 739 if (it != processed_paths.end()) { |
719 folder = it->second; | 740 folder = it->second; |
720 } else { | 741 } else { |
(...skipping 10 matching lines...) Expand all Loading... |
731 additional_folders.end()); | 752 additional_folders.end()); |
732 | 753 |
733 // Sort folders by path. | 754 // Sort folders by path. |
734 std::sort(folders_.begin(), folders_.end(), | 755 std::sort(folders_.begin(), folders_.end(), |
735 [](const SolutionEntry* a, const SolutionEntry* b) { | 756 [](const SolutionEntry* a, const SolutionEntry* b) { |
736 return a->path < b->path; | 757 return a->path < b->path; |
737 }); | 758 }); |
738 | 759 |
739 // Match subfolders with their parents. Since |folders_| are sorted by path we | 760 // Match subfolders with their parents. Since |folders_| are sorted by path we |
740 // know that parent folder always precedes its children in vector. | 761 // know that parent folder always precedes its children in vector. |
741 SolutionEntries parents; | 762 SolutionFolders parents; |
742 for (SolutionEntry* folder : folders_) { | 763 for (SolutionEntry* folder : folders_) { |
743 while (!parents.empty()) { | 764 while (!parents.empty()) { |
744 if (base::StartsWith(folder->path, parents.back()->path, | 765 if (base::StartsWith(folder->path, parents.back()->path, |
745 base::CompareCase::SENSITIVE)) { | 766 base::CompareCase::SENSITIVE)) { |
746 folder->parent_folder = parents.back(); | 767 folder->parent_folder = parents.back(); |
747 break; | 768 break; |
748 } else { | 769 } else { |
749 parents.pop_back(); | 770 parents.pop_back(); |
750 } | 771 } |
751 } | 772 } |
752 parents.push_back(folder); | 773 parents.push_back(folder); |
753 } | 774 } |
754 } | 775 } |
OLD | NEW |