Commit f5be9511 authored by Brad King's avatar Brad King Committed by Kitware Robot

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's avatarKitware Robot <kwrobot@kitware.com>
Merge-request: !1004
parents 37915a69 376dc3eb
This diff is collapsed.
......@@ -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
......
......@@ -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
......
......@@ -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.
......
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.
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.
CMAKE_DIRECTORY_LABELS
-----------------------
Specify labels for the current directory.
This is used to initialize the :prop_dir:`LABELS` directory property.
CTEST_LABELS_FOR_SUBPROJECTS
----------------------------
Specify the CTest ``LabelsForSubprojects`` setting
in a :manual:`ctest(1)` dashboard client script.
......@@ -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@
......
......@@ -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;
}
......
......@@ -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",
......
......@@ -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) {
......
......@@ -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);
......
......@@ -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:
......
......@@ -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
......
......@@ -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;
}
......
......@@ -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];
......
......@@ -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
*/
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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",
......
......@@ -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;
......
......@@ -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) {
......
......@@ -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"));
......
......@@ -83,6 +83,8 @@ static const char* cmDocumentationOptions[][2] = {