| 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 |