Browse Source

Merge topic 'vs-startup-project'

ad140c6e VS: Put ALL_BUILD in the PREDEFINED_TARGETS_FOLDER
f069be05 VS: Fix default target support for targets nested inside a folder
c05ea485 VS: Improve unit test macros
78ec0461 VS: Add option to choose the `.sln` startup project (#15578)
Brad King 9 years ago
parent
commit
5b2acf6c1c

+ 1 - 0
Help/manual/cmake-properties.7.rst

@@ -76,6 +76,7 @@ Properties on Directories
    /prop_dir/VARIABLES
    /prop_dir/VS_GLOBAL_SECTION_POST_section
    /prop_dir/VS_GLOBAL_SECTION_PRE_section
+   /prop_dir/VS_STARTUP_PROJECT
 
 .. _`Target Properties`:
 

+ 12 - 0
Help/prop_dir/VS_STARTUP_PROJECT.rst

@@ -0,0 +1,12 @@
+VS_STARTUP_PROJECT
+------------------
+
+Specify the default startup project in a Visual Studio solution.
+
+The property must be set to the name of an existing target.  This
+will cause that project to be listed first in the generated solution
+file causing Visual Studio to make it the startup project if the
+solution has never been opened before.
+
+If this property is not specified, then the "ALL_BUILD" project
+will be the default.

+ 6 - 0
Help/release/dev/vs-startup-project.rst

@@ -0,0 +1,6 @@
+vs-startup-project
+------------------
+
+* The :ref:`Visual Studio Generators` learned to honor a new
+  :prop_dir:`VS_STARTUP_PROJECT` directory property that specifies
+  the default startup project for generated solutions (``.sln`` files).

+ 20 - 2
Source/cmGlobalVisualStudio71Generator.cxx

@@ -94,16 +94,34 @@ void cmGlobalVisualStudio71Generator
   TargetDependSet projectTargets;
   TargetDependSet originalTargets;
   this->GetTargetSets(projectTargets, originalTargets, root, generators);
-  OrderedTargetDependSet orderedProjectTargets(projectTargets, "ALL_BUILD");
+  OrderedTargetDependSet orderedProjectTargets(
+    projectTargets, this->GetStartupProjectName(root));
 
-  this->WriteTargetsToSolution(fout, root, orderedProjectTargets);
+  // Generate the targets specification to a string.  We will put this in
+  // the actual .sln file later.  As a side effect, this method also
+  // populates the set of folders.
+  std::ostringstream targetsSlnString;
+  this->WriteTargetsToSolution(targetsSlnString, root, orderedProjectTargets);
 
+  // VS 7 does not support folders specified first.
+  if (this->GetVersion() <= VS71)
+    {
+    fout << targetsSlnString.str();
+    }
+
+  // Generate folder specification.
   bool useFolderProperty = this->UseFolderProperty();
   if (useFolderProperty)
     {
     this->WriteFolders(fout);
     }
 
+  // Now write the actual target specification content.
+  if (this->GetVersion() > VS71)
+    {
+    fout << targetsSlnString.str();
+    }
+
   // Write out the configurations information for the solution
   fout << "Global\n";
   // Write out the configurations for the solution

+ 27 - 7
Source/cmGlobalVisualStudioGenerator.cxx

@@ -89,19 +89,13 @@ void cmGlobalVisualStudioGenerator::AddExtraIDETargets()
       cmGeneratorTarget* gt = new cmGeneratorTarget(allBuild, gen[0]);
       gen[0]->AddGeneratorTarget(gt);
 
-#if 0
-      // Can't activate this code because we want ALL_BUILD
-      // selected as the default "startup project" when first
-      // opened in Visual Studio... And if it's nested in a
-      // folder, then that doesn't happen.
       //
       // Organize in the "predefined targets" folder:
       //
-      if (this->UseFolderProperty())
+      if (this->UseFolderProperty() && this->GetVersion() > VS71)
         {
         allBuild->SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
         }
-#endif
 
       // Now make all targets depend on the ALL_BUILD target
       for(std::vector<cmLocalGenerator*>::iterator i = gen.begin();
@@ -518,6 +512,32 @@ cmGlobalVisualStudioGenerator::GetUtilityDepend(
   return i->second;
 }
 
+//----------------------------------------------------------------------------
+std::string
+cmGlobalVisualStudioGenerator::GetStartupProjectName(
+  cmLocalGenerator const* root) const
+{
+  const char* n = root->GetMakefile()->GetProperty("VS_STARTUP_PROJECT");
+  if (n && *n)
+    {
+    std::string startup = n;
+    if (this->FindTarget(startup))
+      {
+      return startup;
+      }
+    else
+      {
+      root->GetMakefile()->IssueMessage(
+        cmake::AUTHOR_WARNING,
+        "Directory property VS_STARTUP_PROJECT specifies target "
+        "'" + startup + "' that does not exist.  Ignoring.");
+      }
+    }
+
+  // default, if not specified
+  return this->GetAllTargetName();
+}
+
 //----------------------------------------------------------------------------
 #include <windows.h>
 

+ 2 - 0
Source/cmGlobalVisualStudioGenerator.h

@@ -106,6 +106,8 @@ public:
 
   void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const;
 
+  std::string GetStartupProjectName(cmLocalGenerator const* root) const;
+
   void AddSymbolExportCommand(
     cmGeneratorTarget*, std::vector<cmCustomCommand>& commands,
     std::string const& configName);

+ 4 - 1
Tests/RunCMake/CMakeLists.txt

@@ -235,7 +235,10 @@ endif()
 
 if("${CMAKE_GENERATOR}" MATCHES "Visual Studio")
   add_RunCMake_test(include_external_msproject)
-  add_RunCMake_test(VSSolution)
+  if("${CMAKE_GENERATOR}" MATCHES "Visual Studio ([789]|10)" AND NOT CMAKE_VS_DEVENV_COMMAND)
+    set(NO_USE_FOLDERS 1)
+  endif()
+  add_RunCMake_test(VSSolution -DNO_USE_FOLDERS=${NO_USE_FOLDERS})
 endif()
 
 if("${CMAKE_GENERATOR}" MATCHES "Visual Studio ([^789]|[789][0-9])")

+ 6 - 0
Tests/RunCMake/VSSolution/RunCMakeTest.cmake

@@ -8,3 +8,9 @@ run_cmake(MorePost)
 run_cmake(PrePost)
 run_cmake(Override1)
 run_cmake(Override2)
+run_cmake(StartupProject)
+run_cmake(StartupProjectMissing)
+
+if(RunCMake_GENERATOR MATCHES "Visual Studio ([^7]|[7][0-9])" AND NOT NO_USE_FOLDERS)
+  run_cmake(StartupProjectUseFolders)
+endif()

+ 5 - 0
Tests/RunCMake/VSSolution/StartupProject-check.cmake

@@ -0,0 +1,5 @@
+getProjectNames(projects)
+list(GET projects 0 first_project)
+if(NOT first_project STREQUAL "TestStartup")
+  error("TestStartup is not the startup project")
+endif()

+ 2 - 0
Tests/RunCMake/VSSolution/StartupProject.cmake

@@ -0,0 +1,2 @@
+add_custom_target(TestStartup)
+set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT "TestStartup")

+ 5 - 0
Tests/RunCMake/VSSolution/StartupProjectMissing-check.cmake

@@ -0,0 +1,5 @@
+getProjectNames(projects)
+list(GET projects 0 first_project)
+if(NOT first_project STREQUAL "ALL_BUILD")
+  error("ALL_BUILD is not the startup project")
+endif()

+ 4 - 0
Tests/RunCMake/VSSolution/StartupProjectMissing-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Warning \(dev\) in CMakeLists.txt:
+  Directory property VS_STARTUP_PROJECT specifies target 'DoesNotExist' that
+  does not exist.  Ignoring.
+This warning is for project developers.  Use -Wno-dev to suppress it.$

+ 1 - 0
Tests/RunCMake/VSSolution/StartupProjectMissing.cmake

@@ -0,0 +1 @@
+set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT "DoesNotExist")

+ 9 - 0
Tests/RunCMake/VSSolution/StartupProjectUseFolders-check.cmake

@@ -0,0 +1,9 @@
+getProjectNames(projects)
+list(GET projects 0 first_project)
+if(NOT first_project STREQUAL "CMakePredefinedTargets")
+  error("CMakePredefinedTargets is not the first project")
+endif()
+list(GET projects 1 second_project)
+if(NOT second_project STREQUAL "TestStartup")
+  error("TestStartup does not immediately follow the CMakePredefinedTargets project")
+endif()

+ 3 - 0
Tests/RunCMake/VSSolution/StartupProjectUseFolders.cmake

@@ -0,0 +1,3 @@
+add_custom_target(TestStartup)
+set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT "TestStartup")

+ 15 - 0
Tests/RunCMake/VSSolution/solution_parsing.cmake

@@ -50,6 +50,21 @@ macro(parseGlobalSections arg_out_pre arg_out_post testName)
 endmacro()
 
 
+macro(getProjectNames arg_out_projects)
+  set(${arg_out_projects} "")
+  set(sln "${RunCMake_TEST_BINARY_DIR}/${test}.sln")
+  if(NOT EXISTS "${sln}")
+    error("Expected solution file ${sln} does not exist")
+  endif()
+  file(STRINGS "${sln}" project_lines REGEX "^Project\\(")
+  foreach(project_line IN LISTS project_lines)
+    string(REGEX REPLACE ".* = \"" "" project_line "${project_line}")
+    string(REGEX REPLACE "\", .*"  "" project_line "${project_line}")
+    list(APPEND ${arg_out_projects} "${project_line}")
+  endforeach()
+endmacro()
+
+
 macro(testGlobalSection prefix sectionName)
   if(NOT DEFINED ${prefix}_${sectionName})
     error("Section ${sectionName} does not exist")