summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/command/add_custom_command.rst11
-rw-r--r--Help/command/add_custom_target.rst9
-rw-r--r--Help/release/dev/expand_custom_commands.rst7
-rw-r--r--Modules/FindHDF5.cmake8
-rw-r--r--Modules/FindICU.cmake1
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/CTest/cmCTestTestHandler.cxx82
-rw-r--r--Source/cmAddCustomCommandCommand.cxx9
-rw-r--r--Source/cmAddCustomTargetCommand.cxx13
-rw-r--r--Source/cmCustomCommand.cxx12
-rw-r--r--Source/cmCustomCommand.h5
-rw-r--r--Source/cmCustomCommandGenerator.cxx32
-rw-r--r--Source/cmCustomCommandGenerator.h2
-rw-r--r--Source/cmFileCommand.cxx2
-rw-r--r--Source/cmMakefile.cxx22
-rw-r--r--Source/cmMakefile.h15
-rw-r--r--Source/kwsys/CMakeLists.txt3
-rw-r--r--Source/kwsys/SystemTools.cxx11
-rw-r--r--Source/kwsys/testSystemTools.cxx53
-rw-r--r--Tests/CustomCommand/CMakeLists.txt21
-rw-r--r--Tests/CustomCommand/compare_options.cmake14
-rw-r--r--Tests/RunCMake/ctest_fixtures/CMakeLists.txt.in6
-rw-r--r--Tests/RunCMake/ctest_fixtures/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/ctest_fixtures/unused-stdout.txt9
-rw-r--r--Tests/RunCMake/file/GLOB-noexp-LIST_DIRECTORIES.cmake1
-rw-r--r--Tests/RunCMake/file/RunCMakeTest.cmake1
26 files changed, 291 insertions, 61 deletions
diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst
index 4ab4298..80e7edf 100644
--- a/Help/command/add_custom_command.rst
+++ b/Help/command/add_custom_command.rst
@@ -21,7 +21,8 @@ The first signature is for adding a custom command to produce an output::
[WORKING_DIRECTORY dir]
[COMMENT comment]
[DEPFILE depfile]
- [VERBATIM] [APPEND] [USES_TERMINAL])
+ [VERBATIM] [APPEND] [USES_TERMINAL]
+ [COMMAND_EXPAND_LISTS])
This defines a command to generate specified ``OUTPUT`` file(s).
A target created in the same directory (``CMakeLists.txt`` file)
@@ -122,6 +123,14 @@ The options are:
Arguments to ``DEPENDS`` may use
:manual:`generator expressions <cmake-generator-expressions(7)>`.
+``COMMAND_EXPAND_LISTS``
+ Lists in ``COMMAND`` arguments will be expanded, including those
+ created with
+ :manual:`generator expressions <cmake-generator-expressions(7)>`,
+ allowing ``COMMAND`` arguments such as
+ ``${CC} "-I$<JOIN:$<TARGET_PROPERTY:foo,INCLUDE_DIRECTORIES>,;-I>" foo.cc``
+ to be properly expanded.
+
``IMPLICIT_DEPENDS``
Request scanning of implicit dependencies of an input file.
The language given specifies the programming language whose
diff --git a/Help/command/add_custom_target.rst b/Help/command/add_custom_target.rst
index 6980d61..bd61c8b 100644
--- a/Help/command/add_custom_target.rst
+++ b/Help/command/add_custom_target.rst
@@ -12,6 +12,7 @@ Add a target with no output so it will always be built.
[WORKING_DIRECTORY dir]
[COMMENT comment]
[VERBATIM] [USES_TERMINAL]
+ [COMMAND_EXPAND_LISTS]
[SOURCES src1 [src2...]])
Adds a target with the given name that executes the given commands.
@@ -88,6 +89,14 @@ The options are:
Use the :command:`add_dependencies` command to add dependencies
on other targets.
+``COMMAND_EXPAND_LISTS``
+ Lists in ``COMMAND`` arguments will be expanded, including those
+ created with
+ :manual:`generator expressions <cmake-generator-expressions(7)>`,
+ allowing ``COMMAND`` arguments such as
+ ``${CC} "-I$<JOIN:$<TARGET_PROPERTY:foo,INCLUDE_DIRECTORIES>,;-I>" foo.cc``
+ to be properly expanded.
+
``SOURCES``
Specify additional source files to be included in the custom target.
Specified source files will be added to IDE project files for
diff --git a/Help/release/dev/expand_custom_commands.rst b/Help/release/dev/expand_custom_commands.rst
new file mode 100644
index 0000000..c8cd897
--- /dev/null
+++ b/Help/release/dev/expand_custom_commands.rst
@@ -0,0 +1,7 @@
+expand_custom_commands
+----------------------
+
+* The commands :command:`add_custom_command` and :command:`add_custom_target`
+ learned the option ``COMMAND_EXPAND_LISTS`` which causes lists in the
+ ``COMMAND`` argument to be expanded, including lists created by generator
+ expressions.
diff --git a/Modules/FindHDF5.cmake b/Modules/FindHDF5.cmake
index 16764e0..6e5a25e 100644
--- a/Modules/FindHDF5.cmake
+++ b/Modules/FindHDF5.cmake
@@ -439,8 +439,8 @@ if(NOT HDF5_FOUND AND NOT HDF5_ROOT)
set(HDF5_${_lang}_LIBRARY ${_lang_location} CACHE PATH
"HDF5 ${_lang} library" )
mark_as_advanced(HDF5_${_lang}_LIBRARY)
- list(APPEND HDF5_LIBRARIES ${HDF5_${_lang}_LIBRARY})
- set(HDF5_${_lang}_LIBRARIES ${HDF5_${_lang}_LIBRARY})
+ list(APPEND HDF5_LIBRARIES ${HDF5_${_lang}_TARGET}${_suffix})
+ set(HDF5_${_lang}_LIBRARIES ${HDF5_${_lang}_TARGET}${_suffix})
set(HDF5_${_lang}_FOUND True)
endif()
if(FIND_HL)
@@ -449,8 +449,8 @@ if(NOT HDF5_FOUND AND NOT HDF5_ROOT)
set(HDF5_${_lang}_HL_LIBRARY ${_lang_hl_location} CACHE PATH
"HDF5 ${_lang} HL library" )
mark_as_advanced(HDF5_${_lang}_HL_LIBRARY)
- list(APPEND HDF5_HL_LIBRARIES ${HDF5_${_lang}_HL_LIBRARY})
- set(HDF5_${_lang}_HL_LIBRARIES ${HDF5_${_lang}_HL_LIBRARY})
+ list(APPEND HDF5_HL_LIBRARIES ${HDF5_${_lang}_TARGET}${_suffix})
+ set(HDF5_${_lang}_HL_LIBRARIES ${HDF5_${_lang}_TARGET}${_suffix})
set(HDF5_HL_FOUND True)
endif()
endif()
diff --git a/Modules/FindICU.cmake b/Modules/FindICU.cmake
index 36dd67e..5210f08 100644
--- a/Modules/FindICU.cmake
+++ b/Modules/FindICU.cmake
@@ -126,6 +126,7 @@ function(_ICU_FIND)
# Generic 64-bit and 32-bit directories
list(APPEND icu_binary_suffixes "${_bin64}" "bin")
list(APPEND icu_library_suffixes "${_lib64}" "lib")
+ list(APPEND icu_include_suffixes "include")
# Find all ICU programs
foreach(program ${icu_programs})
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 0c64d70..d1054cf 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,5 +1,5 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 3)
set(CMake_VERSION_MINOR 7)
-set(CMake_VERSION_PATCH 20170116)
+set(CMake_VERSION_PATCH 20170117)
#set(CMake_VERSION_RC 1)
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index 4e63654..6175e50 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -829,23 +829,31 @@ void cmCTestTestHandler::UpdateForFixtures(ListOfTests& tests) const
addedTests.insert(p.Name);
}
- // This is a lookup of fixture name to a list of indices into the
- // final tests array for tests which require that fixture. It is
- // needed at the end to populate dependencies of the cleanup tests
- // in our final list of tests.
+ // These are lookups of fixture name to a list of indices into the final
+ // tests array for tests which require that fixture and tests which are
+ // setups for that fixture. They are needed at the end to populate
+ // dependencies of the cleanup tests in our final list of tests.
std::map<std::string, std::vector<size_t> > fixtureRequirements;
+ std::map<std::string, std::vector<size_t> > setupFixturesAdded;
// Use integer index for iteration because we append to
// the tests vector as we go
size_t fixtureTestsAdded = 0;
std::set<std::string> addedFixtures;
for (size_t i = 0; i < tests.size(); ++i) {
- if (tests[i].FixturesRequired.empty()) {
- continue;
- }
- // Must copy the set of fixtures because we may invalidate
+ // There are two things to do for each test:
+ // 1. For every fixture required by this test, record that fixture as
+ // being required and create dependencies on that fixture's setup
+ // tests.
+ // 2. Record all setup tests in the final test list so we can later make
+ // cleanup tests in the test list depend on their associated setup
+ // tests to enforce correct ordering.
+
+ // 1. Handle fixture requirements
+ //
+ // Must copy the set of fixtures required because we may invalidate
// the tests array by appending to it
- const std::set<std::string> fixtures = tests[i].FixturesRequired;
+ std::set<std::string> fixtures = tests[i].FixturesRequired;
for (std::set<std::string>::const_iterator fixturesIt = fixtures.begin();
fixturesIt != fixtures.end(); ++fixturesIt) {
@@ -908,32 +916,62 @@ void cmCTestTestHandler::UpdateForFixtures(ListOfTests& tests) const
this->Quiet);
}
}
+
+ // 2. Record all setup fixtures included in the final list of tests
+ for (std::set<std::string>::const_iterator fixturesIt =
+ tests[i].FixturesSetup.begin();
+ fixturesIt != tests[i].FixturesSetup.end(); ++fixturesIt) {
+
+ const std::string& setupFixtureName = *fixturesIt;
+ if (setupFixtureName.empty()) {
+ continue;
+ }
+
+ setupFixturesAdded[setupFixtureName].push_back(i);
+ }
}
// Now that we have the final list of tests, we can update all cleanup
- // tests to depend on those tests which require that fixture
+ // tests to depend on those tests which require that fixture and on any
+ // setup tests for that fixture. The latter is required to handle the
+ // pathological case where setup and cleanup tests are in the test set
+ // but no other test has that fixture as a requirement.
for (ListOfTests::iterator tIt = tests.begin(); tIt != tests.end(); ++tIt) {
cmCTestTestProperties& p = *tIt;
const std::set<std::string>& cleanups = p.FixturesCleanup;
for (std::set<std::string>::const_iterator fIt = cleanups.begin();
fIt != cleanups.end(); ++fIt) {
const std::string& fixture = *fIt;
+
+ // This cleanup test could be part of the original test list that was
+ // passed in. It is then possible that no other test requires the
+ // fIt fixture, so we have to check for this.
std::map<std::string, std::vector<size_t> >::const_iterator cIt =
fixtureRequirements.find(fixture);
- if (cIt == fixtureRequirements.end()) {
- // No test cases require the fixture this cleanup test is for.
- // This cleanup test must have been part of the original test
- // list passed in (which is not an error)
- continue;
+ if (cIt != fixtureRequirements.end()) {
+ const std::vector<size_t>& indices = cIt->second;
+ for (std::vector<size_t>::const_iterator indexIt = indices.begin();
+ indexIt != indices.end(); ++indexIt) {
+ const std::string& reqTestName = tests[*indexIt].Name;
+ if (std::find(p.Depends.begin(), p.Depends.end(), reqTestName) ==
+ p.Depends.end()) {
+ p.Depends.push_back(reqTestName);
+ }
+ }
}
- const std::vector<size_t>& indices = cIt->second;
- for (std::vector<size_t>::const_iterator indexIt = indices.begin();
- indexIt != indices.end(); ++indexIt) {
- const std::string& reqTestName = tests[*indexIt].Name;
- if (std::find(p.Depends.begin(), p.Depends.end(), reqTestName) ==
- p.Depends.end()) {
- p.Depends.push_back(reqTestName);
+ // Ensure fixture cleanup tests always run after their setup tests, even
+ // if no other test cases require the fixture
+ cIt = setupFixturesAdded.find(fixture);
+ if (cIt != setupFixturesAdded.end()) {
+ const std::vector<size_t>& indices = cIt->second;
+ for (std::vector<size_t>::const_iterator indexIt = indices.begin();
+ indexIt != indices.end(); ++indexIt) {
+ const std::string& setupTestName = tests[*indexIt].Name;
+ if (std::find(p.Depends.begin(), p.Depends.end(), setupTestName) ==
+ p.Depends.end()) {
+ p.Depends.push_back(setupTestName);
+ }
}
}
}
diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx
index 620de31..a100617 100644
--- a/Source/cmAddCustomCommandCommand.cxx
+++ b/Source/cmAddCustomCommandCommand.cxx
@@ -36,6 +36,7 @@ bool cmAddCustomCommandCommand::InitialPass(
bool verbatim = false;
bool append = false;
bool uses_terminal = false;
+ bool command_expand_lists = false;
std::string implicit_depends_lang;
cmCustomCommand::ImplicitDependsList implicit_depends;
@@ -92,6 +93,8 @@ bool cmAddCustomCommandCommand::InitialPass(
append = true;
} else if (copy == "USES_TERMINAL") {
uses_terminal = true;
+ } else if (copy == "COMMAND_EXPAND_LISTS") {
+ command_expand_lists = true;
} else if (copy == "TARGET") {
doing = doing_target;
} else if (copy == "ARGS") {
@@ -281,12 +284,14 @@ bool cmAddCustomCommandCommand::InitialPass(
std::vector<std::string> no_depends;
this->Makefile->AddCustomCommandToTarget(
target, byproducts, no_depends, commandLines, cctype, comment,
- working.c_str(), escapeOldStyle, uses_terminal, depfile);
+ working.c_str(), escapeOldStyle, uses_terminal, depfile,
+ command_expand_lists);
} else if (target.empty()) {
// Target is empty, use the output.
this->Makefile->AddCustomCommandToOutput(
output, byproducts, depends, main_dependency, commandLines, comment,
- working.c_str(), false, escapeOldStyle, uses_terminal, depfile);
+ working.c_str(), false, escapeOldStyle, uses_terminal,
+ command_expand_lists, depfile);
// Add implicit dependency scanning requests if any were given.
if (!implicit_depends.empty()) {
diff --git a/Source/cmAddCustomTargetCommand.cxx b/Source/cmAddCustomTargetCommand.cxx
index 56f33b4..0d01493 100644
--- a/Source/cmAddCustomTargetCommand.cxx
+++ b/Source/cmAddCustomTargetCommand.cxx
@@ -47,6 +47,7 @@ bool cmAddCustomTargetCommand::InitialPass(
std::string working_directory;
bool verbatim = false;
bool uses_terminal = false;
+ bool command_expand_lists = false;
std::string comment_buffer;
const char* comment = CM_NULLPTR;
std::vector<std::string> sources;
@@ -90,6 +91,9 @@ bool cmAddCustomTargetCommand::InitialPass(
} else if (copy == "USES_TERMINAL") {
doing = doing_nothing;
uses_terminal = true;
+ } else if (copy == "COMMAND_EXPAND_LISTS") {
+ doing = doing_nothing;
+ command_expand_lists = true;
} else if (copy == "COMMENT") {
doing = doing_comment;
} else if (copy == "COMMAND") {
@@ -221,12 +225,19 @@ bool cmAddCustomTargetCommand::InitialPass(
"USES_TERMINAL may not be specified without any COMMAND");
return true;
}
+ if (commandLines.empty() && command_expand_lists) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "COMMAND_EXPAND_LISTS may not be specified without any COMMAND");
+ return true;
+ }
// Add the utility target to the makefile.
bool escapeOldStyle = !verbatim;
cmTarget* target = this->Makefile->AddUtilityCommand(
targetName, excludeFromAll, working_directory.c_str(), byproducts, depends,
- commandLines, escapeOldStyle, comment, uses_terminal);
+ commandLines, escapeOldStyle, comment, uses_terminal,
+ command_expand_lists);
// Add additional user-specified source files to the target.
target->AddSources(sources);
diff --git a/Source/cmCustomCommand.cxx b/Source/cmCustomCommand.cxx
index 6645b8e..050de17 100644
--- a/Source/cmCustomCommand.cxx
+++ b/Source/cmCustomCommand.cxx
@@ -13,6 +13,7 @@ cmCustomCommand::cmCustomCommand()
this->EscapeOldStyle = true;
this->EscapeAllowMakeVars = false;
this->UsesTerminal = false;
+ this->CommandExpandLists = false;
}
cmCustomCommand::cmCustomCommand(cmMakefile const* mf,
@@ -32,6 +33,7 @@ cmCustomCommand::cmCustomCommand(cmMakefile const* mf,
, HaveComment(comment != CM_NULLPTR)
, EscapeAllowMakeVars(false)
, EscapeOldStyle(true)
+ , CommandExpandLists(false)
{
if (mf) {
this->Backtrace = mf->GetBacktrace();
@@ -127,6 +129,16 @@ void cmCustomCommand::SetUsesTerminal(bool b)
this->UsesTerminal = b;
}
+bool cmCustomCommand::GetCommandExpandLists() const
+{
+ return this->CommandExpandLists;
+}
+
+void cmCustomCommand::SetCommandExpandLists(bool b)
+{
+ this->CommandExpandLists = b;
+}
+
const std::string& cmCustomCommand::GetDepfile() const
{
return this->Depfile;
diff --git a/Source/cmCustomCommand.h b/Source/cmCustomCommand.h
index 66f8fa9..73d53ff 100644
--- a/Source/cmCustomCommand.h
+++ b/Source/cmCustomCommand.h
@@ -85,6 +85,10 @@ public:
bool GetUsesTerminal() const;
void SetUsesTerminal(bool b);
+ /** Set/Get whether lists in command lines should be expanded. */
+ bool GetCommandExpandLists() const;
+ void SetCommandExpandLists(bool b);
+
/** Set/Get the depfile (used by the Ninja generator) */
const std::string& GetDepfile() const;
void SetDepfile(const std::string& depfile);
@@ -103,6 +107,7 @@ private:
bool EscapeAllowMakeVars;
bool EscapeOldStyle;
bool UsesTerminal;
+ bool CommandExpandLists;
};
#endif
diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx
index 8bd3a89..8f4ff4b 100644
--- a/Source/cmCustomCommandGenerator.cxx
+++ b/Source/cmCustomCommandGenerator.cxx
@@ -26,6 +26,24 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
, GE(new cmGeneratorExpression(cc.GetBacktrace()))
, DependsDone(false)
{
+ const cmCustomCommandLines& cmdlines = this->CC.GetCommandLines();
+ for (cmCustomCommandLines::const_iterator cmdline = cmdlines.begin();
+ cmdline != cmdlines.end(); ++cmdline) {
+ cmCustomCommandLine argv;
+ for (cmCustomCommandLine::const_iterator clarg = cmdline->begin();
+ clarg != cmdline->end(); ++clarg) {
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = this->GE->Parse(*clarg);
+ std::string parsed_arg = cge->Evaluate(this->LG, this->Config);
+ if (this->CC.GetCommandExpandLists()) {
+ std::vector<std::string> ExpandedArg;
+ cmSystemTools::ExpandListArgument(parsed_arg, ExpandedArg);
+ argv.insert(argv.end(), ExpandedArg.begin(), ExpandedArg.end());
+ } else {
+ argv.push_back(parsed_arg);
+ }
+ }
+ this->CommandLines.push_back(argv);
+ }
}
cmCustomCommandGenerator::~cmCustomCommandGenerator()
@@ -44,7 +62,7 @@ const char* cmCustomCommandGenerator::GetCrossCompilingEmulator(
if (!this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING")) {
return CM_NULLPTR;
}
- std::string const& argv0 = this->CC.GetCommandLines()[c][0];
+ std::string const& argv0 = this->CommandLines[c][0];
cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0);
if (target && target->GetType() == cmStateEnums::EXECUTABLE &&
!target->IsImported()) {
@@ -55,7 +73,7 @@ const char* cmCustomCommandGenerator::GetCrossCompilingEmulator(
const char* cmCustomCommandGenerator::GetArgv0Location(unsigned int c) const
{
- std::string const& argv0 = this->CC.GetCommandLines()[c][0];
+ std::string const& argv0 = this->CommandLines[c][0];
cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0);
if (target && target->GetType() == cmStateEnums::EXECUTABLE &&
(target->IsImported() ||
@@ -75,11 +93,7 @@ std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const
return std::string(location);
}
- std::string const& argv0 = this->CC.GetCommandLines()[c][0];
- CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = this->GE->Parse(argv0);
- std::string exe = cge->Evaluate(this->LG, this->Config);
-
- return exe;
+ return this->CommandLines[c][0];
}
std::string escapeForShellOldStyle(const std::string& str)
@@ -114,7 +128,7 @@ void cmCustomCommandGenerator::AppendArguments(unsigned int c,
if (this->GetCrossCompilingEmulator(c) != CM_NULLPTR) {
offset = 0;
}
- cmCustomCommandLine const& commandLine = this->CC.GetCommandLines()[c];
+ cmCustomCommandLine const& commandLine = this->CommandLines[c];
for (unsigned int j = offset; j < commandLine.size(); ++j) {
std::string arg;
if (const char* location =
@@ -123,7 +137,7 @@ void cmCustomCommandGenerator::AppendArguments(unsigned int c,
// so transform the latter now.
arg = location;
} else {
- arg = this->GE->Parse(commandLine[j])->Evaluate(this->LG, this->Config);
+ arg = commandLine[j];
}
cmd += " ";
if (this->OldStyle) {
diff --git a/Source/cmCustomCommandGenerator.h b/Source/cmCustomCommandGenerator.h
index 8983c54..286aaf3 100644
--- a/Source/cmCustomCommandGenerator.h
+++ b/Source/cmCustomCommandGenerator.h
@@ -3,6 +3,7 @@
#ifndef cmCustomCommandGenerator_h
#define cmCustomCommandGenerator_h
+#include "cmCustomCommandLines.h"
#include <cmConfigure.h> // IWYU pragma: keep
#include <string>
@@ -22,6 +23,7 @@ class cmCustomCommandGenerator
cmGeneratorExpression* GE;
mutable bool DependsDone;
mutable std::vector<std::string> Depends;
+ cmCustomCommandLines CommandLines;
const char* GetCrossCompilingEmulator(unsigned int c) const;
const char* GetArgv0Location(unsigned int c) const;
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index d10c886..91cecb3 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -788,7 +788,7 @@ bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args,
this->SetError("LIST_DIRECTORIES missing bool value.");
return false;
}
- ++i;
+ continue;
}
if (recurse && (*i == "FOLLOW_SYMLINKS")) {
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index cfc0495..bfe46ae 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -692,7 +692,7 @@ void cmMakefile::AddCustomCommandToTarget(
const std::vector<std::string>& depends,
const cmCustomCommandLines& commandLines, cmTarget::CustomCommandType type,
const char* comment, const char* workingDir, bool escapeOldStyle,
- bool uses_terminal, const std::string& depfile)
+ bool uses_terminal, const std::string& depfile, bool command_expand_lists)
{
// Find the target to which to add the custom command.
cmTargets::iterator ti = this->Targets.find(target);
@@ -764,6 +764,7 @@ void cmMakefile::AddCustomCommandToTarget(
cc.SetEscapeOldStyle(escapeOldStyle);
cc.SetEscapeAllowMakeVars(true);
cc.SetUsesTerminal(uses_terminal);
+ cc.SetCommandExpandLists(command_expand_lists);
cc.SetDepfile(depfile);
switch (type) {
case cmTarget::PRE_BUILD:
@@ -784,7 +785,7 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput(
const std::vector<std::string>& depends, const std::string& main_dependency,
const cmCustomCommandLines& commandLines, const char* comment,
const char* workingDir, bool replace, bool escapeOldStyle,
- bool uses_terminal, const std::string& depfile)
+ bool uses_terminal, bool command_expand_lists, const std::string& depfile)
{
// Make sure there is at least one output.
if (outputs.empty()) {
@@ -878,6 +879,7 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput(
cc->SetEscapeOldStyle(escapeOldStyle);
cc->SetEscapeAllowMakeVars(true);
cc->SetUsesTerminal(uses_terminal);
+ cc->SetCommandExpandLists(command_expand_lists);
cc->SetDepfile(depfile);
file->SetCustomCommand(cc);
this->UpdateOutputToSourceMap(outputs, file);
@@ -916,14 +918,16 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput(
const std::string& output, const std::vector<std::string>& depends,
const std::string& main_dependency, const cmCustomCommandLines& commandLines,
const char* comment, const char* workingDir, bool replace,
- bool escapeOldStyle, bool uses_terminal, const std::string& depfile)
+ bool escapeOldStyle, bool uses_terminal, bool command_expand_lists,
+ const std::string& depfile)
{
std::vector<std::string> outputs;
outputs.push_back(output);
std::vector<std::string> no_byproducts;
return this->AddCustomCommandToOutput(
outputs, no_byproducts, depends, main_dependency, commandLines, comment,
- workingDir, replace, escapeOldStyle, uses_terminal, depfile);
+ workingDir, replace, escapeOldStyle, uses_terminal, command_expand_lists,
+ depfile);
}
void cmMakefile::AddCustomCommandOldStyle(
@@ -1018,12 +1022,13 @@ cmTarget* cmMakefile::AddUtilityCommand(
const std::string& utilityName, bool excludeFromAll,
const char* workingDirectory, const std::vector<std::string>& depends,
const cmCustomCommandLines& commandLines, bool escapeOldStyle,
- const char* comment, bool uses_terminal)
+ const char* comment, bool uses_terminal, bool command_expand_lists)
{
std::vector<std::string> no_byproducts;
return this->AddUtilityCommand(utilityName, excludeFromAll, workingDirectory,
no_byproducts, depends, commandLines,
- escapeOldStyle, comment, uses_terminal);
+ escapeOldStyle, comment, uses_terminal,
+ command_expand_lists);
}
cmTarget* cmMakefile::AddUtilityCommand(
@@ -1031,7 +1036,7 @@ cmTarget* cmMakefile::AddUtilityCommand(
const char* workingDirectory, const std::vector<std::string>& byproducts,
const std::vector<std::string>& depends,
const cmCustomCommandLines& commandLines, bool escapeOldStyle,
- const char* comment, bool uses_terminal)
+ const char* comment, bool uses_terminal, bool command_expand_lists)
{
// Create a target instance for this utility.
cmTarget* target = this->AddNewTarget(cmStateEnums::UTILITY, utilityName);
@@ -1055,7 +1060,8 @@ cmTarget* cmMakefile::AddUtilityCommand(
bool no_replace = false;
this->AddCustomCommandToOutput(
forced, byproducts, depends, no_main_dependency, commandLines, comment,
- workingDirectory, no_replace, escapeOldStyle, uses_terminal);
+ workingDirectory, no_replace, escapeOldStyle, uses_terminal,
+ command_expand_lists);
cmSourceFile* sf = target->AddSourceCMP0049(force);
// The output is not actually created so mark it symbolic.
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 3484e5a..9d9e90a 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -125,7 +125,8 @@ public:
const std::vector<std::string>& depends,
const cmCustomCommandLines& commandLines, cmTarget::CustomCommandType type,
const char* comment, const char* workingDir, bool escapeOldStyle = true,
- bool uses_terminal = false, const std::string& depfile = "");
+ bool uses_terminal = false, const std::string& depfile = "",
+ bool command_expand_lists = false);
cmSourceFile* AddCustomCommandToOutput(
const std::vector<std::string>& outputs,
const std::vector<std::string>& byproducts,
@@ -133,13 +134,15 @@ public:
const std::string& main_dependency,
const cmCustomCommandLines& commandLines, const char* comment,
const char* workingDir, bool replace = false, bool escapeOldStyle = true,
- bool uses_terminal = false, const std::string& depfile = "");
+ bool uses_terminal = false, bool command_expand_lists = false,
+ const std::string& depfile = "");
cmSourceFile* AddCustomCommandToOutput(
const std::string& output, const std::vector<std::string>& depends,
const std::string& main_dependency,
const cmCustomCommandLines& commandLines, const char* comment,
const char* workingDir, bool replace = false, bool escapeOldStyle = true,
- bool uses_terminal = false, const std::string& depfile = "");
+ bool uses_terminal = false, bool command_expand_lists = false,
+ const std::string& depfile = "");
void AddCustomCommandOldStyle(const std::string& target,
const std::vector<std::string>& outputs,
const std::vector<std::string>& depends,
@@ -182,13 +185,15 @@ public:
const std::string& utilityName, bool excludeFromAll,
const char* workingDirectory, const std::vector<std::string>& depends,
const cmCustomCommandLines& commandLines, bool escapeOldStyle = true,
- const char* comment = CM_NULLPTR, bool uses_terminal = false);
+ const char* comment = CM_NULLPTR, bool uses_terminal = false,
+ bool command_expand_lists = false);
cmTarget* AddUtilityCommand(
const std::string& utilityName, bool excludeFromAll,
const char* workingDirectory, const std::vector<std::string>& byproducts,
const std::vector<std::string>& depends,
const cmCustomCommandLines& commandLines, bool escapeOldStyle = true,
- const char* comment = CM_NULLPTR, bool uses_terminal = false);
+ const char* comment = CM_NULLPTR, bool uses_terminal = false,
+ bool command_expand_lists = false);
/**
* Add a subdirectory to the build.
diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt
index 9eb3b2d..d4fe8a7 100644
--- a/Source/kwsys/CMakeLists.txt
+++ b/Source/kwsys/CMakeLists.txt
@@ -818,6 +818,9 @@ IF(KWSYS_C_SRCS OR KWSYS_CXX_SRCS)
# for symbol lookup using dladdr
TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE} ${CMAKE_DL_LIBS})
ENDIF()
+ IF (CMAKE_SYSTEM_NAME STREQUAL "SunOS")
+ TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE} socket)
+ ENDIF()
ENDIF()
ENDIF()
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index b018a43..97dd4ae 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -763,7 +763,7 @@ bool SystemTools::MakeDirectory(const char* path)
bool SystemTools::MakeDirectory(const std::string& path)
{
- if (SystemTools::FileExists(path)) {
+ if (SystemTools::PathExists(path)) {
return SystemTools::FileIsDirectory(path);
}
if (path.empty()) {
@@ -1280,7 +1280,7 @@ bool SystemTools::PathCygwinToWin32(const char* path, char* win32_path)
bool SystemTools::Touch(const std::string& filename, bool create)
{
- if (!SystemTools::FileExists(filename)) {
+ if (!SystemTools::PathExists(filename)) {
if (create) {
FILE* file = Fopen(filename, "a+b");
if (file) {
@@ -4289,7 +4289,7 @@ bool SystemTools::GetLineFromStream(std::istream& is, std::string& line,
// if we read too much then truncate the buffer
if (leftToRead > 0) {
if (static_cast<long>(length) > leftToRead) {
- buffer[leftToRead - 1] = 0;
+ buffer[leftToRead] = 0;
leftToRead = 0;
} else {
leftToRead -= static_cast<long>(length);
@@ -4389,10 +4389,7 @@ bool SystemTools::SetPermissions(const char* file, mode_t mode,
bool SystemTools::SetPermissions(const std::string& file, mode_t mode,
bool honor_umask)
{
- // TEMPORARY / TODO: After FileExists calls lstat() instead of
- // access(), change this call to FileExists instead of
- // TestFileAccess so that we don't follow symlinks.
- if (!SystemTools::TestFileAccess(file, TEST_FILE_OK)) {
+ if (!SystemTools::PathExists(file)) {
return false;
}
if (honor_umask) {
diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx
index b04f2cb..8e1ea25 100644
--- a/Source/kwsys/testSystemTools.cxx
+++ b/Source/kwsys/testSystemTools.cxx
@@ -6,11 +6,13 @@
#pragma warning(disable : 4786)
#endif
+#include KWSYS_HEADER(FStream.hxx)
#include KWSYS_HEADER(SystemTools.hxx)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
+#include "FStream.hxx.in"
#include "SystemTools.hxx.in"
#endif
@@ -857,6 +859,55 @@ static bool CheckFind()
return res;
}
+static bool CheckGetLineFromStream()
+{
+ const std::string fileWithFiveCharsOnFirstLine(TEST_SYSTEMTOOLS_SOURCE_DIR
+ "/README.rst");
+
+ kwsys::ifstream file(fileWithFiveCharsOnFirstLine.c_str(), std::ios::in);
+
+ if (!file) {
+ std::cerr << "Problem opening: " << fileWithFiveCharsOnFirstLine
+ << std::endl;
+ return false;
+ }
+
+ std::string line;
+ bool has_newline = false;
+ bool result;
+
+ file.seekg(0, std::ios::beg);
+ result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1);
+ if (!result || line.size() != 5) {
+ std::cerr << "First line does not have five characters: " << line.size()
+ << std::endl;
+ return false;
+ }
+
+ file.seekg(0, std::ios::beg);
+ result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1);
+ if (!result || line.size() != 5) {
+ std::cerr << "First line does not have five characters after rewind: "
+ << line.size() << std::endl;
+ return false;
+ }
+
+ bool ret = true;
+
+ for (size_t size = 1; size <= 5; ++size) {
+ file.seekg(0, std::ios::beg);
+ result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline,
+ static_cast<long>(size));
+ if (!result || line.size() != size) {
+ std::cerr << "Should have read " << size << " characters but got "
+ << line.size() << std::endl;
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
//----------------------------------------------------------------------------
int testSystemTools(int, char* [])
{
@@ -893,5 +944,7 @@ int testSystemTools(int, char* [])
res &= CheckFind();
+ res &= CheckGetLineFromStream();
+
return res ? 0 : 1;
}
diff --git a/Tests/CustomCommand/CMakeLists.txt b/Tests/CustomCommand/CMakeLists.txt
index db57e19..e9a9f52 100644
--- a/Tests/CustomCommand/CMakeLists.txt
+++ b/Tests/CustomCommand/CMakeLists.txt
@@ -513,3 +513,24 @@ add_custom_target(UseConsoleTarget ALL
VERBATIM
USES_TERMINAL
)
+
+# Test COMMAND_EXPAND_LISTS
+set(cmp_args "1ARG=COMMAND_EXPAND_LISTS" "2ARG=test" "3ARG=outfile"
+ "4ARG=content")
+set(AARGS "")
+foreach(arg IN LISTS cmp_args)
+ list(APPEND AARGS "-DA${arg}")
+endforeach()
+
+set(gen_file "expand_custom_command.phony")
+add_custom_command(
+ OUTPUT "${gen_file}"
+ COMMAND ${CMAKE_COMMAND} ${AARGS}
+ "-DB$<JOIN:$<TARGET_PROPERTY:command_expand_lists,CMPARGS>,;-DB>"
+ "-P" "${CMAKE_CURRENT_SOURCE_DIR}/compare_options.cmake"
+ COMMAND_EXPAND_LISTS
+ VERBATIM
+)
+set_property(SOURCE "${gen_file}" PROPERTY SYMBOLIC ON)
+add_custom_target(command_expand_lists ALL DEPENDS "${gen_file}")
+set_property(TARGET command_expand_lists PROPERTY CMPARGS "${cmp_args}")
diff --git a/Tests/CustomCommand/compare_options.cmake b/Tests/CustomCommand/compare_options.cmake
new file mode 100644
index 0000000..a32e579
--- /dev/null
+++ b/Tests/CustomCommand/compare_options.cmake
@@ -0,0 +1,14 @@
+set(range 1 2 3 4 5 6 7 8 9 10)
+set(aargs "")
+set(bargs "")
+foreach(n IN LISTS range)
+ set(aval "${A${n}ARG}")
+ set(bval "${B${n}ARG}")
+ if(aval OR bval)
+ list(APPEND aargs "\"${aval}\"")
+ list(APPEND bargs "\"${bval}\"")
+ endif()
+endforeach()
+if(NOT "${aargs}" STREQUAL "${bargs}")
+ message(FATAL_ERROR "COMPARE_OPTIONS: \n\t${aargs} != \n\t${bargs}")
+endif()
diff --git a/Tests/RunCMake/ctest_fixtures/CMakeLists.txt.in b/Tests/RunCMake/ctest_fixtures/CMakeLists.txt.in
index ba1c77a..ab50fdd 100644
--- a/Tests/RunCMake/ctest_fixtures/CMakeLists.txt.in
+++ b/Tests/RunCMake/ctest_fixtures/CMakeLists.txt.in
@@ -30,6 +30,8 @@ failTest(setupFails) # 9
passTest(wontRun) # 10
passTest(cyclicSetup) # 11
passTest(cyclicCleanup) # 12
+passTest(cleanupUnused) # 13
+passTest(setupUnused) # 14
# Define fixture dependencies and ordering
set_tests_properties(setupFoo PROPERTIES FIXTURES_SETUP "Foo")
@@ -50,6 +52,9 @@ set_tests_properties(two PROPERTIES FIXTURES_REQUIRED "Bar")
set_tests_properties(three PROPERTIES FIXTURES_REQUIRED "Meta;Bar")
set_tests_properties(wontRun PROPERTIES FIXTURES_REQUIRED "Fails")
+set_tests_properties(cleanupUnused PROPERTIES FIXTURES_CLEANUP "Unused")
+set_tests_properties(setupUnused PROPERTIES FIXTURES_SETUP "Unused")
+
@CASE_CMAKELISTS_CYCLIC_CODE@
# These are the cases verified by the main cmake build
@@ -62,6 +67,7 @@ set_tests_properties(wontRun PROPERTIES FIXTURES_REQUIRED "Fails")
# wontRun 9, 10
# cyclicSetup -NA- (configure fails)
# cyclicCleanup -NA- (configure fails)
+# unused 14, 13
#
# In the case of asking for just setupFoo, since there are
# no tests using the Foo fixture, we do NOT expect cleanupFoo
diff --git a/Tests/RunCMake/ctest_fixtures/RunCMakeTest.cmake b/Tests/RunCMake/ctest_fixtures/RunCMakeTest.cmake
index f13289a..673cf57 100644
--- a/Tests/RunCMake/ctest_fixtures/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ctest_fixtures/RunCMakeTest.cmake
@@ -17,6 +17,7 @@ run_ctest_test(two INCLUDE two)
run_ctest_test(three INCLUDE three)
run_ctest_test(setupFoo INCLUDE setupFoo)
run_ctest_test(wontRun INCLUDE wontRun)
+run_ctest_test(unused INCLUDE Unused)
#------------------------------------------------------------
# CMake configure will fail due to cyclic test dependencies
diff --git a/Tests/RunCMake/ctest_fixtures/unused-stdout.txt b/Tests/RunCMake/ctest_fixtures/unused-stdout.txt
new file mode 100644
index 0000000..b04a621
--- /dev/null
+++ b/Tests/RunCMake/ctest_fixtures/unused-stdout.txt
@@ -0,0 +1,9 @@
+Test project .*/Tests/RunCMake/ctest_fixtures/unused-build
+ Start 14: setupUnused
+1/2 Test #14: setupUnused +\.+ +Passed +[0-9.]+ sec
+ Start 13: cleanupUnused
+2/2 Test #13: cleanupUnused +\.+ +Passed +[0-9.]+ sec
++
+100% tests passed, 0 tests failed out of 2
++
+Total Test time \(real\) = +[0-9.]+ sec$
diff --git a/Tests/RunCMake/file/GLOB-noexp-LIST_DIRECTORIES.cmake b/Tests/RunCMake/file/GLOB-noexp-LIST_DIRECTORIES.cmake
new file mode 100644
index 0000000..37a9d54
--- /dev/null
+++ b/Tests/RunCMake/file/GLOB-noexp-LIST_DIRECTORIES.cmake
@@ -0,0 +1 @@
+file(GLOB CONTENT_LIST LIST_DIRECTORIES false)
diff --git a/Tests/RunCMake/file/RunCMakeTest.cmake b/Tests/RunCMake/file/RunCMakeTest.cmake
index 48fa757..7497544 100644
--- a/Tests/RunCMake/file/RunCMakeTest.cmake
+++ b/Tests/RunCMake/file/RunCMakeTest.cmake
@@ -31,6 +31,7 @@ run_cmake(GLOB_RECURSE)
run_cmake(GLOB-error-LIST_DIRECTORIES-not-boolean)
# test is valid both for GLOB and GLOB_RECURSE
run_cmake(GLOB-error-LIST_DIRECTORIES-no-arg)
+run_cmake(GLOB-noexp-LIST_DIRECTORIES)
if(NOT WIN32 OR CYGWIN)
run_cmake(GLOB_RECURSE-cyclic-recursion)