Browse Source

Merge topic 'labels-for-subprojects'

376dc3eb Help: Add notes for topic 'labels_for_subprojects'
a70d8e93 Add tests for new directory labels and labels-for-subprojects features
47b3a57c Display subproject timing summary
d3859624 Add directory property 'LABELS' and CMAKE_DIRECTORY_LABELS variable
d08ec4d2 Add CTEST_LABELS_FOR_SUBPROJECTS as a CTest module and script variable

Acked-by: Kitware Robot <[email protected]>
Merge-request: !1004
Brad King 8 năm trước cách đây
mục cha
commit
f5be951117
57 tập tin đã thay đổi với 883 bổ sung15 xóa
  1. 0 1
      Auxiliary/vim/syntax/cmake.vim
  2. 1 0
      Help/manual/cmake-properties.7.rst
  3. 2 0
      Help/manual/cmake-variables.7.rst
  4. 33 0
      Help/manual/ctest.1.rst
  5. 13 0
      Help/prop_dir/LABELS.rst
  6. 14 0
      Help/release/dev/labels_for_subprojects.rst
  7. 6 0
      Help/variable/CMAKE_DIRECTORY_LABELS.rst
  8. 5 0
      Help/variable/CTEST_LABELS_FOR_SUBPROJECTS.rst
  9. 3 0
      Modules/DartConfiguration.tcl.in
  10. 6 0
      Source/CTest/cmCTestBuildCommand.cxx
  11. 1 0
      Source/CTest/cmCTestBuildHandler.cxx
  12. 6 0
      Source/CTest/cmCTestConfigureCommand.cxx
  13. 1 0
      Source/CTest/cmCTestConfigureHandler.cxx
  14. 1 0
      Source/CTest/cmCTestMemCheckHandler.cxx
  15. 1 1
      Source/CTest/cmCTestScriptHandler.cxx
  16. 6 0
      Source/CTest/cmCTestTestCommand.cxx
  17. 179 2
      Source/CTest/cmCTestTestHandler.cxx
  18. 7 0
      Source/CTest/cmCTestTestHandler.h
  19. 34 0
      Source/cmCTest.cxx
  20. 6 0
      Source/cmCTest.h
  21. 2 2
      Source/cmCommands.cxx
  22. 48 9
      Source/cmGlobalGenerator.cxx
  23. 20 0
      Source/cmLocalGenerator.cxx
  24. 3 0
      Source/cmMakefile.cxx
  25. 2 0
      Source/ctest.cxx
  26. 1 0
      Tests/RunCMake/CMakeLists.txt
  27. 5 0
      Tests/RunCMake/ctest_labels_for_subprojects/CMakeLists.txt.in
  28. 2 0
      Tests/RunCMake/ctest_labels_for_subprojects/CTestConfig.cmake.in
  29. 36 0
      Tests/RunCMake/ctest_labels_for_subprojects/CTestConfigCTestScript-check.cmake
  30. 7 0
      Tests/RunCMake/ctest_labels_for_subprojects/CTestConfigCTestScript-stdout.txt
  31. 36 0
      Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariable-check.cmake
  32. 7 0
      Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariable-stdout.txt
  33. 34 0
      Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariableCommandLine-check.cmake
  34. 1 0
      Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariableCommandLine-result.txt
  35. 1 0
      Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariableCommandLine-stderr.txt
  36. 6 0
      Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariableCommandLine-stdout.txt
  37. 1 0
      Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCMakeLists-result.txt
  38. 1 0
      Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCMakeLists-stderr.txt
  39. 6 0
      Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCMakeLists-stdout.txt
  40. 1 0
      Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCTestConfig-result.txt
  41. 1 0
      Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCTestConfig-stderr.txt
  42. 6 0
      Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCTestConfig-stdout.txt
  43. 1 0
      Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCTestConfigNoSummary-result.txt
  44. 1 0
      Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCTestConfigNoSummary-stderr.txt
  45. 7 0
      Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCTestConfigNoSummary-stdout.txt
  46. 1 0
      Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCommandLine-result.txt
  47. 1 0
      Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCommandLine-stderr.txt
  48. 6 0
      Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCommandLine-stdout.txt
  49. 33 0
      Tests/RunCMake/ctest_labels_for_subprojects/MyExperimentalFeature/CMakeLists.txt
  50. 16 0
      Tests/RunCMake/ctest_labels_for_subprojects/MyExperimentalFeature/experimental.c
  51. 12 0
      Tests/RunCMake/ctest_labels_for_subprojects/MyProductionCode/CMakeLists.txt
  52. 16 0
      Tests/RunCMake/ctest_labels_for_subprojects/MyProductionCode/production.c
  53. 7 0
      Tests/RunCMake/ctest_labels_for_subprojects/MyThirdPartyDependency/CMakeLists.txt
  54. 10 0
      Tests/RunCMake/ctest_labels_for_subprojects/MyThirdPartyDependency/src/CMakeLists.txt
  55. 14 0
      Tests/RunCMake/ctest_labels_for_subprojects/MyThirdPartyDependency/src/thirdparty.c
  56. 185 0
      Tests/RunCMake/ctest_labels_for_subprojects/RunCMakeTest.cmake
  57. 21 0
      Tests/RunCMake/ctest_labels_for_subprojects/test.cmake.in

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 1
Auxiliary/vim/syntax/cmake.vim


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

@@ -74,6 +74,7 @@ Properties on Directories
    /prop_dir/INCLUDE_REGULAR_EXPRESSION
    /prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG
    /prop_dir/INTERPROCEDURAL_OPTIMIZATION
+   /prop_dir/LABELS
    /prop_dir/LINK_DIRECTORIES
    /prop_dir/LISTFILE_STACK
    /prop_dir/MACROS

+ 2 - 0
Help/manual/cmake-variables.7.rst

@@ -32,6 +32,7 @@ Variables that Provide Information
    /variable/CMAKE_CURRENT_LIST_FILE
    /variable/CMAKE_CURRENT_LIST_LINE
    /variable/CMAKE_CURRENT_SOURCE_DIR
+   /variable/CMAKE_DIRECTORY_LABELS
    /variable/CMAKE_DL_LIBS
    /variable/CMAKE_EDIT_COMMAND
    /variable/CMAKE_EXECUTABLE_SUFFIX
@@ -482,6 +483,7 @@ Variables for CTest
    /variable/CTEST_GIT_UPDATE_OPTIONS
    /variable/CTEST_HG_COMMAND
    /variable/CTEST_HG_UPDATE_OPTIONS
+   /variable/CTEST_LABELS_FOR_SUBPROJECTS
    /variable/CTEST_MEMORYCHECK_COMMAND
    /variable/CTEST_MEMORYCHECK_COMMAND_OPTIONS
    /variable/CTEST_MEMORYCHECK_SANITIZER_OPTIONS

+ 33 - 0
Help/manual/ctest.1.rst

@@ -250,6 +250,13 @@ Options
  label associated with the tests run.  If there are no labels on the
  tests, nothing extra is printed.
 
+ ``--no-subproject-summary``
+ Disable timing summary information for subprojects.
+
+ This option tells ctest not to print summary information for each
+ subproject associated with the tests run.  If there are no subprojects on the
+ tests, nothing extra is printed.
+
 ``--build-and-test <path-to-source> <path-to-build>``
  Configure, build and run a test.
 
@@ -758,6 +765,15 @@ Configuration settings include:
   * :module:`CTest` module variable: :variable:`CMAKE_COMMAND`
     followed by :variable:`PROJECT_SOURCE_DIR`
 
+``LabelsForSubprojects``
+  Specify a semicolon-separated list of labels that will be treated as
+  subprojects. This mapping will be passed on to CDash when configure, test or
+  build results are submitted.
+
+  * `CTest Script`_ variable: :variable:`CTEST_LABELS_FOR_SUBPROJECTS`
+  * :module:`CTest` module variable: ``CTEST_LABELS_FOR_SUBPROJECTS``
+
+
 .. _`CTest Build Step`:
 
 CTest Build Step
@@ -780,6 +796,14 @@ Configuration settings include:
   * :module:`CTest` module variable: ``DEFAULT_CTEST_CONFIGURATION_TYPE``,
     initialized by the ``CMAKE_CONFIG_TYPE`` environment variable
 
+``LabelsForSubprojects``
+  Specify a semicolon-separated list of labels that will be treated as
+  subprojects. This mapping will be passed on to CDash when configure, test or
+  build results are submitted.
+
+  * `CTest Script`_ variable: :variable:`CTEST_LABELS_FOR_SUBPROJECTS`
+  * :module:`CTest` module variable: ``CTEST_LABELS_FOR_SUBPROJECTS``
+
 ``MakeCommand``
   Command-line to launch the software build process.
   It will be executed in the location specified by the
@@ -815,6 +839,15 @@ Arguments to the command may specify some of the step settings.
 
 Configuration settings include:
 
+``LabelsForSubprojects``
+  Specify a semicolon-separated list of labels that will be treated as
+  subprojects. This mapping will be passed on to CDash when configure, test or
+  build results are submitted.
+
+  * `CTest Script`_ variable: :variable:`CTEST_LABELS_FOR_SUBPROJECTS`
+  * :module:`CTest` module variable: ``CTEST_LABELS_FOR_SUBPROJECTS``
+
+
 ``TestLoad``
   While running tests in parallel (e.g. with ``-j``), try not to start
   tests when they may cause the CPU load to pass above a given threshold.

+ 13 - 0
Help/prop_dir/LABELS.rst

@@ -0,0 +1,13 @@
+LABELS
+------
+
+Specify a list of text labels associated with a directory and all of its
+subdirectories. This is equivalent to setting the :prop_tgt:`LABELS` target
+property and the :prop_test:`LABELS` test property on all targets and tests in
+the current directory and subdirectories. Note: Launchers must enabled to
+propagate labels to targets.
+
+The :variable:`CMAKE_DIRECTORY_LABELS` variable can be used to initialize this
+property.
+
+The list is reported in dashboard submissions.

+ 14 - 0
Help/release/dev/labels_for_subprojects.rst

@@ -0,0 +1,14 @@
+labels_for_subprojects
+----------------------
+
+* A :variable:`CTEST_LABELS_FOR_SUBPROJECTS` CTest module variable and CTest
+  script variable was added to specify a list of labels that should be treated
+  as subprojects by CDash. To use this value in both the CTest module and the
+  ctest command line `Dashboard Client` mode (e.g. ctest -S) set it in the
+  CTestConfig.cmake config file.
+
+* A :prop_dir:`LABELS` directory property was added to specify labels
+  for all targets and tests in a directory.
+
+* A :variable:`CMAKE_DIRECTORY_LABELS` variable was added to specify
+  labels for all tests in a directory.

+ 6 - 0
Help/variable/CMAKE_DIRECTORY_LABELS.rst

@@ -0,0 +1,6 @@
+CMAKE_DIRECTORY_LABELS
+-----------------------
+
+Specify labels for the current directory.
+
+This is used to initialize the :prop_dir:`LABELS` directory property.

+ 5 - 0
Help/variable/CTEST_LABELS_FOR_SUBPROJECTS.rst

@@ -0,0 +1,5 @@
+CTEST_LABELS_FOR_SUBPROJECTS
+----------------------------
+
+Specify the CTest ``LabelsForSubprojects`` setting
+in a :manual:`ctest(1)` dashboard client script.

+ 3 - 0
Modules/DartConfiguration.tcl.in

@@ -16,6 +16,9 @@ Site: @SITE@
 # Build name is osname-revision-compiler, i.e. Linux-2.4.2-2smp-c++
 BuildName: @BUILDNAME@
 
+# Subprojects
+LabelsForSubprojects: @CTEST_LABELS_FOR_SUBPROJECTS@
+
 # Submission information
 IsCDash: @CTEST_DROP_SITE_CDASH@
 CDashVersion: @CTEST_CDASH_VERSION@

+ 6 - 0
Source/CTest/cmCTestBuildCommand.cxx

@@ -153,6 +153,12 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
                                        this->Quiet);
   }
 
+  if (const char* labelsForSubprojects =
+        this->Makefile->GetDefinition("CTEST_LABELS_FOR_SUBPROJECTS")) {
+    this->CTest->SetCTestConfiguration("LabelsForSubprojects",
+                                       labelsForSubprojects, this->Quiet);
+  }
+
   handler->SetQuiet(this->Quiet);
   return handler;
 }

+ 1 - 0
Source/CTest/cmCTestBuildHandler.cxx

@@ -488,6 +488,7 @@ int cmCTestBuildHandler::ProcessHandler()
 void cmCTestBuildHandler::GenerateXMLHeader(cmXMLWriter& xml)
 {
   this->CTest->StartXML(xml, this->AppendXML);
+  this->CTest->GenerateSubprojectsOutput(xml);
   xml.StartElement("Build");
   xml.Element("StartDateTime", this->StartBuild);
   xml.Element("StartBuildTime",

+ 6 - 0
Source/CTest/cmCTestConfigureCommand.cxx

@@ -141,6 +141,12 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
     }
   }
 
+  if (const char* labelsForSubprojects =
+        this->Makefile->GetDefinition("CTEST_LABELS_FOR_SUBPROJECTS")) {
+    this->CTest->SetCTestConfiguration("LabelsForSubprojects",
+                                       labelsForSubprojects, this->Quiet);
+  }
+
   cmCTestGenericHandler* handler =
     this->CTest->GetInitializedHandler("configure");
   if (!handler) {

+ 1 - 0
Source/CTest/cmCTestConfigureHandler.cxx

@@ -73,6 +73,7 @@ int cmCTestConfigureHandler::ProcessHandler()
     if (os) {
       cmXMLWriter xml(os);
       this->CTest->StartXML(xml, this->AppendXML);
+      this->CTest->GenerateSubprojectsOutput(xml);
       xml.StartElement("Configure");
       xml.Element("StartDateTime", start_time);
       xml.Element("StartConfigureTime", start_time_time);

+ 1 - 0
Source/CTest/cmCTestMemCheckHandler.cxx

@@ -291,6 +291,7 @@ void cmCTestMemCheckHandler::GenerateDartOutput(cmXMLWriter& xml)
     return;
   }
   this->CTest->StartXML(xml, this->AppendXML);
+  this->CTest->GenerateSubprojectsOutput(xml);
   xml.StartElement("DynamicAnalysis");
   switch (this->MemoryTesterStyle) {
     case cmCTestMemCheckHandler::VALGRIND:

+ 1 - 1
Source/CTest/cmCTestScriptHandler.cxx

@@ -394,7 +394,7 @@ int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg)
   return 0;
 }
 
-// extract variabels from the script to set ivars
+// extract variables from the script to set ivars
 int cmCTestScriptHandler::ExtractVariables()
 {
   // Temporary variables

+ 6 - 0
Source/CTest/cmCTestTestCommand.cxx

@@ -124,6 +124,12 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler()
   }
   handler->SetTestLoad(testLoad);
 
+  if (const char* labelsForSubprojects =
+        this->Makefile->GetDefinition("CTEST_LABELS_FOR_SUBPROJECTS")) {
+    this->CTest->SetCTestConfiguration("LabelsForSubprojects",
+                                       labelsForSubprojects, this->Quiet);
+  }
+
   handler->SetQuiet(this->Quiet);
   return handler;
 }

+ 179 - 2
Source/CTest/cmCTestTestHandler.cxx

@@ -238,6 +238,36 @@ bool cmCTestSetTestsPropertiesCommand::InitialPass(
   return this->TestHandler->SetTestsProperties(args);
 }
 
+class cmCTestSetDirectoryPropertiesCommand : public cmCommand
+{
+public:
+  /**
+   * This is a virtual constructor for the command.
+   */
+  cmCommand* Clone() CM_OVERRIDE
+  {
+    cmCTestSetDirectoryPropertiesCommand* c =
+      new cmCTestSetDirectoryPropertiesCommand;
+    c->TestHandler = this->TestHandler;
+    return c;
+  }
+
+  /**
+   * This is called when the command is first encountered in
+   * the CMakeLists.txt file.
+  */
+  bool InitialPass(std::vector<std::string> const& /*unused*/,
+                   cmExecutionStatus& /*unused*/) CM_OVERRIDE;
+
+  cmCTestTestHandler* TestHandler;
+};
+
+bool cmCTestSetDirectoryPropertiesCommand::InitialPass(
+  std::vector<std::string> const& args, cmExecutionStatus&)
+{
+  return this->TestHandler->SetDirectoryProperties(args);
+}
+
 // get the next number in a string with numbers separated by ,
 // pos is the start of the search and pos2 is the end of the search
 // pos becomes pos2 after a call to GetNextNumber.
@@ -506,9 +536,14 @@ int cmCTestTestHandler::ProcessHandler()
                  << static_cast<int>(percent + .5f) << "% tests passed, "
                  << failed.size() << " tests failed out of " << total
                  << std::endl);
-    if (this->CTest->GetLabelSummary()) {
+
+    if (!this->CTest->GetLabelsForSubprojects().empty() &&
+        this->CTest->GetSubprojectSummary()) {
+      this->PrintSubprojectSummary();
+    } else if (this->CTest->GetLabelSummary()) {
       this->PrintLabelSummary();
     }
+
     char realBuf[1024];
     sprintf(realBuf, "%6.2f sec", (double)(clock_finish - clock_start));
     cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
@@ -658,6 +693,84 @@ void cmCTestTestHandler::PrintLabelSummary()
   }
 }
 
+void cmCTestTestHandler::PrintSubprojectSummary()
+{
+  std::vector<std::string> subprojects =
+    this->CTest->GetLabelsForSubprojects();
+
+  cmCTestTestHandler::ListOfTests::iterator it = this->TestList.begin();
+  std::map<std::string, double> labelTimes;
+  std::map<std::string, int> labelCounts;
+  std::set<std::string> labels;
+  // initialize maps
+  std::string::size_type maxlen = 0;
+  for (; it != this->TestList.end(); ++it) {
+    cmCTestTestProperties& p = *it;
+    for (std::vector<std::string>::iterator l = p.Labels.begin();
+         l != p.Labels.end(); ++l) {
+      std::vector<std::string>::iterator subproject =
+        std::find(subprojects.begin(), subprojects.end(), *l);
+      if (subproject != subprojects.end()) {
+        if ((*l).size() > maxlen) {
+          maxlen = (*l).size();
+        }
+        labels.insert(*l);
+        labelTimes[*l] = 0;
+        labelCounts[*l] = 0;
+      }
+    }
+  }
+  cmCTestTestHandler::TestResultsVector::iterator ri =
+    this->TestResults.begin();
+  // fill maps
+  for (; ri != this->TestResults.end(); ++ri) {
+    cmCTestTestResult& result = *ri;
+    cmCTestTestProperties& p = *result.Properties;
+    for (std::vector<std::string>::iterator l = p.Labels.begin();
+         l != p.Labels.end(); ++l) {
+      std::vector<std::string>::iterator subproject =
+        std::find(subprojects.begin(), subprojects.end(), *l);
+      if (subproject != subprojects.end()) {
+        labelTimes[*l] += result.ExecutionTime;
+        ++labelCounts[*l];
+      }
+    }
+  }
+  // now print times
+  if (!labels.empty()) {
+    cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+                       "\nSubproject Time Summary:", this->Quiet);
+  }
+  for (std::set<std::string>::const_iterator i = labels.begin();
+       i != labels.end(); ++i) {
+    std::string label = *i;
+    label.resize(maxlen + 3, ' ');
+
+    char buf[1024];
+    sprintf(buf, "%6.2f sec", labelTimes[*i]);
+
+    std::ostringstream labelCountStr;
+    labelCountStr << "(" << labelCounts[*i] << " test";
+    if (labelCounts[*i] > 1) {
+      labelCountStr << "s";
+    }
+    labelCountStr << ")";
+
+    cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "\n"
+                         << label << " = " << buf << " "
+                         << labelCountStr.str(),
+                       this->Quiet);
+    if (this->LogFile) {
+      *this->LogFile << "\n" << *i << " = " << buf << "\n";
+    }
+  }
+  if (!labels.empty()) {
+    if (this->LogFile) {
+      *this->LogFile << "\n";
+    }
+    cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "\n", this->Quiet);
+  }
+}
 void cmCTestTestHandler::CheckLabelFilterInclude(cmCTestTestProperties& it)
 {
   // if not using Labels to filter then return
@@ -1277,6 +1390,7 @@ void cmCTestTestHandler::GenerateDartOutput(cmXMLWriter& xml)
   }
 
   this->CTest->StartXML(xml, this->AppendXML);
+  this->CTest->GenerateSubprojectsOutput(xml);
   xml.StartElement("Testing");
   xml.Element("StartDateTime", this->StartTest);
   xml.Element("StartTestTime", this->StartTestTime);
@@ -1660,6 +1774,12 @@ void cmCTestTestHandler::GetListOfTests()
   newCom4->TestHandler = this;
   cm.GetState()->AddBuiltinCommand("set_tests_properties", newCom4);
 
+  // Add handler for SET_DIRECTORY_PROPERTIES
+  cmCTestSetDirectoryPropertiesCommand* newCom5 =
+    new cmCTestSetDirectoryPropertiesCommand;
+  newCom5->TestHandler = this;
+  cm.GetState()->AddBuiltinCommand("set_directory_properties", newCom5);
+
   const char* testFilename;
   if (cmSystemTools::FileExists("CTestTestfile.cmake")) {
     // does the CTestTestfile.cmake exist ?
@@ -2171,7 +2291,16 @@ bool cmCTestTestHandler::SetTestsProperties(
             cmSystemTools::ExpandListArgument(val, rtit->Environment);
           }
           if (key == "LABELS") {
-            cmSystemTools::ExpandListArgument(val, rtit->Labels);
+            std::vector<std::string> Labels;
+            cmSystemTools::ExpandListArgument(val, Labels);
+            rtit->Labels.insert(rtit->Labels.end(), Labels.begin(),
+                                Labels.end());
+            // sort the array
+            std::sort(rtit->Labels.begin(), rtit->Labels.end());
+            // remove duplicates
+            std::vector<std::string>::iterator new_end =
+              std::unique(rtit->Labels.begin(), rtit->Labels.end());
+            rtit->Labels.erase(new_end, rtit->Labels.end());
           }
           if (key == "MEASUREMENT") {
             size_t pos = val.find_first_of('=');
@@ -2224,6 +2353,54 @@ bool cmCTestTestHandler::SetTestsProperties(
   return true;
 }
 
+bool cmCTestTestHandler::SetDirectoryProperties(
+  const std::vector<std::string>& args)
+{
+  std::vector<std::string>::const_iterator it;
+  std::vector<std::string> tests;
+  bool found = false;
+  for (it = args.begin(); it != args.end(); ++it) {
+    if (*it == "PROPERTIES") {
+      found = true;
+      break;
+    }
+    tests.push_back(*it);
+  }
+
+  if (!found) {
+    return false;
+  }
+  ++it; // skip PROPERTIES
+  for (; it != args.end(); ++it) {
+    std::string key = *it;
+    ++it;
+    if (it == args.end()) {
+      break;
+    }
+    std::string val = *it;
+    cmCTestTestHandler::ListOfTests::iterator rtit;
+    for (rtit = this->TestList.begin(); rtit != this->TestList.end(); ++rtit) {
+      std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+      if (cwd == rtit->Directory) {
+        if (key == "LABELS") {
+          std::vector<std::string> DirectoryLabels;
+          cmSystemTools::ExpandListArgument(val, DirectoryLabels);
+          rtit->Labels.insert(rtit->Labels.end(), DirectoryLabels.begin(),
+                              DirectoryLabels.end());
+
+          // sort the array
+          std::sort(rtit->Labels.begin(), rtit->Labels.end());
+          // remove duplicates
+          std::vector<std::string>::iterator new_end =
+            std::unique(rtit->Labels.begin(), rtit->Labels.end());
+          rtit->Labels.erase(new_end, rtit->Labels.end());
+        }
+      }
+    }
+  }
+  return true;
+}
+
 bool cmCTestTestHandler::AddTest(const std::vector<std::string>& args)
 {
   const std::string& testname = args[0];

+ 7 - 0
Source/CTest/cmCTestTestHandler.h

@@ -90,6 +90,11 @@ public:
    */
   bool SetTestsProperties(const std::vector<std::string>& args);
 
+  /**
+   * Set directory properties
+   */
+  bool SetDirectoryProperties(const std::vector<std::string>& args);
+
   void Initialize() CM_OVERRIDE;
 
   // NOTE: This struct is Saved/Restored
@@ -227,6 +232,8 @@ private:
   virtual void GenerateDartOutput(cmXMLWriter& xml);
 
   void PrintLabelSummary();
+  void PrintSubprojectSummary();
+
   /**
    * Run the tests for a directory and any subdirectories
    */

+ 34 - 0
Source/cmCTest.cxx

@@ -11,6 +11,7 @@
 #include "cmsys/Process.h"
 #include "cmsys/String.hxx"
 #include "cmsys/SystemInformation.hxx"
+#include <algorithm>
 #include <ctype.h>
 #include <iostream>
 #include <map>
@@ -253,6 +254,7 @@ std::string cmCTest::DecodeURL(const std::string& in)
 cmCTest::cmCTest()
 {
   this->LabelSummary = true;
+  this->SubprojectSummary = true;
   this->ParallelLevel = 1;
   this->ParallelLevelSetInCli = false;
   this->TestLoad = 0;
@@ -1364,6 +1366,35 @@ void cmCTest::AddSiteProperties(cmXMLWriter& xml)
   }
 }
 
+void cmCTest::GenerateSubprojectsOutput(cmXMLWriter& xml)
+{
+  std::vector<std::string> subprojects = this->GetLabelsForSubprojects();
+  std::vector<std::string>::const_iterator i;
+  for (i = subprojects.begin(); i != subprojects.end(); ++i) {
+    xml.StartElement("Subproject");
+    xml.Attribute("name", *i);
+    xml.Element("Label", *i);
+    xml.EndElement(); // Subproject
+  }
+}
+
+std::vector<std::string> cmCTest::GetLabelsForSubprojects()
+{
+  std::string labelsForSubprojects =
+    this->GetCTestConfiguration("LabelsForSubprojects");
+  std::vector<std::string> subprojects;
+  cmSystemTools::ExpandListArgument(labelsForSubprojects, subprojects);
+
+  // sort the array
+  std::sort(subprojects.begin(), subprojects.end());
+  // remove duplicates
+  std::vector<std::string>::iterator new_end =
+    std::unique(subprojects.begin(), subprojects.end());
+  subprojects.erase(new_end, subprojects.end());
+
+  return subprojects;
+}
+
 void cmCTest::EndXML(cmXMLWriter& xml)
 {
   xml.EndElement(); // Site
@@ -1765,6 +1796,9 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
   if (this->CheckArgument(arg, "--no-label-summary")) {
     this->LabelSummary = false;
   }
+  if (this->CheckArgument(arg, "--no-subproject-summary")) {
+    this->SubprojectSummary = false;
+  }
   if (this->CheckArgument(arg, "-Q", "--quiet")) {
     this->Quiet = true;
   }

+ 6 - 0
Source/cmCTest.h

@@ -438,7 +438,9 @@ public:
     this->StreamErr = err;
   }
   void AddSiteProperties(cmXMLWriter& xml);
+
   bool GetLabelSummary() { return this->LabelSummary; }
+  bool GetSubprojectSummary() { return this->SubprojectSummary; }
 
   std::string GetCostDataFile();
 
@@ -453,6 +455,9 @@ public:
   /** Return true if test should run until fail */
   bool GetRepeatUntilFail() { return this->RepeatUntilFail; }
 
+  void GenerateSubprojectsOutput(cmXMLWriter& xml);
+  std::vector<std::string> GetLabelsForSubprojects();
+
 private:
   int RepeatTests;
   bool RepeatUntilFail;
@@ -464,6 +469,7 @@ private:
   bool ExtraVerbose;
   bool ProduceXML;
   bool LabelSummary;
+  bool SubprojectSummary;
   bool UseHTTP10;
   bool PrintLabels;
   bool Failover;

+ 2 - 2
Source/cmCommands.cxx

@@ -147,8 +147,6 @@ void GetScriptingCommands(cmState* state)
   state->AddBuiltinCommand("separate_arguments",
                            new cmSeparateArgumentsCommand);
   state->AddBuiltinCommand("set", new cmSetCommand);
-  state->AddBuiltinCommand("set_directory_properties",
-                           new cmSetDirectoryPropertiesCommand);
   state->AddBuiltinCommand("set_property", new cmSetPropertyCommand);
   state->AddBuiltinCommand("site_name", new cmSiteNameCommand);
   state->AddBuiltinCommand("string", new cmStringCommand);
@@ -231,6 +229,8 @@ void GetProjectCommands(cmState* state)
   state->AddBuiltinCommand("install_targets", new cmInstallTargetsCommand);
   state->AddBuiltinCommand("link_directories", new cmLinkDirectoriesCommand);
   state->AddBuiltinCommand("project", new cmProjectCommand);
+  state->AddBuiltinCommand("set_directory_properties",
+                           new cmSetDirectoryPropertiesCommand);
   state->AddBuiltinCommand("set_source_files_properties",
                            new cmSetSourceFilesPropertiesCommand);
   state->AddBuiltinCommand("set_target_properties",

+ 48 - 9
Source/cmGlobalGenerator.cxx

@@ -2811,7 +2811,12 @@ void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target)
 
 #ifdef CMAKE_BUILD_WITH_CMAKE
   // Check whether labels are enabled for this target.
-  if (const char* value = target->GetProperty("LABELS")) {
+  const char* targetLabels = target->GetProperty("LABELS");
+  const char* directoryLabels =
+    target->Target->GetMakefile()->GetProperty("LABELS");
+  const char* cmakeDirectoryLabels =
+    target->Target->GetMakefile()->GetDefinition("CMAKE_DIRECTORY_LABELS");
+  if (targetLabels || directoryLabels || cmakeDirectoryLabels) {
     Json::Value lj_root(Json::objectValue);
     Json::Value& lj_target = lj_root["target"] = Json::objectValue;
     lj_target["name"] = target->GetName();
@@ -2821,19 +2826,53 @@ void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target)
     cmSystemTools::MakeDirectory(dir.c_str());
     cmGeneratedFileStream fout(file.c_str());
 
+    std::vector<std::string> labels;
+
     // List the target-wide labels.  All sources in the target get
     // these labels.
-    std::vector<std::string> labels;
-    cmSystemTools::ExpandListArgument(value, labels);
-    if (!labels.empty()) {
-      fout << "# Target labels\n";
-      for (std::vector<std::string>::const_iterator li = labels.begin();
-           li != labels.end(); ++li) {
-        fout << " " << *li << "\n";
-        lj_target_labels.append(*li);
+    if (targetLabels) {
+      cmSystemTools::ExpandListArgument(targetLabels, labels);
+      if (!labels.empty()) {
+        fout << "# Target labels\n";
+        for (std::vector<std::string>::const_iterator li = labels.begin();
+             li != labels.end(); ++li) {
+          fout << " " << *li << "\n";
+          lj_target_labels.append(*li);
+        }
       }
     }
 
+    // List directory labels
+    std::vector<std::string> directoryLabelsList;
+    std::vector<std::string> cmakeDirectoryLabelsList;
+
+    if (directoryLabels) {
+      cmSystemTools::ExpandListArgument(directoryLabels, directoryLabelsList);
+    }
+
+    if (cmakeDirectoryLabels) {
+      cmSystemTools::ExpandListArgument(cmakeDirectoryLabels,
+                                        cmakeDirectoryLabelsList);
+    }
+
+    if (!directoryLabelsList.empty() || !cmakeDirectoryLabelsList.empty()) {
+      fout << "# Directory labels\n";
+    }
+
+    for (std::vector<std::string>::const_iterator li =
+           directoryLabelsList.begin();
+         li != directoryLabelsList.end(); ++li) {
+      fout << " " << *li << "\n";
+      lj_target_labels.append(*li);
+    }
+
+    for (std::vector<std::string>::const_iterator li =
+           cmakeDirectoryLabelsList.begin();
+         li != cmakeDirectoryLabelsList.end(); ++li) {
+      fout << " " << *li << "\n";
+      lj_target_labels.append(*li);
+    }
+
     // List the source files with any per-source labels.
     fout << "# Source files and their labels\n";
     std::vector<cmSourceFile*> sources;

+ 20 - 0
Source/cmLocalGenerator.cxx

@@ -277,6 +277,25 @@ void cmLocalGenerator::GenerateTestFiles()
     outP = cmOutputConverter::EscapeForCMake(outP);
     fout << "subdirs(" << outP << ")" << std::endl;
   }
+
+  // Add directory labels property
+  const char* directoryLabels =
+    this->Makefile->GetDefinition("CMAKE_DIRECTORY_LABELS");
+  const char* labels = this->Makefile->GetProperty("LABELS");
+
+  if (labels || directoryLabels) {
+    fout << "set_directory_properties(PROPERTIES LABELS ";
+    if (labels) {
+      fout << cmOutputConverter::EscapeForCMake(labels);
+    }
+    if (labels && directoryLabels) {
+      fout << ";";
+    }
+    if (directoryLabels) {
+      fout << cmOutputConverter::EscapeForCMake(directoryLabels);
+    }
+    fout << ")" << std::endl;
+  }
 }
 
 void cmLocalGenerator::CreateEvaluationFileOutputs(std::string const& config)
@@ -327,6 +346,7 @@ void cmLocalGenerator::GenerateInstallRules()
 {
   // Compute the install prefix.
   const char* prefix = this->Makefile->GetDefinition("CMAKE_INSTALL_PREFIX");
+
 #if defined(_WIN32) && !defined(__CYGWIN__)
   std::string prefix_win32;
   if (!prefix) {

+ 3 - 0
Source/cmMakefile.cxx

@@ -1235,6 +1235,9 @@ void cmMakefile::InitializeFromParent(cmMakefile* parent)
     }
   }
 
+  // labels
+  this->SetProperty("LABELS", parent->GetProperty("LABELS"));
+
   // link libraries
   this->SetProperty("LINK_LIBRARIES", parent->GetProperty("LINK_LIBRARIES"));
 

+ 2 - 0
Source/ctest.cxx

@@ -83,6 +83,8 @@ static const char* cmDocumentationOptions[][2] = {
   { "--max-width <width>", "Set the max width for a test name to output" },
   { "--interactive-debug-mode [0|1]", "Set the interactive mode to 0 or 1." },
   { "--no-label-summary", "Disable timing summary information for labels." },
+  { "--no-subproject-summary", "Disable timing summary information for "
+                               "subprojects." },
   { "--build-and-test", "Configure, build and run a test." },
   { "--build-target", "Specify a specific target to build." },
   { "--build-nocmake", "Run the build without running cmake first." },

+ 1 - 0
Tests/RunCMake/CMakeLists.txt

@@ -348,6 +348,7 @@ if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
     list(APPEND CompilerLauncher_ARGS -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
   endif()
   add_RunCMake_test(CompilerLauncher)
+  add_RunCMake_test(ctest_labels_for_subprojects)
 endif()
 
 add_RunCMake_test_group(CPack "DEB;RPM;7Z;TBZ2;TGZ;TXZ;TZ;ZIP;STGZ")

+ 5 - 0
Tests/RunCMake/ctest_labels_for_subprojects/CMakeLists.txt.in

@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.9)
+@CASE_CMAKELISTS_PREFIX_CODE@
+project(CTestLabelsForSubprojects@CASE_NAME@ NONE)
+include(CTest)
+@CASE_CMAKELISTS_SUFFIX_CODE@

+ 2 - 0
Tests/RunCMake/ctest_labels_for_subprojects/CTestConfig.cmake.in

@@ -0,0 +1,2 @@
+set(CTEST_PROJECT_NAME "CTestLabelsForSubprojects@CASE_NAME@")
+@CTEST_EXTRA_CONFIG@

+ 36 - 0
Tests/RunCMake/ctest_labels_for_subprojects/CTestConfigCTestScript-check.cmake

@@ -0,0 +1,36 @@
+set(EXPERIMENTAL_FEATURE_REGEX "<Subproject name=\"MyExperimentalFeature\">.*<Label>MyExperimentalFeature</Label>.*</Subproject>")
+set(PRODUCTION_CODE_REGEX "<Subproject name=\"MyProductionCode\">.*<Label>MyProductionCode</Label>.*</Subproject>")
+set(SUBPROJECTS_REGEX "${EXPERIMENTAL_FEATURE_REGEX}.*${PRODUCTION_CODE_REGEX}")
+
+file(GLOB configure_xml_file "${RunCMake_TEST_BINARY_DIR}/Testing/*/Configure.xml")
+if(configure_xml_file)
+  file(READ "${configure_xml_file}" configure_xml)
+  if(NOT configure_xml MATCHES "${SUBPROJECTS_REGEX}.*<Configure>")
+     set(RunCMake_TEST_FAILED "Configure.xml does not contain the expected list of subprojects")
+  endif()
+else()
+  set(RunCMake_TEST_FAILED "Configure.xml not found")
+endif()
+
+file(GLOB build_xml_file "${RunCMake_TEST_BINARY_DIR}/Testing/*/Build.xml")
+if(build_xml_file)
+  file(READ "${build_xml_file}" build_xml)
+  set(BUILD_WARNING_REGEX "<Failure type=\"Warning\">.*<Labels>.*<Label>MyExperimentalFeature</Label>.*</Labels>")
+  if(NOT build_xml MATCHES "${SUBPROJECTS_REGEX}.*<Build>.*${BUILD_ERROR_REGEX}.*</Build>")
+    set(RunCMake_TEST_FAILED "Build.xml does not contain the expected list of subprojects and labels")
+  endif()
+else()
+  set(RunCMake_TEST_FAILED "Build.xml not found")
+endif()
+
+file(GLOB test_xml_file "${RunCMake_TEST_BINARY_DIR}/Testing/*/Test.xml")
+if(test_xml_file)
+  file(READ "${test_xml_file}" test_xml)
+  set(TEST_FAILED_REGEX "<Test Status=\"failed\">.*<Labels>.*<Label>MyExperimentalFeature</Label>.*<Label>NotASubproject</Label>.*</Labels>")
+  set(TEST_PASSED_REGEX "<Test Status=\"passed\">.*<Labels>.*<Label>MyProductionCode</Label>.*</Labels>")
+  if(NOT test_xml MATCHES "${SUBPROJECTS_REGEX}.*<Testing>.*${TEST_FAILED_REGEX}.*${TEST_PASSED_REGEX}.*${TEST_NOTRUN_REGEX}.*</Testing>")
+    set(RunCMake_TEST_FAILED "Test.xml does not contain the expected list of subprojects and labels")
+  endif()
+else()
+  set(RunCMake_TEST_FAILED "${CTEST_BINARY_DIRECTORY}/Testing/*/Test.xml not found")
+endif()

+ 7 - 0
Tests/RunCMake/ctest_labels_for_subprojects/CTestConfigCTestScript-stdout.txt

@@ -0,0 +1,7 @@
+17% tests passed, 5 tests failed out of 6
++
+Subproject Time Summary:
+MyExperimentalFeature += +[0-9.]+ sec \(5 tests\)
+MyProductionCode += +[0-9.]+ sec \(1 test\)
++
+Total Test time \(real\) = +[0-9.]+ sec

+ 36 - 0
Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariable-check.cmake

@@ -0,0 +1,36 @@
+set(EXPERIMENTAL_FEATURE_REGEX "<Subproject name=\"MyExperimentalFeature\">.*<Label>MyExperimentalFeature</Label>.*</Subproject>")
+set(PRODUCTION_CODE_REGEX "<Subproject name=\"MyProductionCode\">.*<Label>MyProductionCode</Label>.*</Subproject>")
+set(SUBPROJECTS_REGEX "${EXPERIMENTAL_FEATURE_REGEX}.*${PRODUCTION_CODE_REGEX}")
+
+file(GLOB configure_xml_file "${RunCMake_TEST_BINARY_DIR}/Testing/*/Configure.xml")
+if(configure_xml_file)
+  file(READ "${configure_xml_file}" configure_xml)
+  if(NOT configure_xml MATCHES "${SUBPROJECTS_REGEX}.*<Configure>")
+     set(RunCMake_TEST_FAILED "Configure.xml does not contain the expected list of subprojects")
+  endif()
+else()
+  set(RunCMake_TEST_FAILED "Configure.xml not found")
+endif()
+
+file(GLOB build_xml_file "${RunCMake_TEST_BINARY_DIR}/Testing/*/Build.xml")
+if(build_xml_file)
+  file(READ "${build_xml_file}" build_xml)
+  set(BUILD_WARNING_REGEX "<Failure type=\"Warning\">.*<Labels>.*<Label>MyExperimentalFeature</Label>.*</Labels>")
+  if(NOT build_xml MATCHES "${SUBPROJECTS_REGEX}.*<Build>.*${BUILD_ERROR_REGEX}.*</Build>")
+    set(RunCMake_TEST_FAILED "Build.xml does not contain the expected list of subprojects and labels")
+  endif()
+else()
+  set(RunCMake_TEST_FAILED "Build.xml not found")
+endif()
+
+file(GLOB test_xml_file "${RunCMake_TEST_BINARY_DIR}/Testing/*/Test.xml")
+if(test_xml_file)
+  file(READ "${test_xml_file}" test_xml)
+  set(TEST_FAILED_REGEX "<Test Status=\"failed\">.*<Labels>.*<Label>MyExperimentalFeature</Label>.*<Label>NotASubproject</Label>.*</Labels>")
+  set(TEST_PASSED_REGEX "<Test Status=\"passed\">.*<Labels>.*<Label>MyProductionCode</Label>.*</Labels>")
+  if(NOT test_xml MATCHES "${SUBPROJECTS_REGEX}.*<Testing>.*${TEST_FAILED_REGEX}.*${TEST_PASSED_REGEX}.*${TEST_NOTRUN_REGEX}.*</Testing>")
+    set(RunCMake_TEST_FAILED "Test.xml does not contain the expected list of subprojects and labels")
+  endif()
+else()
+  set(RunCMake_TEST_FAILED "${CTEST_BINARY_DIRECTORY}/Testing/*/Test.xml not found")
+endif()

+ 7 - 0
Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariable-stdout.txt

@@ -0,0 +1,7 @@
+17% tests passed, 5 tests failed out of 6
++
+Subproject Time Summary:
+MyExperimentalFeature += +[0-9.]+ sec \(5 tests\)
+MyProductionCode += +[0-9.]+ sec \(1 test\)
++
+Total Test time \(real\) = +[0-9.]+ sec

+ 34 - 0
Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariableCommandLine-check.cmake

@@ -0,0 +1,34 @@
+set(THIRD_PARTY_REGEX "<Subproject name=\"MyThirdPartyDependency\">.*<Label>MyThirdPartyDependency</Label>.*</Subproject>")
+set(SUBPROJECTS_REGEX "${THIRD_PARTY_REGEX}")
+
+file(GLOB configure_xml_file "${RunCMake_TEST_BINARY_DIR}/Testing/*/Configure.xml")
+if(configure_xml_file)
+  file(READ "${configure_xml_file}" configure_xml)
+  if(NOT configure_xml MATCHES "${SUBPROJECTS_REGEX}.*<Configure>")
+     set(RunCMake_TEST_FAILED "Configure.xml does not contain the expected list of subprojects")
+  endif()
+else()
+  set(RunCMake_TEST_FAILED "Configure.xml not found")
+endif()
+
+file(GLOB build_xml_file "${RunCMake_TEST_BINARY_DIR}/Testing/*/Build.xml")
+if(build_xml_file)
+  file(READ "${build_xml_file}" build_xml)
+  set(BUILD_ERROR_REGEX "<Failure type=\"Error\">.*<Labels>.*<Label>MyThirdPartyDependency</Label>.*<Label>NotASubproject</Label>.*</Labels>")
+  if(NOT build_xml MATCHES "${SUBPROJECTS_REGEX}.*<Build>.*${BUILD_ERROR_REGEX}.*</Build>")
+    set(RunCMake_TEST_FAILED "Build.xml does not contain the expected list of subprojects and labels")
+  endif()
+else()
+  set(RunCMake_TEST_FAILED "Build.xml not found")
+endif()
+
+file(GLOB test_xml_file "${RunCMake_TEST_BINARY_DIR}/Testing/*/Test.xml")
+if(test_xml_file)
+  file(READ "${test_xml_file}" test_xml)
+  set(TEST_NOTRUN_REGEX "<Test Status=\"notrun\">.*<Labels>.*<Label>MyThirdPartyDependency</Label>.*<Label>NotASubproject</Label>.*</Labels>")
+  if(NOT test_xml MATCHES "${SUBPROJECTS_REGEX}.*<Testing>.*${TEST_FAILED_REGEX}.*${TEST_PASSED_REGEX}.*${TEST_NOTRUN_REGEX}.*</Testing>")
+    set(RunCMake_TEST_FAILED "Test.xml does not contain the expected list of subprojects and labels")
+  endif()
+else()
+  set(RunCMake_TEST_FAILED "${CTEST_BINARY_DIRECTORY}/Testing/*/Test.xml not found")
+endif()

+ 1 - 0
Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariableCommandLine-result.txt

@@ -0,0 +1 @@
+(-1|255)

+ 1 - 0
Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariableCommandLine-stderr.txt

@@ -0,0 +1 @@
+Unable to find executable:.*MyThirdPartyDependency/src/thirdparty

+ 6 - 0
Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariableCommandLine-stdout.txt

@@ -0,0 +1,6 @@
+0% tests passed, 1 tests failed out of 1
++
+Subproject Time Summary:
+MyThirdPartyDependency += +[0-9.]+ sec \(1 test\)
++
+Total Test time \(real\) = +[0-9.]+ sec

+ 1 - 0
Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCMakeLists-result.txt

@@ -0,0 +1 @@
+8

+ 1 - 0
Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCMakeLists-stderr.txt

@@ -0,0 +1 @@
+Errors while running CTest

+ 6 - 0
Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCMakeLists-stdout.txt

@@ -0,0 +1,6 @@
+50% tests passed, 1 tests failed out of 2
++
+Subproject Time Summary:
+MySubproject += +[0-9.]+ sec \(2 tests\)
++
+Total Test time \(real\) = +[0-9.]+ sec

+ 1 - 0
Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCTestConfig-result.txt

@@ -0,0 +1 @@
+8

+ 1 - 0
Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCTestConfig-stderr.txt

@@ -0,0 +1 @@
+Errors while running CTest

+ 6 - 0
Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCTestConfig-stdout.txt

@@ -0,0 +1,6 @@
+67% tests passed, 1 tests failed out of 3
++
+Subproject Time Summary:
+MySubproject += +[0-9.]+ sec \(2 tests\)
++
+Total Test time \(real\) = +[0-9.]+ sec

+ 1 - 0
Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCTestConfigNoSummary-result.txt

@@ -0,0 +1 @@
+8

+ 1 - 0
Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCTestConfigNoSummary-stderr.txt

@@ -0,0 +1 @@
+Errors while running CTest

+ 7 - 0
Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCTestConfigNoSummary-stdout.txt

@@ -0,0 +1,7 @@
+67% tests passed, 1 tests failed out of 3
++
+Label Time Summary:
+MySubproject += +[0-9.]+ sec \(2 tests\)
+NotASubproject += +[0-9.]+ sec \(1 test\)
++
+Total Test time \(real\) = +[0-9.]+ sec

+ 1 - 0
Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCommandLine-result.txt

@@ -0,0 +1 @@
+8

+ 1 - 0
Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCommandLine-stderr.txt

@@ -0,0 +1 @@
+Errors while running CTest

+ 6 - 0
Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCommandLine-stdout.txt

@@ -0,0 +1,6 @@
+50% tests passed, 1 tests failed out of 2
++
+Subproject Time Summary:
+MySubproject += +[0-9.]+ sec \(2 tests\)
++
+Total Test time \(real\) = +[0-9.]+ sec

+ 33 - 0
Tests/RunCMake/ctest_labels_for_subprojects/MyExperimentalFeature/CMakeLists.txt

@@ -0,0 +1,33 @@
+project(MyExperimentalFeature)
+cmake_minimum_required(VERSION 3.8)
+
+include(CTest)
+
+set(CMAKE_DIRECTORY_LABELS "MyExperimentalFeature;NotASubproject")
+
+add_executable(testapp experimental.c)
+
+add_test(experimentalFail1 testapp 5)
+set_tests_properties (experimentalFail1
+  PROPERTIES PASS_REGULAR_EXPRESSION "Test!"
+  )
+
+add_test(experimentalFail2 testapp -5)
+set_tests_properties (experimentalFail2
+  PROPERTIES PASS_REGULAR_EXPRESSION "Test!"
+  )
+
+add_test(experimentalFail3 testapp -5)
+set_tests_properties (experimentalFail3
+  PROPERTIES PASS_REGULAR_EXPRESSION "Test!"
+  )
+
+add_test(experimentalFail4 testapp -5)
+set_tests_properties (experimentalFail4
+  PROPERTIES PASS_REGULAR_EXPRESSION "Test!"
+  )
+
+add_test(experimentalFail5 testapp -5)
+set_tests_properties (experimentalFail5
+  PROPERTIES PASS_REGULAR_EXPRESSION "Test!"
+  )

+ 16 - 0
Tests/RunCMake/ctest_labels_for_subprojects/MyExperimentalFeature/experimental.c

@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+int main(void)
+{
+  int i = 0;
+  if (i > 0) {
+    printf("This doesn't happen.\n");
+    printf("Neither does this.\n");
+  }
+  i = i + 1;
+  if (i > 0) {
+    printf("This does happen.\n");
+  }
+
+  return 0;
+}

+ 12 - 0
Tests/RunCMake/ctest_labels_for_subprojects/MyProductionCode/CMakeLists.txt

@@ -0,0 +1,12 @@
+project(MyProductionCode)
+cmake_minimum_required(VERSION 3.8)
+
+include(CTest)
+
+add_executable(production production.c)
+add_test(NAME production COMMAND production)
+
+set_property(TARGET production PROPERTY LABELS MyProductionCode)
+set_property(TEST production PROPERTY LABELS MyProductionCode)
+
+set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY LABELS "NotASubproject")

+ 16 - 0
Tests/RunCMake/ctest_labels_for_subprojects/MyProductionCode/production.c

@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+int main(void)
+{
+  int j = 0;
+  if (j > 0) {
+    printf("This doesn't happen.\n");
+    printf("Neither does this.\n");
+  }
+  j = j + 1;
+  if (j > 0) {
+    printf("This does happen.\n");
+  }
+
+  return 0;
+}

+ 7 - 0
Tests/RunCMake/ctest_labels_for_subprojects/MyThirdPartyDependency/CMakeLists.txt

@@ -0,0 +1,7 @@
+project(MyThirdPartyDependency)
+cmake_minimum_required(VERSION 3.8)
+
+include(CTest)
+
+set_directory_properties(PROPERTIES LABELS "NotASubproject;MyThirdPartyDependency")
+add_subdirectory(src)

+ 10 - 0
Tests/RunCMake/ctest_labels_for_subprojects/MyThirdPartyDependency/src/CMakeLists.txt

@@ -0,0 +1,10 @@
+project(MyThirdPartyDependency)
+cmake_minimum_required(VERSION 3.8)
+
+include(CTest)
+
+add_executable(thirdparty thirdparty.c)
+add_test(NAME thirdparty COMMAND thirdparty)
+
+set_property(TARGET thirdparty PROPERTY LABELS NotASubproject)
+set_property(TEST thirdparty PROPERTY LABELS NotASubproject)

+ 14 - 0
Tests/RunCMake/ctest_labels_for_subprojects/MyThirdPartyDependency/src/thirdparty.c

@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+int main(void)
+{
+  printf(This function has an error!\n");
+  n = 5;
+  return 0;
+}
+
+int notcalled()
+{
+  printf(This function doesn't get called.\n");
+  return 0;
+}

+ 185 - 0
Tests/RunCMake/ctest_labels_for_subprojects/RunCMakeTest.cmake

@@ -0,0 +1,185 @@
+include(RunCTest)
+
+
+# 1. Specify subprojects in the CTest script
+function(run_CTestScriptVariable)
+  set(CTEST_EXTRA_CONFIG "set(CTEST_USE_LAUNCHERS 1)")
+  set(CASE_TEST_PREFIX_CODE [[
+file(COPY "${CTEST_RUNCMAKE_SOURCE_DIRECTORY}/MyProductionCode"
+  DESTINATION ${CTEST_SOURCE_DIRECTORY})
+file(COPY "${CTEST_RUNCMAKE_SOURCE_DIRECTORY}/MyExperimentalFeature"
+  DESTINATION ${CTEST_SOURCE_DIRECTORY})
+
+set(CTEST_LABELS_FOR_SUBPROJECTS "MyProductionCode;MyExperimentalFeature")
+  ]])
+  set(CASE_CMAKELISTS_SUFFIX_CODE [[
+add_subdirectory(MyExperimentalFeature)
+add_subdirectory(MyProductionCode)
+  ]])
+
+  run_ctest(CTestScriptVariable)
+
+  unset(CTEST_EXTRA_CONFIG)
+  unset(CASE_TEST_PREFIX_CODE)
+  unset(CASE_CMAKELISTS_SUFFIX_CODE)
+endfunction()
+run_CTestScriptVariable()
+
+# 2. Specify subprojects via a CTest script variable on the command line e.g.
+#    ctest -S test.cmake -DCTEST_LABELS_FOR_SUBPROJECTS:STRING="MySubproject"
+# Note: This test includes a failing build
+function(run_CTestScriptVariableCommandLine)
+  set(CTEST_EXTRA_CONFIG "set(CTEST_USE_LAUNCHERS 1)")
+  set(CASE_TEST_PREFIX_CODE [[
+file(COPY "${CTEST_RUNCMAKE_SOURCE_DIRECTORY}/MyThirdPartyDependency"
+  DESTINATION ${CTEST_SOURCE_DIRECTORY})
+  ]])
+  set(CASE_CMAKELISTS_SUFFIX_CODE [[
+add_subdirectory(MyThirdPartyDependency)
+  ]])
+
+  run_ctest(CTestScriptVariableCommandLine "-DCTEST_LABELS_FOR_SUBPROJECTS:STRING=MyThirdPartyDependency")
+
+  unset(CTEST_EXTRA_CONFIG)
+  unset(CASE_TEST_PREFIX_CODE)
+  unset(CASE_CMAKELISTS_SUFFIX_CODE)
+endfunction()
+run_CTestScriptVariableCommandLine()
+
+# 3. Set subprojects via a CTest module variable on the command line
+#    (will populate DartConfiguration.tcl)
+function(run_ModuleVariableCommandLine)
+  set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/ModuleVariableCommandLine")
+  set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/ModuleVariableCommandLine-build")
+  set(RunCMake_TEST_NO_CLEAN 1)
+  file(REMOVE_RECURSE "${RunCMake_TEST_SOURCE_DIR}")
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+  set(CASE_CMAKELISTS_SUFFIX_CODE [[
+set(someFile "${CMAKE_CURRENT_SOURCE_DIR}/test.cmake")
+add_test(NAME SuccessfulTest COMMAND "${CMAKE_COMMAND}" --version)
+set_property(TEST SuccessfulTest PROPERTY LABELS MySubproject)
+add_test(NAME FailingTest
+          COMMAND ${CMAKE_COMMAND} -E compare_files "${someFile}" "${someFile}xxx")
+set_property(TEST FailingTest PROPERTY LABELS MySubproject)
+  ]])
+  configure_file(${RunCMake_SOURCE_DIR}/CMakeLists.txt.in
+                 ${RunCMake_TEST_SOURCE_DIR}/CMakeLists.txt @ONLY)
+
+  set(RunCMake_TEST_OPTIONS "-DCTEST_LABELS_FOR_SUBPROJECTS:STRING=MySubproject")
+  run_cmake(ModuleVariableCommandLine-cmake)
+  unset(RunCMake_TEST_OPTIONS)
+  run_cmake_command(ModuleVariableCommandLine ${CMAKE_CTEST_COMMAND} -C Debug -V)
+
+  unset(RunCMake_TEST_SOURCE_DIR)
+  unset(RunCMake_TEST_BINARY_DIR)
+  unset(RunCMake_TEST_NO_CLEAN)
+  unset(CASE_CMAKELISTS_SUFFIX_CODE)
+endfunction()
+run_ModuleVariableCommandLine()
+
+# 4. Set subprojects via a CTest module variable in CMakeLists.txt
+#    (will populate DartConfiguration.tcl)
+function(run_ModuleVariableCMakeLists)
+  set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/ModuleVariableCMakeLists")
+  set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/ModuleVariableCMakeLists-build")
+  set(RunCMake_TEST_NO_CLEAN 1)
+  file(REMOVE_RECURSE "${RunCMake_TEST_SOURCE_DIR}")
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+  set(CASE_CMAKELISTS_PREFIX_CODE [[
+set(CTEST_LABELS_FOR_SUBPROJECTS MySubproject)
+]])
+
+  set(CASE_CMAKELISTS_SUFFIX_CODE [[
+set(someFile "${CMAKE_CURRENT_SOURCE_DIR}/test.cmake")
+add_test(NAME SuccessfulTest COMMAND "${CMAKE_COMMAND}" --version)
+set_property(TEST SuccessfulTest PROPERTY LABELS MySubproject)
+add_test(NAME FailingTest
+          COMMAND ${CMAKE_COMMAND} -E compare_files "${someFile}" "${someFile}xxx")
+set_property(TEST FailingTest PROPERTY LABELS MySubproject)
+  ]])
+  configure_file(${RunCMake_SOURCE_DIR}/CMakeLists.txt.in
+                 ${RunCMake_TEST_SOURCE_DIR}/CMakeLists.txt @ONLY)
+
+  run_cmake(ModuleVariableCMakeLists-cmake)
+  run_cmake_command(ModuleVariableCMakeLists ${CMAKE_CTEST_COMMAND} -C Debug -V)
+
+  unset(RunCMake_TEST_SOURCE_DIR)
+  unset(RunCMake_TEST_BINARY_DIR)
+  unset(RunCMake_TEST_NO_CLEAN)
+  unset(CASE_CMAKELISTS_SUFFIX_CODE)
+  unset(CASE_CMAKELISTS_SUFFIX_CODE)
+endfunction()
+run_ModuleVariableCMakeLists()
+
+# The remaining tests set subprojects in CTestConfig.cmake. Settings in this
+# config file are shared by both the CTest module and the ctest command line
+# `Dashboard Client` mode (e.g. ctest -S).
+
+function(run_ModuleVariableCTestConfig CASE_NAME)
+  set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/${CASE_NAME}")
+  set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${CASE_NAME}-build")
+  set(RunCMake_TEST_NO_CLEAN 1)
+  file(REMOVE_RECURSE "${RunCMake_TEST_SOURCE_DIR}")
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+  set(CTEST_EXTRA_CONFIG "set(CTEST_LABELS_FOR_SUBPROJECTS \"MySubproject\")")
+  configure_file(${RunCMake_SOURCE_DIR}/CTestConfig.cmake.in
+                 ${RunCMake_TEST_SOURCE_DIR}/CTestConfig.cmake @ONLY)
+
+  set(CASE_CMAKELISTS_SUFFIX_CODE [[
+set(someFile "${CMAKE_CURRENT_SOURCE_DIR}/test.cmake")
+add_test(NAME SuccessfulTest COMMAND "${CMAKE_COMMAND}" --version)
+set_property(TEST SuccessfulTest PROPERTY LABELS MySubproject)
+add_test(NAME FailingTest
+          COMMAND ${CMAKE_COMMAND} -E compare_files "${someFile}" "${someFile}xxx")
+set_property(TEST FailingTest PROPERTY LABELS MySubproject)
+add_test(NAME AnotherSuccessfulTest COMMAND "${CMAKE_COMMAND}" --version)
+set_property(TEST AnotherSuccessfulTest PROPERTY LABELS NotASubproject)
+  ]])
+  configure_file(${RunCMake_SOURCE_DIR}/CMakeLists.txt.in
+                 ${RunCMake_TEST_SOURCE_DIR}/CMakeLists.txt @ONLY)
+
+  run_cmake(${CASE_NAME}-cmake)
+  run_cmake_command(${CASE_NAME} ${CMAKE_CTEST_COMMAND} -C Debug -V ${ARGN})
+
+  unset(RunCMake_TEST_SOURCE_DIR)
+  unset(RunCMake_TEST_BINARY_DIR)
+  unset(RunCMake_TEST_NO_CLEAN)
+  unset(CTEST_EXTRA_CONFIG)
+  unset(CASE_CMAKELISTS_SUFFIX_CODE)
+endfunction()
+
+# 5. Check that the Subproject timing Summary is printed
+run_ModuleVariableCTestConfig(ModuleVariableCTestConfig)
+
+# 6. Use --no-subproject-summary to disable the Subproject timing summary.
+run_ModuleVariableCTestConfig(ModuleVariableCTestConfigNoSummary --no-subproject-summary)
+
+# 7. Verify that subprojects are sent to CDash when running a CTest script
+function(run_CTestConfigCTestScript)
+  set(CTEST_EXTRA_CONFIG [[
+set(CTEST_USE_LAUNCHERS 1)
+set(CTEST_LABELS_FOR_SUBPROJECTS "MyProductionCode;MyExperimentalFeature")
+  ]])
+  set(CASE_TEST_PREFIX_CODE [[
+file(COPY "${CTEST_RUNCMAKE_SOURCE_DIRECTORY}/MyProductionCode"
+  DESTINATION ${CTEST_SOURCE_DIRECTORY})
+file(COPY "${CTEST_RUNCMAKE_SOURCE_DIRECTORY}/MyExperimentalFeature"
+  DESTINATION ${CTEST_SOURCE_DIRECTORY})
+  ]])
+  set(CASE_CMAKELISTS_SUFFIX_CODE [[
+add_subdirectory(MyExperimentalFeature)
+add_subdirectory(MyProductionCode)
+  ]])
+  run_ctest(CTestConfigCTestScript)
+
+  unset(CTEST_EXTRA_CONFIG)
+  unset(CASE_TEST_PREFIX_CODE)
+  unset(CASE_CMAKELISTS_SUFFIX_CODE)
+endfunction()
+run_CTestConfigCTestScript()

+ 21 - 0
Tests/RunCMake/ctest_labels_for_subprojects/test.cmake.in

@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 3.7)
+
+# Settings:
+
+set(CTEST_SITE                          "test-site")
+set(CTEST_BUILD_NAME                    "test-build-name")
+set(CTEST_SOURCE_DIRECTORY              "@RunCMake_BINARY_DIR@/@CASE_NAME@")
+set(CTEST_BINARY_DIRECTORY              "@RunCMake_BINARY_DIR@/@CASE_NAME@-build")
+set(CTEST_CMAKE_GENERATOR               "@RunCMake_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM      "@RunCMake_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET       "@RunCMake_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION           "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_RUNCMAKE_SOURCE_DIRECTORY     "@RunCMake_SOURCE_DIR@")
+
+@CASE_TEST_PREFIX_CODE@
+
+set(ctest_test_args "@CASE_CTEST_TEST_ARGS@")
+ctest_start(Experimental)
+ctest_configure()
+ctest_build()
+ctest_test(${ctest_test_args})

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác