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 <iterator> |
8 #include <map> | 9 #include <map> |
9 #include <memory> | 10 #include <memory> |
10 #include <set> | 11 #include <set> |
11 #include <string> | 12 #include <string> |
12 | 13 |
13 #include "base/logging.h" | 14 #include "base/logging.h" |
14 #include "base/strings/string_split.h" | 15 #include "base/strings/string_split.h" |
15 #include "base/strings/string_util.h" | 16 #include "base/strings/string_util.h" |
16 #include "base/strings/utf_string_conversions.h" | 17 #include "base/strings/utf_string_conversions.h" |
17 #include "tools/gn/builder.h" | 18 #include "tools/gn/builder.h" |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
204 version_string_ = kVersionStringVs2015; | 205 version_string_ = kVersionStringVs2015; |
205 break; | 206 break; |
206 default: | 207 default: |
207 NOTREACHED() << "Not a valid Visual Studio Version: " << version; | 208 NOTREACHED() << "Not a valid Visual Studio Version: " << version; |
208 } | 209 } |
209 | 210 |
210 windows_kits_include_dirs_ = GetWindowsKitsIncludeDirs(); | 211 windows_kits_include_dirs_ = GetWindowsKitsIncludeDirs(); |
211 } | 212 } |
212 | 213 |
213 VisualStudioWriter::~VisualStudioWriter() { | 214 VisualStudioWriter::~VisualStudioWriter() { |
214 STLDeleteContainerPointers(projects_.begin(), projects_.end()); | |
215 STLDeleteContainerPointers(folders_.begin(), folders_.end()); | |
216 } | 215 } |
217 | 216 |
218 // static | 217 // static |
219 bool VisualStudioWriter::RunAndWriteFiles(const BuildSettings* build_settings, | 218 bool VisualStudioWriter::RunAndWriteFiles(const BuildSettings* build_settings, |
220 Builder* builder, | 219 Builder* builder, |
221 Version version, | 220 Version version, |
222 const std::string& sln_name, | 221 const std::string& sln_name, |
223 const std::string& dir_filters, | 222 const std::string& dir_filters, |
224 Err* err) { | 223 Err* err) { |
225 std::vector<const Target*> targets; | 224 std::vector<const Target*> targets; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 } | 273 } |
275 | 274 |
276 if (writer.projects_.empty()) { | 275 if (writer.projects_.empty()) { |
277 *err = Err(Location(), "No Visual Studio projects generated."); | 276 *err = Err(Location(), "No Visual Studio projects generated."); |
278 return false; | 277 return false; |
279 } | 278 } |
280 | 279 |
281 // Sort projects so they appear always in the same order in solution file. | 280 // Sort projects so they appear always in the same order in solution file. |
282 // Otherwise solution file is rewritten and reloaded by Visual Studio. | 281 // Otherwise solution file is rewritten and reloaded by Visual Studio. |
283 std::sort(writer.projects_.begin(), writer.projects_.end(), | 282 std::sort(writer.projects_.begin(), writer.projects_.end(), |
284 [](const SolutionEntry* a, const SolutionEntry* b) { | 283 [](const std::unique_ptr<SolutionProject>& a, |
| 284 const std::unique_ptr<SolutionProject>& b) { |
285 return a->path < b->path; | 285 return a->path < b->path; |
286 }); | 286 }); |
287 | 287 |
288 writer.ResolveSolutionFolders(); | 288 writer.ResolveSolutionFolders(); |
289 return writer.WriteSolutionFile(sln_name, err); | 289 return writer.WriteSolutionFile(sln_name, err); |
290 } | 290 } |
291 | 291 |
292 bool VisualStudioWriter::WriteProjectFiles(const Target* target, Err* err) { | 292 bool VisualStudioWriter::WriteProjectFiles(const Target* target, Err* err) { |
293 std::string project_name = target->label().name(); | 293 std::string project_name = target->label().name(); |
294 const char* project_config_platform = config_platform_; | 294 const char* project_config_platform = config_platform_; |
295 if (!target->settings()->is_default()) { | 295 if (!target->settings()->is_default()) { |
296 project_name += "_" + target->toolchain()->label().name(); | 296 project_name += "_" + target->toolchain()->label().name(); |
297 const Value* value = | 297 const Value* value = |
298 target->settings()->base_config()->GetValue(variables::kCurrentCpu); | 298 target->settings()->base_config()->GetValue(variables::kCurrentCpu); |
299 if (value != nullptr && value->string_value() == "x64") | 299 if (value != nullptr && value->string_value() == "x64") |
300 project_config_platform = "x64"; | 300 project_config_platform = "x64"; |
301 else | 301 else |
302 project_config_platform = "Win32"; | 302 project_config_platform = "Win32"; |
303 } | 303 } |
304 | 304 |
305 SourceFile target_file = GetTargetOutputDir(target).ResolveRelativeFile( | 305 SourceFile target_file = GetTargetOutputDir(target).ResolveRelativeFile( |
306 Value(nullptr, project_name + ".vcxproj"), err); | 306 Value(nullptr, project_name + ".vcxproj"), err); |
307 if (target_file.is_null()) | 307 if (target_file.is_null()) |
308 return false; | 308 return false; |
309 | 309 |
310 base::FilePath vcxproj_path = build_settings_->GetFullPath(target_file); | 310 base::FilePath vcxproj_path = build_settings_->GetFullPath(target_file); |
311 std::string vcxproj_path_str = FilePathToUTF8(vcxproj_path); | 311 std::string vcxproj_path_str = FilePathToUTF8(vcxproj_path); |
312 | 312 |
313 projects_.push_back(new SolutionProject( | 313 projects_.emplace_back(new SolutionProject( |
314 project_name, vcxproj_path_str, | 314 project_name, vcxproj_path_str, |
315 MakeGuid(vcxproj_path_str, kGuidSeedProject), | 315 MakeGuid(vcxproj_path_str, kGuidSeedProject), |
316 FilePathToUTF8(build_settings_->GetFullPath(target->label().dir())), | 316 FilePathToUTF8(build_settings_->GetFullPath(target->label().dir())), |
317 project_config_platform)); | 317 project_config_platform)); |
318 | 318 |
319 std::stringstream vcxproj_string_out; | 319 std::stringstream vcxproj_string_out; |
320 if (!WriteProjectFileContents(vcxproj_string_out, *projects_.back(), target, | 320 if (!WriteProjectFileContents(vcxproj_string_out, *projects_.back(), target, |
321 err)) { | 321 err)) { |
322 projects_.pop_back(); | 322 projects_.pop_back(); |
323 return false; | 323 return false; |
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
641 } | 641 } |
642 | 642 |
643 void VisualStudioWriter::WriteSolutionFileContents( | 643 void VisualStudioWriter::WriteSolutionFileContents( |
644 std::ostream& out, | 644 std::ostream& out, |
645 const base::FilePath& solution_dir_path) { | 645 const base::FilePath& solution_dir_path) { |
646 out << "Microsoft Visual Studio Solution File, Format Version 12.00" | 646 out << "Microsoft Visual Studio Solution File, Format Version 12.00" |
647 << std::endl; | 647 << std::endl; |
648 out << "# " << version_string_ << std::endl; | 648 out << "# " << version_string_ << std::endl; |
649 | 649 |
650 SourceDir solution_dir(FilePathToUTF8(solution_dir_path)); | 650 SourceDir solution_dir(FilePathToUTF8(solution_dir_path)); |
651 for (const SolutionEntry* folder : folders_) { | 651 for (const std::unique_ptr<SolutionEntry>& folder : folders_) { |
652 out << "Project(\"" << kGuidTypeFolder << "\") = \"(" << folder->name | 652 out << "Project(\"" << kGuidTypeFolder << "\") = \"(" << folder->name |
653 << ")\", \"" << RebasePath(folder->path, solution_dir) << "\", \"" | 653 << ")\", \"" << RebasePath(folder->path, solution_dir) << "\", \"" |
654 << folder->guid << "\"" << std::endl; | 654 << folder->guid << "\"" << std::endl; |
655 out << "EndProject" << std::endl; | 655 out << "EndProject" << std::endl; |
656 } | 656 } |
657 | 657 |
658 for (const SolutionEntry* project : projects_) { | 658 for (const std::unique_ptr<SolutionProject>& project : projects_) { |
659 out << "Project(\"" << kGuidTypeProject << "\") = \"" << project->name | 659 out << "Project(\"" << kGuidTypeProject << "\") = \"" << project->name |
660 << "\", \"" << RebasePath(project->path, solution_dir) << "\", \"" | 660 << "\", \"" << RebasePath(project->path, solution_dir) << "\", \"" |
661 << project->guid << "\"" << std::endl; | 661 << project->guid << "\"" << std::endl; |
662 out << "EndProject" << std::endl; | 662 out << "EndProject" << std::endl; |
663 } | 663 } |
664 | 664 |
665 out << "Global" << std::endl; | 665 out << "Global" << std::endl; |
666 | 666 |
667 out << "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution" | 667 out << "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution" |
668 << std::endl; | 668 << std::endl; |
669 const std::string config_mode_prefix = std::string(kConfigurationName) + '|'; | 669 const std::string config_mode_prefix = std::string(kConfigurationName) + '|'; |
670 const std::string config_mode = config_mode_prefix + config_platform_; | 670 const std::string config_mode = config_mode_prefix + config_platform_; |
671 out << "\t\t" << config_mode << " = " << config_mode << std::endl; | 671 out << "\t\t" << config_mode << " = " << config_mode << std::endl; |
672 out << "\tEndGlobalSection" << std::endl; | 672 out << "\tEndGlobalSection" << std::endl; |
673 | 673 |
674 out << "\tGlobalSection(ProjectConfigurationPlatforms) = postSolution" | 674 out << "\tGlobalSection(ProjectConfigurationPlatforms) = postSolution" |
675 << std::endl; | 675 << std::endl; |
676 for (const SolutionProject* project : projects_) { | 676 for (const std::unique_ptr<SolutionProject>& project : projects_) { |
677 const std::string project_config_mode = | 677 const std::string project_config_mode = |
678 config_mode_prefix + project->config_platform; | 678 config_mode_prefix + project->config_platform; |
679 out << "\t\t" << project->guid << '.' << config_mode | 679 out << "\t\t" << project->guid << '.' << config_mode |
680 << ".ActiveCfg = " << project_config_mode << std::endl; | 680 << ".ActiveCfg = " << project_config_mode << std::endl; |
681 out << "\t\t" << project->guid << '.' << config_mode | 681 out << "\t\t" << project->guid << '.' << config_mode |
682 << ".Build.0 = " << project_config_mode << std::endl; | 682 << ".Build.0 = " << project_config_mode << std::endl; |
683 } | 683 } |
684 out << "\tEndGlobalSection" << std::endl; | 684 out << "\tEndGlobalSection" << std::endl; |
685 | 685 |
686 out << "\tGlobalSection(SolutionProperties) = preSolution" << std::endl; | 686 out << "\tGlobalSection(SolutionProperties) = preSolution" << std::endl; |
687 out << "\t\tHideSolutionNode = FALSE" << std::endl; | 687 out << "\t\tHideSolutionNode = FALSE" << std::endl; |
688 out << "\tEndGlobalSection" << std::endl; | 688 out << "\tEndGlobalSection" << std::endl; |
689 | 689 |
690 out << "\tGlobalSection(NestedProjects) = preSolution" << std::endl; | 690 out << "\tGlobalSection(NestedProjects) = preSolution" << std::endl; |
691 for (const SolutionEntry* folder : folders_) { | 691 for (const std::unique_ptr<SolutionEntry>& folder : folders_) { |
692 if (folder->parent_folder) { | 692 if (folder->parent_folder) { |
693 out << "\t\t" << folder->guid << " = " << folder->parent_folder->guid | 693 out << "\t\t" << folder->guid << " = " << folder->parent_folder->guid |
694 << std::endl; | 694 << std::endl; |
695 } | 695 } |
696 } | 696 } |
697 for (const SolutionEntry* project : projects_) { | 697 for (const std::unique_ptr<SolutionProject>& project : projects_) { |
698 out << "\t\t" << project->guid << " = " << project->parent_folder->guid | 698 out << "\t\t" << project->guid << " = " << project->parent_folder->guid |
699 << std::endl; | 699 << std::endl; |
700 } | 700 } |
701 out << "\tEndGlobalSection" << std::endl; | 701 out << "\tEndGlobalSection" << std::endl; |
702 | 702 |
703 out << "EndGlobal" << std::endl; | 703 out << "EndGlobal" << std::endl; |
704 } | 704 } |
705 | 705 |
706 void VisualStudioWriter::ResolveSolutionFolders() { | 706 void VisualStudioWriter::ResolveSolutionFolders() { |
707 root_folder_path_.clear(); | 707 root_folder_path_.clear(); |
708 | 708 |
709 // Get all project directories. Create solution folder for each directory. | 709 // Get all project directories. Create solution folder for each directory. |
710 std::map<base::StringPiece, SolutionEntry*> processed_paths; | 710 std::map<base::StringPiece, SolutionEntry*> processed_paths; |
711 for (SolutionProject* project : projects_) { | 711 for (const std::unique_ptr<SolutionProject>& project : projects_) { |
712 base::StringPiece folder_path = project->label_dir_path; | 712 base::StringPiece folder_path = project->label_dir_path; |
713 if (IsSlash(folder_path[folder_path.size() - 1])) | 713 if (IsSlash(folder_path[folder_path.size() - 1])) |
714 folder_path = folder_path.substr(0, folder_path.size() - 1); | 714 folder_path = folder_path.substr(0, folder_path.size() - 1); |
715 auto it = processed_paths.find(folder_path); | 715 auto it = processed_paths.find(folder_path); |
716 if (it != processed_paths.end()) { | 716 if (it != processed_paths.end()) { |
717 project->parent_folder = it->second; | 717 project->parent_folder = it->second; |
718 } else { | 718 } else { |
719 std::string folder_path_str = folder_path.as_string(); | 719 std::string folder_path_str = folder_path.as_string(); |
720 SolutionEntry* folder = new SolutionEntry( | 720 std::unique_ptr<SolutionEntry> folder(new SolutionEntry( |
721 FindLastDirComponent(SourceDir(folder_path)).as_string(), | 721 FindLastDirComponent(SourceDir(folder_path)).as_string(), |
722 folder_path_str, MakeGuid(folder_path_str, kGuidSeedFolder)); | 722 folder_path_str, MakeGuid(folder_path_str, kGuidSeedFolder))); |
723 folders_.push_back(folder); | 723 project->parent_folder = folder.get(); |
724 project->parent_folder = folder; | 724 processed_paths[folder_path] = folder.get(); |
725 processed_paths[folder_path] = folder; | 725 folders_.push_back(std::move(folder)); |
726 | 726 |
727 if (root_folder_path_.empty()) { | 727 if (root_folder_path_.empty()) { |
728 root_folder_path_ = folder_path_str; | 728 root_folder_path_ = folder_path_str; |
729 } else { | 729 } else { |
730 size_t common_prefix_len = 0; | 730 size_t common_prefix_len = 0; |
731 size_t max_common_length = | 731 size_t max_common_length = |
732 std::min(root_folder_path_.size(), folder_path.size()); | 732 std::min(root_folder_path_.size(), folder_path.size()); |
733 size_t i; | 733 size_t i; |
734 for (i = common_prefix_len; i < max_common_length; ++i) { | 734 for (i = common_prefix_len; i < max_common_length; ++i) { |
735 if (IsSlash(root_folder_path_[i]) && IsSlash(folder_path[i])) | 735 if (IsSlash(root_folder_path_[i]) && IsSlash(folder_path[i])) |
736 common_prefix_len = i + 1; | 736 common_prefix_len = i + 1; |
737 else if (root_folder_path_[i] != folder_path[i]) | 737 else if (root_folder_path_[i] != folder_path[i]) |
738 break; | 738 break; |
739 } | 739 } |
740 if (i == max_common_length && | 740 if (i == max_common_length && |
741 (i == folder_path.size() || IsSlash(folder_path[i]))) | 741 (i == folder_path.size() || IsSlash(folder_path[i]))) |
742 common_prefix_len = max_common_length; | 742 common_prefix_len = max_common_length; |
743 if (common_prefix_len < root_folder_path_.size()) { | 743 if (common_prefix_len < root_folder_path_.size()) { |
744 if (IsSlash(root_folder_path_[common_prefix_len - 1])) | 744 if (IsSlash(root_folder_path_[common_prefix_len - 1])) |
745 --common_prefix_len; | 745 --common_prefix_len; |
746 root_folder_path_ = root_folder_path_.substr(0, common_prefix_len); | 746 root_folder_path_ = root_folder_path_.substr(0, common_prefix_len); |
747 } | 747 } |
748 } | 748 } |
749 } | 749 } |
750 } | 750 } |
751 | 751 |
752 // Create also all parent folders up to |root_folder_path_|. | 752 // Create also all parent folders up to |root_folder_path_|. |
753 SolutionFolders additional_folders; | 753 SolutionFolders additional_folders; |
754 for (SolutionEntry* folder : folders_) { | 754 for (const std::unique_ptr<SolutionEntry>& solution_folder : folders_) { |
755 if (folder->path == root_folder_path_) | 755 if (solution_folder->path == root_folder_path_) |
756 continue; | 756 continue; |
757 | 757 |
| 758 SolutionEntry* folder = solution_folder.get(); |
758 base::StringPiece parent_path; | 759 base::StringPiece parent_path; |
759 while ((parent_path = FindParentDir(&folder->path)) != root_folder_path_) { | 760 while ((parent_path = FindParentDir(&folder->path)) != root_folder_path_) { |
760 auto it = processed_paths.find(parent_path); | 761 auto it = processed_paths.find(parent_path); |
761 if (it != processed_paths.end()) { | 762 if (it != processed_paths.end()) { |
762 folder = it->second; | 763 folder = it->second; |
763 } else { | 764 } else { |
764 folder = new SolutionEntry( | 765 std::unique_ptr<SolutionEntry> new_folder(new SolutionEntry( |
765 FindLastDirComponent(SourceDir(parent_path)).as_string(), | 766 FindLastDirComponent(SourceDir(parent_path)).as_string(), |
766 parent_path.as_string(), | 767 parent_path.as_string(), |
767 MakeGuid(parent_path.as_string(), kGuidSeedFolder)); | 768 MakeGuid(parent_path.as_string(), kGuidSeedFolder))); |
768 additional_folders.push_back(folder); | 769 processed_paths[parent_path] = new_folder.get(); |
769 processed_paths[parent_path] = folder; | 770 folder = new_folder.get(); |
| 771 additional_folders.push_back(std::move(new_folder)); |
770 } | 772 } |
771 } | 773 } |
772 } | 774 } |
773 folders_.insert(folders_.end(), additional_folders.begin(), | 775 folders_.insert(folders_.end(), |
774 additional_folders.end()); | 776 std::make_move_iterator(additional_folders.begin()), |
| 777 std::make_move_iterator(additional_folders.end())); |
775 | 778 |
776 // Sort folders by path. | 779 // Sort folders by path. |
777 std::sort(folders_.begin(), folders_.end(), | 780 std::sort(folders_.begin(), folders_.end(), |
778 [](const SolutionEntry* a, const SolutionEntry* b) { | 781 [](const std::unique_ptr<SolutionEntry>& a, |
| 782 const std::unique_ptr<SolutionEntry>& b) { |
779 return a->path < b->path; | 783 return a->path < b->path; |
780 }); | 784 }); |
781 | 785 |
782 // Match subfolders with their parents. Since |folders_| are sorted by path we | 786 // Match subfolders with their parents. Since |folders_| are sorted by path we |
783 // know that parent folder always precedes its children in vector. | 787 // know that parent folder always precedes its children in vector. |
784 SolutionFolders parents; | 788 std::vector<SolutionEntry*> parents; |
785 for (SolutionEntry* folder : folders_) { | 789 for (const std::unique_ptr<SolutionEntry>& folder : folders_) { |
786 while (!parents.empty()) { | 790 while (!parents.empty()) { |
787 if (base::StartsWith(folder->path, parents.back()->path, | 791 if (base::StartsWith(folder->path, parents.back()->path, |
788 base::CompareCase::SENSITIVE)) { | 792 base::CompareCase::SENSITIVE)) { |
789 folder->parent_folder = parents.back(); | 793 folder->parent_folder = parents.back(); |
790 break; | 794 break; |
791 } else { | 795 } else { |
792 parents.pop_back(); | 796 parents.pop_back(); |
793 } | 797 } |
794 } | 798 } |
795 parents.push_back(folder); | 799 parents.push_back(folder.get()); |
796 } | 800 } |
797 } | 801 } |
798 | 802 |
799 std::string VisualStudioWriter::GetNinjaTarget(const Target* target) { | 803 std::string VisualStudioWriter::GetNinjaTarget(const Target* target) { |
800 std::ostringstream ninja_target_out; | 804 std::ostringstream ninja_target_out; |
801 DCHECK(!target->dependency_output_file().value().empty()); | 805 DCHECK(!target->dependency_output_file().value().empty()); |
802 ninja_path_output_.WriteFile(ninja_target_out, | 806 ninja_path_output_.WriteFile(ninja_target_out, |
803 target->dependency_output_file()); | 807 target->dependency_output_file()); |
804 return ninja_target_out.str(); | 808 return ninja_target_out.str(); |
805 } | 809 } |
OLD | NEW |