Browse Source

Merge topic 'vs-project-groups'

e6ac0aa Add FOLDER target property, for IDEs (#3796)
Brad King 15 years ago
parent
commit
28edb70a9e

+ 34 - 1
CMakeLists.txt

@@ -180,6 +180,18 @@ MACRO(CMAKE_SETUP_TESTING)
 ENDMACRO(CMAKE_SETUP_TESTING)
 
 
+MACRO(CMAKE_SET_TARGET_FOLDER tgt folder)
+  # Really, I just want this to be an "if(TARGET ${tgt})" ...
+  # but I'm not sure that our min req'd., CMake 2.4.5 can handle
+  # that... so I'm just activating this for now, with a version
+  # compare, and only for MSVC builds.
+  IF(MSVC)
+    IF(NOT ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} LESS 2.8)
+      SET_PROPERTY(TARGET "${tgt}" PROPERTY FOLDER "${folder}")
+    ENDIF()
+  ENDIF()
+ENDMACRO(CMAKE_SET_TARGET_FOLDER)
+
 
 #-----------------------------------------------------------------------
 # a macro to build the utilities used by CMake
@@ -199,7 +211,17 @@ MACRO (CMAKE_BUILD_UTILITIES)
   SET(KWSYS_HEADER_ROOT ${CMake_BINARY_DIR}/Source)
   SET(KWSYS_INSTALL_DOC_DIR "${CMake_DOC_DEST}")
   ADD_SUBDIRECTORY(Source/kwsys)
-  
+  SET(kwsys_folder "Utilities/KWSys")
+  CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE} "${kwsys_folder}")
+  CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE}_c "${kwsys_folder}")
+  CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE}EncodeExecutable "${kwsys_folder}")
+  CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE}ProcessFwd9x "${kwsys_folder}")
+  CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE}TestDynload "${kwsys_folder}")
+  CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE}TestProcess "${kwsys_folder}")
+  CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE}TestsC "${kwsys_folder}")
+  CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE}TestsCxx "${kwsys_folder}")
+  CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE}TestSharedForward "${kwsys_folder}")
+
   #---------------------------------------------------------------------
   # Setup third-party libraries.
   # Everything in the tree should be able to include files from the
@@ -228,6 +250,7 @@ MACRO (CMAKE_BUILD_UTILITIES)
     SET(CMAKE_ZLIB_INCLUDES)
     SET(CMAKE_ZLIB_LIBRARIES cmzlib)
     ADD_SUBDIRECTORY(Utilities/cmzlib)
+    CMAKE_SET_TARGET_FOLDER(cmzlib "Utilities/3rdParty")
   ENDIF(CMAKE_USE_SYSTEM_ZLIB)
   
   #---------------------------------------------------------------------
@@ -254,6 +277,8 @@ MACRO (CMAKE_BUILD_UTILITIES)
       SET(CMAKE_CURL_TEST_URL "${CMAKE_TESTS_CDASH_SERVER}/user.php")
     ENDIF(CMAKE_TESTS_CDASH_SERVER)
     ADD_SUBDIRECTORY(Utilities/cmcurl)
+    CMAKE_SET_TARGET_FOLDER(cmcurl "Utilities/3rdParty")
+    CMAKE_SET_TARGET_FOLDER(LIBCURL "Utilities/3rdParty")
   ENDIF(CMAKE_USE_SYSTEM_CURL)
 
   #---------------------------------------------------------------------
@@ -262,6 +287,7 @@ MACRO (CMAKE_BUILD_UTILITIES)
     "${CMAKE_CURRENT_BINARY_DIR}/Utilities/cmcompress")
   SET(CMAKE_COMPRESS_LIBRARIES "cmcompress")
   ADD_SUBDIRECTORY(Utilities/cmcompress)
+  CMAKE_SET_TARGET_FOLDER(cmcompress "Utilities/3rdParty")
   IF(CMAKE_USE_SYSTEM_BZIP2)
     FIND_PACKAGE(BZip2)
   ELSE()
@@ -269,6 +295,7 @@ MACRO (CMAKE_BUILD_UTILITIES)
       "${CMAKE_CURRENT_SOURCE_DIR}/Utilities/cmbzip2")
     SET(BZIP2_LIBRARIES cmbzip2)
     ADD_SUBDIRECTORY(Utilities/cmbzip2)
+    CMAKE_SET_TARGET_FOLDER(cmbzip2 "Utilities/3rdParty")
   ENDIF()
 
   #---------------------------------------------------------------------
@@ -293,6 +320,7 @@ MACRO (CMAKE_BUILD_UTILITIES)
     SET(BUILD_ARCHIVE_WITHIN_CMAKE TRUE)
     ADD_DEFINITIONS(-DLIBARCHIVE_STATIC)
     ADD_SUBDIRECTORY(Utilities/cmlibarchive)
+    CMAKE_SET_TARGET_FOLDER(cmlibarchive "Utilities/3rdParty")
     SET(CMAKE_TAR_LIBRARIES cmlibarchive ${BZIP2_LIBRARIES})
   ENDIF(CMAKE_USE_SYSTEM_LIBARCHIVE)
 
@@ -310,6 +338,7 @@ MACRO (CMAKE_BUILD_UTILITIES)
     SET(CMAKE_EXPAT_INCLUDES)
     SET(CMAKE_EXPAT_LIBRARIES cmexpat)
     ADD_SUBDIRECTORY(Utilities/cmexpat)
+    CMAKE_SET_TARGET_FOLDER(cmexpat "Utilities/3rdParty")
   ENDIF(CMAKE_USE_SYSTEM_EXPAT)
   
   #---------------------------------------------------------------------
@@ -553,6 +582,10 @@ ADD_SUBDIRECTORY(Source)
 ADD_SUBDIRECTORY(Utilities)
 ADD_SUBDIRECTORY(Tests)
 
+CMAKE_SET_TARGET_FOLDER(CMakeLibTests "Tests")
+CMAKE_SET_TARGET_FOLDER(cmw9xcom "Utilities/Win9xCompat")
+CMAKE_SET_TARGET_FOLDER(documentation "Documentation")
+
 # add a test
 ADD_TEST(SystemInformationNew "${CMAKE_CMAKE_COMMAND}" 
   --system-information  -G "${CMAKE_TEST_GENERATOR}" )

+ 2 - 0
Modules/CTestTargets.cmake

@@ -65,6 +65,7 @@ IF(NOT _CTEST_TARGETS_ADDED)
       ${CMAKE_CTEST_COMMAND} ${__conf_types} -D ${mode}
       )
     SET_PROPERTY(TARGET ${mode} PROPERTY RULE_LAUNCH_CUSTOM "")
+    SET_PROPERTY(TARGET ${mode} PROPERTY FOLDER "CTestDashboardTargets")
   ENDFOREACH(mode)
 
   # For Makefile generators add more granular targets.
@@ -79,6 +80,7 @@ IF(NOT _CTEST_TARGETS_ADDED)
           ${CMAKE_CTEST_COMMAND} ${__conf_types} -D ${mode}${testtype}
           )
         SET_PROPERTY(TARGET ${mode}${testtype} PROPERTY RULE_LAUNCH_CUSTOM "")
+        SET_PROPERTY(TARGET ${mode}${testtype} PROPERTY FOLDER "CTestDashboardTargets")
       ENDFOREACH(testtype)
     ENDFOREACH(mode)
   ENDIF("${CMAKE_GENERATOR}" MATCHES Make)

+ 40 - 0
Source/cmGlobalGenerator.cxx

@@ -1845,6 +1845,38 @@ void cmGlobalGenerator::CreateDefaultGlobalTargets(cmTargets* targets)
     }
 }
 
+//----------------------------------------------------------------------------
+const char* cmGlobalGenerator::GetPredefinedTargetsFolder()
+{
+  const char* prop =
+    this->GetCMakeInstance()->GetProperty("PREDEFINED_TARGETS_FOLDER");
+
+  if (prop)
+    {
+    return prop;
+    }
+
+  return "CMakePredefinedTargets";
+}
+
+//----------------------------------------------------------------------------
+bool cmGlobalGenerator::UseFolderProperty()
+{
+  const char* prop = this->GetCMakeInstance()->GetProperty("USE_FOLDERS");
+
+  // If this property is defined, let the setter turn this on or off...
+  //
+  if (prop)
+    {
+    return cmSystemTools::IsOn(prop);
+    }
+
+  // By default, this feature is ON:
+  //
+  return true;
+}
+
+//----------------------------------------------------------------------------
 cmTarget cmGlobalGenerator::CreateGlobalTarget(
   const char* name, const char* message,
   const cmCustomCommandLines* commandLines,
@@ -1874,6 +1906,14 @@ cmTarget cmGlobalGenerator::CreateGlobalTarget(
     {
     target.AddUtility(dit->c_str());
     }
+
+  // Organize in the "predefined targets" folder:
+  //
+  if (this->UseFolderProperty())
+    {
+    target.SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
+    }
+
   return target;
 }
 

+ 3 - 0
Source/cmGlobalGenerator.h

@@ -322,6 +322,9 @@ protected:
   // All targets in the entire project.
   std::map<cmStdString,cmTarget *> TotalTargets;
 
+  virtual const char* GetPredefinedTargetsFolder();
+  virtual bool UseFolderProperty();
+
 private:
   float FirstTimeProgress;
   // If you add a new map here, make sure it is copied

+ 16 - 0
Source/cmGlobalVisualStudio71Generator.cxx

@@ -111,6 +111,13 @@ void cmGlobalVisualStudio71Generator
   OrderedTargetDependSet orderedProjectTargets(projectTargets);
 
   this->WriteTargetsToSolution(fout, root, orderedProjectTargets);
+
+  bool useFolderProperty = this->UseFolderProperty();
+  if (useFolderProperty)
+    {
+    this->WriteFolders(fout);
+    }
+
   // Write out the configurations information for the solution
   fout << "Global\n";
   // Write out the configurations for the solution
@@ -120,6 +127,15 @@ void cmGlobalVisualStudio71Generator
   // Write out the configurations for all the targets in the project
   this->WriteTargetConfigurations(fout, root, orderedProjectTargets);
   fout << "\tEndGlobalSection\n";
+
+  if (useFolderProperty)
+    {
+    // Write out project folders
+    fout << "\tGlobalSection(NestedProjects) = preSolution\n";
+    this->WriteFoldersContent(fout);
+    fout << "\tEndGlobalSection\n";
+    }
+
   // Write the footer for the SLN file
   this->WriteSLNFooter(fout);
 }

+ 99 - 0
Source/cmGlobalVisualStudio7Generator.cxx

@@ -300,6 +300,48 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution(
                             cmLocalGenerator::START_OUTPUT);
         this->WriteProject(fout, vcprojName, dir.c_str(),
                            *target);
+
+        // Create "solution folder" information from FOLDER target property
+        //
+        if (this->UseFolderProperty())
+          {
+          const char *targetFolder = target->GetProperty("FOLDER");
+          if (targetFolder)
+            {
+            std::vector<cmsys::String> tokens =
+              cmSystemTools::SplitString(targetFolder, '/', false);
+
+            std::string cumulativePath = "";
+
+            for(std::vector<cmsys::String>::iterator iter = tokens.begin();
+                iter != tokens.end(); ++iter)
+              {
+              if(!iter->size())
+                {
+                continue;
+                }
+
+              if (cumulativePath.empty())
+                {
+                cumulativePath = *iter;
+                }
+              else
+                {
+                VisualStudioFolders[cumulativePath].insert(
+                  cumulativePath + "/" + *iter);
+
+                cumulativePath = cumulativePath + "/" + *iter;
+                }
+
+              this->CreateGUID(cumulativePath.c_str());
+              }
+
+            if (!cumulativePath.empty())
+              {
+              VisualStudioFolders[cumulativePath].insert(target->GetName());
+              }
+            }
+          }
         }
       }
     }
@@ -327,6 +369,7 @@ void cmGlobalVisualStudio7Generator::WriteTargetDepends(
     }
 }
 
+//----------------------------------------------------------------------------
 // Write a SLN file to the stream
 void cmGlobalVisualStudio7Generator
 ::WriteSLNFile(std::ostream& fout,
@@ -344,6 +387,13 @@ void cmGlobalVisualStudio7Generator
   OrderedTargetDependSet orderedProjectTargets(projectTargets);
 
   this->WriteTargetsToSolution(fout, root, orderedProjectTargets);
+
+  bool useFolderProperty = this->UseFolderProperty();
+  if (useFolderProperty)
+    {
+    this->WriteFolders(fout);
+    }
+
   // Write out the configurations information for the solution
   fout << "Global\n"
        << "\tGlobalSection(SolutionConfiguration) = preSolution\n";
@@ -361,6 +411,14 @@ void cmGlobalVisualStudio7Generator
   this->WriteTargetDepends(fout, orderedProjectTargets);
   fout << "\tEndGlobalSection\n";
 
+  if (useFolderProperty)
+    {
+    // Write out project folders
+    fout << "\tGlobalSection(NestedProjects) = preSolution\n";
+    this->WriteFoldersContent(fout);
+    fout << "\tEndGlobalSection\n";
+    }
+
   // Write out the configurations for all the targets in the project
   fout << "\tGlobalSection(ProjectConfiguration) = postSolution\n";
   this->WriteTargetConfigurations(fout, root, orderedProjectTargets);
@@ -370,6 +428,47 @@ void cmGlobalVisualStudio7Generator
   this->WriteSLNFooter(fout);
 }
 
+//----------------------------------------------------------------------------
+void cmGlobalVisualStudio7Generator::WriteFolders(std::ostream& fout)
+{
+  std::string guidProjectTypeFolder = "2150E333-8FDC-42A3-9474-1A3956D46DE8";
+  for(std::map<std::string,std::set<std::string> >::iterator iter =
+    VisualStudioFolders.begin(); iter != VisualStudioFolders.end(); ++iter)
+    {
+    std::string fullName = iter->first;
+    std::string guid = this->GetGUID(fullName.c_str());
+    std::string nameOnly = cmSystemTools::GetFilenameName(fullName);
+    cmSystemTools::ReplaceString(fullName, "/", "\\");
+
+    fout << "Project(\"{" <<
+      guidProjectTypeFolder << "}\") = \"" <<
+      nameOnly << "\", \"" <<
+      fullName << "\", \"{" <<
+      guid <<
+      "}\"\nEndProject\n";
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmGlobalVisualStudio7Generator::WriteFoldersContent(std::ostream& fout)
+{
+  for(std::map<std::string,std::set<std::string> >::iterator iter =
+    VisualStudioFolders.begin(); iter != VisualStudioFolders.end(); ++iter)
+    {
+    std::string key(iter->first);
+    std::string guidParent(this->GetGUID(key.c_str()));
+
+    for(std::set<std::string>::iterator it = iter->second.begin();
+        it != iter->second.end(); ++it)
+      {
+      std::string value(*it);
+      std::string guid(this->GetGUID(value.c_str()));
+
+      fout << "\t\t{" << guid << "} = {" << guidParent << "}\n";
+      }
+    }
+}
+
 //----------------------------------------------------------------------------
 std::string
 cmGlobalVisualStudio7Generator::ConvertToSolutionPath(const char* path)

+ 4 - 0
Source/cmGlobalVisualStudio7Generator.h

@@ -143,6 +143,10 @@ protected:
   std::vector<std::string> Configurations;
   std::map<cmStdString, cmStdString> GUIDMap;
 
+  virtual void WriteFolders(std::ostream& fout);
+  virtual void WriteFoldersContent(std::ostream& fout);
+  std::map<std::string,std::set<std::string> > VisualStudioFolders;
+
   // Set during OutputSLNFile with the name of the current project.
   // There is one SLN file per project.
   std::string CurrentProject;

+ 7 - 0
Source/cmGlobalVisualStudio8Generator.cxx

@@ -137,6 +137,13 @@ void cmGlobalVisualStudio8Generator::AddCheckTarget()
                           no_working_directory, no_depends,
                           noCommandLines);
 
+  // Organize in the "predefined targets" folder:
+  //
+  if (this->UseFolderProperty())
+    {
+    tgt->SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
+    }
+
   // Create a list of all stamp files for this project.
   std::vector<std::string> stamps;
   std::string stampList = cmake::GetCMakeFilesDirectoryPostSlash();

+ 15 - 0
Source/cmGlobalVisualStudioGenerator.cxx

@@ -56,6 +56,21 @@ void cmGlobalVisualStudioGenerator::Generate()
         AddUtilityCommand("ALL_BUILD", true, no_working_dir,
                           no_depends, no_commands, false,
                           "Build all projects");
+
+#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())
+        {
+        allBuild->SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
+        }
+#endif
+
       // Now make all targets depend on the ALL_BUILD target
       cmTargets targets;
       for(std::vector<cmLocalGenerator*>::iterator i = gen.begin();

+ 10 - 1
Source/cmTarget.cxx

@@ -853,11 +853,20 @@ void cmTarget::DefineProperties(cmake *cm)
      "The names returned are suitable for passing to the "
      "set_source_files_properties command.");
 
+  cm->DefineProperty
+    ("FOLDER", cmProperty::TARGET,
+     "Set the folder name. Use to organize targets in an IDE.",
+     "Targets with no FOLDER property will appear as top level "
+     "entities in IDEs like Visual Studio. Targets with the same "
+     "FOLDER property value will appear next to each other in a "
+     "folder of that name. To nest folders, use FOLDER values such "
+     "as 'GUI/Dialogs' with '/' characters separating folder levels.");
+
   cm->DefineProperty
     ("PROJECT_LABEL", cmProperty::TARGET,
      "Change the name of a target in an IDE.",
      "Can be used to change the name of the target in an IDE "
-     "like visual stuido. ");
+     "like Visual Studio. ");
   cm->DefineProperty
     ("VS_KEYWORD", cmProperty::TARGET,
      "Visual Studio project keyword.",

+ 17 - 0
Source/cmake.cxx

@@ -3483,6 +3483,23 @@ void cmake::DefineProperties(cmake *cm)
      "the value of this property.  "
      "Non-Makefile generators currently ignore this property.");
 
+  cm->DefineProperty
+    ("USE_FOLDERS", cmProperty::GLOBAL,
+     "Use the FOLDER target property to organize targets into folders.",
+     "If not set, CMake treats this property as ON by default. "
+     "CMake generators that are capable of organizing into a "
+     "hierarchy of folders use the values of the FOLDER target "
+     "property to name those folders. See also the documentation "
+     "for the FOLDER target property.");
+
+  cm->DefineProperty
+    ("PREDEFINED_TARGETS_FOLDER", cmProperty::GLOBAL,
+     "Name of FOLDER for targets that are added automatically by CMake.",
+     "If not set, CMake uses \"CMakePredefinedTargets\" as a default "
+     "value for this property. Targets such as INSTALL, PACKAGE and "
+     "RUN_TESTS will be organized into this FOLDER. See also the "
+     "documentation for the FOLDER target property.");
+
   // ================================================================
   // define variables as well
   // ================================================================

+ 45 - 0
Tests/ExternalProject/CMakeLists.txt

@@ -7,6 +7,9 @@ find_package(CVS)
 find_package(Subversion)
 find_package(Git)
 
+set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER
+  "CMakePredefinedTargets-in-ExternalProjectTest")
+
 set(base "${CMAKE_BINARY_DIR}/CMakeExternals")
 set(binary_base "${base}/Build")
 set_property(DIRECTORY PROPERTY EP_BASE ${base})
@@ -42,6 +45,22 @@ endif()
 
 # Empty projects that test all the known ExternalProject_Add argument key words:
 #
+set(proj AAA-TestAlphabetization)
+ExternalProject_Add(${proj}
+  BUILD_COMMAND ""
+  CONFIGURE_COMMAND ""
+  DOWNLOAD_COMMAND ""
+  INSTALL_COMMAND ""
+)
+
+set(proj ZZZ-TestAlphabetization)
+ExternalProject_Add(${proj}
+  BUILD_COMMAND ""
+  CONFIGURE_COMMAND ""
+  DOWNLOAD_COMMAND ""
+  INSTALL_COMMAND ""
+)
+
 set(proj MinimalNoOpProject)
 ExternalProject_Add(${proj}
   BUILD_COMMAND ""
@@ -71,6 +90,7 @@ ExternalProject_Add(${proj}
   URL_MD5 ""
   UPDATE_COMMAND ""
 )
+set_property(TARGET ${proj} PROPERTY FOLDER "")
 
 
 # Local DIR:
@@ -83,6 +103,7 @@ if(can_build_tutorial_step5)
     TEST_BEFORE_INSTALL 1
     LOG_INSTALL 1
   )
+  set_property(TARGET ${proj} PROPERTY FOLDER "Local")
   ExternalProject_Get_Property(${proj} install_dir)
   set(TutorialStep5_install_dir ${install_dir})
 
@@ -93,6 +114,7 @@ if(can_build_tutorial_step5)
     TEST_AFTER_INSTALL 1
     LOG_TEST 1
   )
+  set_property(TARGET ${proj} PROPERTY FOLDER "Local")
 endif()
 
 
@@ -110,6 +132,7 @@ ExternalProject_Add(${proj}
   INSTALL_COMMAND ""
   LOG_CONFIGURE 1
 )
+set_property(TARGET ${proj} PROPERTY FOLDER "Local/TAR")
 
 set(proj TutorialStep1-LocalNoDirTAR)
 ExternalProject_Add(${proj}
@@ -120,6 +143,7 @@ ExternalProject_Add(${proj}
              -DTEST_LIST:STRING=1@@2@@3
   INSTALL_COMMAND ""
 )
+set_property(TARGET ${proj} PROPERTY FOLDER "Local/TAR")
 ExternalProject_Add_Step(${proj} mypatch
   COMMAND ${CMAKE_COMMAND} -E echo "This is a custom external project step."
   COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/Step1Patch.cmake
@@ -139,6 +163,7 @@ ExternalProject_Add(${proj}
   INSTALL_COMMAND ""
   LOG_BUILD 1
 )
+set_property(TARGET ${proj} PROPERTY FOLDER "Local/TGZ")
 
 set(proj TutorialStep1-LocalNoDirTGZ)
 ExternalProject_Add(${proj}
@@ -148,6 +173,7 @@ ExternalProject_Add(${proj}
   CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
   INSTALL_COMMAND ""
 )
+set_property(TARGET ${proj} PROPERTY FOLDER "Local/TGZ")
 
 
 # Local BZ2:
@@ -164,6 +190,7 @@ ExternalProject_Add(${proj}
   BUILD_COMMAND ""
   INSTALL_COMMAND ""
 )
+set_property(TARGET ${proj} PROPERTY FOLDER "Local/BZ2")
 
 set(proj TutorialStep1-LocalNoDirBZ2)
 ExternalProject_Add(${proj}
@@ -172,6 +199,7 @@ ExternalProject_Add(${proj}
   BUILD_COMMAND ""
   INSTALL_COMMAND ""
 )
+set_property(TARGET ${proj} PROPERTY FOLDER "Local/BZ2")
 
 
 # Local ZIP:
@@ -188,6 +216,7 @@ ExternalProject_Add(${proj}
   BUILD_COMMAND ""
   INSTALL_COMMAND ""
 )
+set_property(TARGET ${proj} PROPERTY FOLDER "Local/ZIP")
 
 set(proj TutorialStep1-LocalNoDirZIP)
 ExternalProject_Add(${proj}
@@ -196,6 +225,7 @@ ExternalProject_Add(${proj}
   BUILD_COMMAND ""
   INSTALL_COMMAND ""
 )
+set_property(TARGET ${proj} PROPERTY FOLDER "Local/ZIP")
 
 
 # CVS-based tests:
@@ -227,6 +257,8 @@ if(do_cvs_tests)
     CONFIGURE_COMMAND "${CVS_EXECUTABLE}" --version
     INSTALL_COMMAND ""
   )
+  set_property(TARGET ${proj}
+    PROPERTY FOLDER "SetupRepos/Local/Deeply/Nested/For/Testing")
 
   # CVS by date stamp:
   #
@@ -241,6 +273,7 @@ if(do_cvs_tests)
     INSTALL_COMMAND ""
     DEPENDS "SetupLocalCVSRepository"
   )
+  set_property(TARGET ${proj} PROPERTY FOLDER "CVS")
 
   # CVS by tag:
   #
@@ -255,6 +288,7 @@ if(do_cvs_tests)
     INSTALL_COMMAND ""
     DEPENDS "SetupLocalCVSRepository"
   )
+  set_property(TARGET ${proj} PROPERTY FOLDER "CVS")
 
   # Live CVS / HEAD (no CVS_TAG):
   #
@@ -274,6 +308,7 @@ if(do_cvs_tests)
     DEPENDS "TutorialStep1-CVS-20090626"
     DEPENDS "TutorialStep1-CVS-testtag1"
   )
+  set_property(TARGET ${proj} PROPERTY FOLDER "CVS")
 endif()
 
 
@@ -326,6 +361,8 @@ if(do_svn_tests)
     CONFIGURE_COMMAND "${Subversion_SVN_EXECUTABLE}" --version
     INSTALL_COMMAND ""
   )
+  set_property(TARGET ${proj}
+    PROPERTY FOLDER "SetupRepos/Local/Deeply/Nested/For/Testing")
 
   # SVN by date stamp:
   #
@@ -339,6 +376,7 @@ if(do_svn_tests)
     INSTALL_COMMAND ""
     DEPENDS "SetupLocalSVNRepository"
   )
+  set_property(TARGET ${proj} PROPERTY FOLDER "SVN")
 
   # SVN by revision number:
   #
@@ -352,6 +390,7 @@ if(do_svn_tests)
     INSTALL_COMMAND ""
     DEPENDS "SetupLocalSVNRepository"
   )
+  set_property(TARGET ${proj} PROPERTY FOLDER "SVN")
 
   # Live SVN / trunk (no SVN_REVISION):
   #
@@ -364,6 +403,7 @@ if(do_svn_tests)
     DEPENDS "SetupLocalSVNRepository"
     LOG_DOWNLOAD 1
   )
+  set_property(TARGET ${proj} PROPERTY FOLDER "SVN")
 endif()
 
 
@@ -401,6 +441,8 @@ if(do_git_tests)
     CONFIGURE_COMMAND "${GIT_EXECUTABLE}" --version
     INSTALL_COMMAND ""
   )
+  set_property(TARGET ${proj}
+    PROPERTY FOLDER "SetupRepos/Local/Deeply/Nested/For/Testing")
 
   # git by commit id:
   #
@@ -414,6 +456,7 @@ if(do_git_tests)
     INSTALL_COMMAND ""
     DEPENDS "SetupLocalGITRepository"
   )
+  set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
 
   # git by explicit branch/tag name:
   #
@@ -427,6 +470,7 @@ if(do_git_tests)
     INSTALL_COMMAND ""
     DEPENDS "SetupLocalGITRepository"
   )
+  set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
 
   # Live git / master (no GIT_TAG):
   #
@@ -439,6 +483,7 @@ if(do_git_tests)
     DEPENDS "SetupLocalGITRepository"
     LOG_UPDATE 1
   )
+  set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
 endif()