summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/command/add_library.rst3
-rw-r--r--Help/manual/cmake-variables.7.rst1
-rw-r--r--Help/release/dev/allow-OBJECT-library-extra-sources.rst6
-rw-r--r--Help/release/dev/export-from-obj-libs.rst5
-rw-r--r--Help/release/dev/thread-sanitizer.rst5
-rw-r--r--Help/variable/CTEST_MEMORYCHECK_TYPE.rst6
-rw-r--r--Modules/CMakeExpandImportedTargets.cmake12
-rw-r--r--Modules/FindSWIG.cmake3
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/CTest/cmCTestMemCheckCommand.cxx2
-rw-r--r--Source/CTest/cmCTestMemCheckHandler.cxx439
-rw-r--r--Source/CTest/cmCTestMemCheckHandler.h36
-rw-r--r--Source/CTest/cmCTestRunTest.cxx15
-rw-r--r--Source/cmGeneratorTarget.cxx7
-rw-r--r--Source/cmGetSourceFilePropertyCommand.cxx2
-rw-r--r--Source/cmMakefile.cxx97
-rw-r--r--Source/cmMakefile.h7
-rw-r--r--Source/kwsys/CMakeLists.txt7
-rw-r--r--Source/kwsys/Directory.cxx13
-rw-r--r--Source/kwsys/SystemTools.cxx209
-rw-r--r--Source/kwsys/SystemTools.hxx.in13
-rw-r--r--Source/kwsys/testDynamicLoader.cxx2
-rw-r--r--Source/kwsys/testSystemTools.cxx257
-rw-r--r--Source/kwsys/testSystemTools.h.in5
-rw-r--r--Tests/CTestTestMemcheck/CMakeLists.txt18
-rw-r--r--Tests/CTestTestMemcheck/test.cmake.in1
-rw-r--r--Tests/CTestTestMemcheck/testThreadSanitizer.cmake47
-rw-r--r--Tests/ObjectLibrary/A/CMakeLists.txt20
-rw-r--r--Tests/ObjectLibrary/B/CMakeLists.txt5
-rw-r--r--Tests/ObjectLibrary/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/ObjectLibrary/BadObjSource1-stderr.txt3
-rw-r--r--Tests/RunCMake/ObjectLibrary/BadObjSource2-stderr.txt3
32 files changed, 957 insertions, 295 deletions
diff --git a/Help/command/add_library.rst b/Help/command/add_library.rst
index f19b5c0..f86f3c5 100644
--- a/Help/command/add_library.rst
+++ b/Help/command/add_library.rst
@@ -94,7 +94,8 @@ object library name. For example:
will include objlib's object files in a library and an executable
along with those compiled from their own sources. Object libraries
-may contain only sources (and headers) that compile to object files.
+may contain only sources that compile, header files, and other files
+that would not affect linking of a normal library (e.g. ``.txt``).
They may contain custom commands generating such sources, but not
``PRE_BUILD``, ``PRE_LINK``, or ``POST_BUILD`` commands. Object libraries
cannot be imported, exported, installed, or linked. Some native build
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 983bf22..05a7b33 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -344,6 +344,7 @@ Variables for CTest
/variable/CTEST_MEMORYCHECK_COMMAND
/variable/CTEST_MEMORYCHECK_COMMAND_OPTIONS
/variable/CTEST_MEMORYCHECK_SUPPRESSIONS_FILE
+ /variable/CTEST_MEMORYCHECK_TYPE
/variable/CTEST_NIGHTLY_START_TIME
/variable/CTEST_P4_CLIENT
/variable/CTEST_P4_COMMAND
diff --git a/Help/release/dev/allow-OBJECT-library-extra-sources.rst b/Help/release/dev/allow-OBJECT-library-extra-sources.rst
new file mode 100644
index 0000000..472fcdc
--- /dev/null
+++ b/Help/release/dev/allow-OBJECT-library-extra-sources.rst
@@ -0,0 +1,6 @@
+allow-OBJECT-library-extra-sources
+----------------------------------
+
+* :ref:`Object Libraries` may now have extra sources that do not
+ compile to object files so long as they would not affect linking
+ of a normal library (e.g. ``.dat`` is okay but not ``.def``).
diff --git a/Help/release/dev/export-from-obj-libs.rst b/Help/release/dev/export-from-obj-libs.rst
new file mode 100644
index 0000000..6d58288
--- /dev/null
+++ b/Help/release/dev/export-from-obj-libs.rst
@@ -0,0 +1,5 @@
+export-from-obj-libs
+--------------------
+
+* The :module:`GenerateExportHeader` module ``generate_export_header``
+ function learned to allow use with :ref:`Object Libraries`.
diff --git a/Help/release/dev/thread-sanitizer.rst b/Help/release/dev/thread-sanitizer.rst
new file mode 100644
index 0000000..f38e8e1
--- /dev/null
+++ b/Help/release/dev/thread-sanitizer.rst
@@ -0,0 +1,5 @@
+thread-sanitizer
+----------------
+
+* The :command:`ctest_memcheck` command learned to support
+ ``ThreadSanitizer``.
diff --git a/Help/variable/CTEST_MEMORYCHECK_TYPE.rst b/Help/variable/CTEST_MEMORYCHECK_TYPE.rst
new file mode 100644
index 0000000..f7875da
--- /dev/null
+++ b/Help/variable/CTEST_MEMORYCHECK_TYPE.rst
@@ -0,0 +1,6 @@
+CTEST_MEMORYCHECK_TYPE
+-------------------------
+
+Specify the CTest ``MemoryCheckType`` setting
+in a :manual:`ctest(1)` dashboard client script.
+Valid values are Valgrind, Purify, BoundsChecker, and ThreadSanitizer.
diff --git a/Modules/CMakeExpandImportedTargets.cmake b/Modules/CMakeExpandImportedTargets.cmake
index 0752e04..b6ab7ef 100644
--- a/Modules/CMakeExpandImportedTargets.cmake
+++ b/Modules/CMakeExpandImportedTargets.cmake
@@ -71,7 +71,11 @@ function(CMAKE_EXPAND_IMPORTED_TARGETS _RESULT )
set(_CCSR_NEW_REQ_LIBS )
set(_CHECK_FOR_IMPORTED_TARGETS FALSE)
foreach(_CURRENT_LIB ${_CCSR_REQ_LIBS})
- get_target_property(_importedConfigs "${_CURRENT_LIB}" IMPORTED_CONFIGURATIONS)
+ if(TARGET "${_CURRENT_LIB}")
+ get_target_property(_importedConfigs "${_CURRENT_LIB}" IMPORTED_CONFIGURATIONS)
+ else()
+ set(_importedConfigs "")
+ endif()
if (_importedConfigs)
# message(STATUS "Detected imported target ${_CURRENT_LIB}")
# Ok, so this is an imported target.
@@ -123,7 +127,11 @@ function(CMAKE_EXPAND_IMPORTED_TARGETS _RESULT )
# all remaining imported target names (there shouldn't be any left anyway).
set(_CCSR_NEW_REQ_LIBS )
foreach(_CURRENT_LIB ${_CCSR_REQ_LIBS})
- get_target_property(_importedConfigs "${_CURRENT_LIB}" IMPORTED_CONFIGURATIONS)
+ if(TARGET "${_CURRENT_LIB}")
+ get_target_property(_importedConfigs "${_CURRENT_LIB}" IMPORTED_CONFIGURATIONS)
+ else()
+ set(_importedConfigs "")
+ endif()
if (NOT _importedConfigs)
list(APPEND _CCSR_NEW_REQ_LIBS "${_CURRENT_LIB}" )
# message(STATUS "final: appending ${_CURRENT_LIB}")
diff --git a/Modules/FindSWIG.cmake b/Modules/FindSWIG.cmake
index 8bd4048..818d1f2 100644
--- a/Modules/FindSWIG.cmake
+++ b/Modules/FindSWIG.cmake
@@ -25,6 +25,7 @@
#=============================================================================
# Copyright 2004-2009 Kitware, Inc.
# Copyright 2011 Mathieu Malaterre <mathieu.malaterre@gmail.com>
+# Copyright 2014 Sylvain Joubert <joubert.sy@gmail.com>
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
@@ -36,7 +37,7 @@
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
-find_program(SWIG_EXECUTABLE NAMES swig2.0 swig)
+find_program(SWIG_EXECUTABLE NAMES swig3.0 swig2.0 swig)
if(SWIG_EXECUTABLE)
execute_process(COMMAND ${SWIG_EXECUTABLE} -swiglib
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 8321e0a..0de45a0 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 0)
-set(CMake_VERSION_PATCH 20140707)
+set(CMake_VERSION_PATCH 20140714)
#set(CMake_VERSION_RC 1)
diff --git a/Source/CTest/cmCTestMemCheckCommand.cxx b/Source/CTest/cmCTestMemCheckCommand.cxx
index 535c993..939b4dc 100644
--- a/Source/CTest/cmCTestMemCheckCommand.cxx
+++ b/Source/CTest/cmCTestMemCheckCommand.cxx
@@ -21,6 +21,8 @@ cmCTestGenericHandler* cmCTestMemCheckCommand::InitializeActualHandler()
= this->CTest->GetInitializedHandler("memcheck");
this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
+ "MemoryCheckType", "CTEST_MEMORYCHECK_TYPE");
+ this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
"MemoryCheckCommand", "CTEST_MEMORYCHECK_COMMAND");
this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
"MemoryCheckCommandOptions", "CTEST_MEMORYCHECK_COMMAND_OPTIONS");
diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx
index 7b50174..bcf09ad 100644
--- a/Source/CTest/cmCTestMemCheckHandler.cxx
+++ b/Source/CTest/cmCTestMemCheckHandler.cxx
@@ -18,6 +18,7 @@
#include <cmsys/Process.h>
#include <cmsys/RegularExpression.hxx>
#include <cmsys/Base64.h>
+#include <cmsys/Glob.hxx>
#include <cmsys/FStream.hxx>
#include "cmMakefile.h"
#include "cmXMLSafe.h"
@@ -124,60 +125,7 @@ public:
#define BOUNDS_CHECKER_MARKER \
"******######*****Begin BOUNDS CHECKER XML******######******"
-//----------------------------------------------------------------------
-static const char* cmCTestMemCheckResultStrings[] = {
- "ABR",
- "ABW",
- "ABWL",
- "COR",
- "EXU",
- "FFM",
- "FIM",
- "FMM",
- "FMR",
- "FMW",
- "FUM",
- "IPR",
- "IPW",
- "MAF",
- "MLK",
- "MPK",
- "NPR",
- "ODS",
- "PAR",
- "PLK",
- "UMC",
- "UMR",
- 0
-};
-
-//----------------------------------------------------------------------
-static const char* cmCTestMemCheckResultLongStrings[] = {
- "Threading Problem",
- "ABW",
- "ABWL",
- "COR",
- "EXU",
- "FFM",
- "FIM",
- "Mismatched deallocation",
- "FMR",
- "FMW",
- "FUM",
- "IPR",
- "IPW",
- "MAF",
- "Memory Leak",
- "Potential Memory Leak",
- "NPR",
- "ODS",
- "Invalid syscall param",
- "PLK",
- "Uninitialized Memory Conditional",
- "Uninitialized Memory Read",
- 0
-};
//----------------------------------------------------------------------
@@ -186,12 +134,14 @@ cmCTestMemCheckHandler::cmCTestMemCheckHandler()
this->MemCheck = true;
this->CustomMaximumPassedTestOutputSize = 0;
this->CustomMaximumFailedTestOutputSize = 0;
+ this->LogWithPID = false;
}
//----------------------------------------------------------------------
void cmCTestMemCheckHandler::Initialize()
{
this->Superclass::Initialize();
+ this->LogWithPID = false;
this->CustomMaximumPassedTestOutputSize = 0;
this->CustomMaximumFailedTestOutputSize = 0;
this->MemoryTester = "";
@@ -199,12 +149,6 @@ void cmCTestMemCheckHandler::Initialize()
this->MemoryTesterOptions.clear();
this->MemoryTesterStyle = UNKNOWN;
this->MemoryTesterOutputFile = "";
- int cc;
- for ( cc = 0; cc < NO_MEMORY_FAULT; cc ++ )
- {
- this->MemoryTesterGlobalResults[cc] = 0;
- }
-
}
//----------------------------------------------------------------------
@@ -249,8 +193,8 @@ void cmCTestMemCheckHandler::GenerateTestCommand(
index = stream.str();
for ( pp = 0; pp < this->MemoryTesterDynamicOptions.size(); pp ++ )
{
- std::string arg = this->MemoryTesterDynamicOptions[pp];
- std::string::size_type pos = arg.find("??");
+ std::string arg = this->MemoryTesterDynamicOptions[pp];
+ std::string::size_type pos = arg.find("??");
if (pos != std::string::npos)
{
arg.replace(pos, 2, index);
@@ -260,18 +204,125 @@ void cmCTestMemCheckHandler::GenerateTestCommand(
memcheckcommand += arg;
memcheckcommand += "\"";
}
+ // Create a copy of the memory tester environment variable.
+ // This is used for memory testing programs that pass options
+ // via environment varaibles.
+ std::string memTesterEnvironmentVariable =
+ this->MemoryTesterEnvironmentVariable;
for ( pp = 0; pp < this->MemoryTesterOptions.size(); pp ++ )
{
- args.push_back(this->MemoryTesterOptions[pp]);
- memcheckcommand += " \"";
- memcheckcommand += this->MemoryTesterOptions[pp];
- memcheckcommand += "\"";
+ if(memTesterEnvironmentVariable.size())
+ {
+ // If we are using env to pass options, append all the options to
+ // this string with space separation.
+ memTesterEnvironmentVariable += " " + this->MemoryTesterOptions[pp];
+ }
+ // for regular options just add them to args and memcheckcommand
+ // which is just used for display
+ else
+ {
+ args.push_back(this->MemoryTesterOptions[pp]);
+ memcheckcommand += " \"";
+ memcheckcommand += this->MemoryTesterOptions[pp];
+ memcheckcommand += "\"";
+ }
+ }
+ // if this is an env option type, then add the env string as a single
+ // argument.
+ if(memTesterEnvironmentVariable.size())
+ {
+ std::string::size_type pos = memTesterEnvironmentVariable.find("??");
+ if (pos != std::string::npos)
+ {
+ memTesterEnvironmentVariable.replace(pos, 2, index);
+ }
+ memcheckcommand += " " + memTesterEnvironmentVariable;
+ args.push_back(memTesterEnvironmentVariable);
}
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Memory check command: "
<< memcheckcommand << std::endl);
}
//----------------------------------------------------------------------
+void cmCTestMemCheckHandler::InitializeResultsVectors()
+{
+ // fill these members
+// cmsys::vector<std::string> ResultStrings;
+// cmsys::vector<std::string> ResultStringsLong;
+// cmsys::vector<int> GlobalResults;
+ this->ResultStringsLong.clear();
+ this->ResultStrings.clear();
+ this->GlobalResults.clear();
+ // If we are working with style checkers that dynamically fill
+ // the results strings then return.
+ if(this->MemoryTesterStyle > cmCTestMemCheckHandler::BOUNDS_CHECKER)
+ {
+ return;
+ }
+
+ // define the standard set of errors
+ //----------------------------------------------------------------------
+ static const char* cmCTestMemCheckResultStrings[] = {
+ "ABR",
+ "ABW",
+ "ABWL",
+ "COR",
+ "EXU",
+ "FFM",
+ "FIM",
+ "FMM",
+ "FMR",
+ "FMW",
+ "FUM",
+ "IPR",
+ "IPW",
+ "MAF",
+ "MLK",
+ "MPK",
+ "NPR",
+ "ODS",
+ "PAR",
+ "PLK",
+ "UMC",
+ "UMR",
+ 0
+ };
+//----------------------------------------------------------------------
+ static const char* cmCTestMemCheckResultLongStrings[] = {
+ "Threading Problem",
+ "ABW",
+ "ABWL",
+ "COR",
+ "EXU",
+ "FFM",
+ "FIM",
+ "Mismatched deallocation",
+ "FMR",
+ "FMW",
+ "FUM",
+ "IPR",
+ "IPW",
+ "MAF",
+ "Memory Leak",
+ "Potential Memory Leak",
+ "NPR",
+ "ODS",
+ "Invalid syscall param",
+ "PLK",
+ "Uninitialized Memory Conditional",
+ "Uninitialized Memory Read",
+ 0
+ };
+ this->GlobalResults.clear();
+ for(int i =0; cmCTestMemCheckResultStrings[i] != 0; ++i)
+ {
+ this->ResultStrings.push_back(cmCTestMemCheckResultStrings[i]);
+ this->ResultStringsLong.push_back(cmCTestMemCheckResultLongStrings[i]);
+ this->GlobalResults.push_back(0);
+ }
+}
+
+//----------------------------------------------------------------------
void cmCTestMemCheckHandler::PopulateCustomVectors(cmMakefile *mf)
{
this->cmCTestTestHandler::PopulateCustomVectors(mf);
@@ -283,6 +334,8 @@ void cmCTestMemCheckHandler::PopulateCustomVectors(cmMakefile *mf)
this->CTest->PopulateCustomVector(mf,
"CTEST_CUSTOM_MEMCHECK_IGNORE",
this->CustomTestsIgnore);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ mf, "CMakeCommand", "CMAKE_COMMAND");
}
//----------------------------------------------------------------------
@@ -292,7 +345,6 @@ void cmCTestMemCheckHandler::GenerateDartOutput(std::ostream& os)
{
return;
}
-
this->CTest->StartXML(os, this->AppendXML);
os << "<DynamicAnalysis Checker=\"";
switch ( this->MemoryTesterStyle )
@@ -306,6 +358,9 @@ void cmCTestMemCheckHandler::GenerateDartOutput(std::ostream& os)
case cmCTestMemCheckHandler::BOUNDS_CHECKER:
os << "BoundsChecker";
break;
+ case cmCTestMemCheckHandler::THREAD_SANITIZER:
+ os << "ThreadSanitizer";
+ break;
default:
os << "Unknown";
}
@@ -333,8 +388,7 @@ void cmCTestMemCheckHandler::GenerateDartOutput(std::ostream& os)
{
cmCTestTestResult *result = &this->TestResults[cc];
std::string memcheckstr;
- int memcheckresults[cmCTestMemCheckHandler::NO_MEMORY_FAULT];
- int kk;
+ std::vector<int> memcheckresults(this->ResultStrings.size(), 0);
bool res = this->ProcessMemCheckOutput(result->Output, memcheckstr,
memcheckresults);
if ( res && result->Status == cmCTestMemCheckHandler::COMPLETED )
@@ -345,16 +399,17 @@ void cmCTestMemCheckHandler::GenerateDartOutput(std::ostream& os)
static_cast<size_t>(this->CustomMaximumFailedTestOutputSize));
this->WriteTestResultHeader(os, result);
os << "\t\t<Results>" << std::endl;
- for ( kk = 0; cmCTestMemCheckResultLongStrings[kk]; kk ++ )
+ for(std::vector<int>::size_type kk = 0;
+ kk < memcheckresults.size(); ++kk)
{
if ( memcheckresults[kk] )
{
- os << "\t\t\t<Defect type=\"" << cmCTestMemCheckResultLongStrings[kk]
+ os << "\t\t\t<Defect type=\"" << this->ResultStringsLong[kk]
<< "\">"
<< memcheckresults[kk]
<< "</Defect>" << std::endl;
}
- this->MemoryTesterGlobalResults[kk] += memcheckresults[kk];
+ this->GlobalResults[kk] += memcheckresults[kk];
}
std::string logTag;
@@ -383,9 +438,9 @@ void cmCTestMemCheckHandler::GenerateDartOutput(std::ostream& os)
cmCTestLog(this->CTest, HANDLER_OUTPUT, "Memory checking results:"
<< std::endl);
os << "\t<DefectList>" << std::endl;
- for ( cc = 0; cmCTestMemCheckResultStrings[cc]; cc ++ )
+ for ( cc = 0; cc < this->GlobalResults.size(); cc ++ )
{
- if ( this->MemoryTesterGlobalResults[cc] )
+ if ( this->GlobalResults[cc] )
{
#ifdef cerr
# undef cerr
@@ -393,9 +448,9 @@ void cmCTestMemCheckHandler::GenerateDartOutput(std::ostream& os)
std::cerr.width(35);
#define cerr no_cerr
cmCTestLog(this->CTest, HANDLER_OUTPUT,
- cmCTestMemCheckResultLongStrings[cc] << " - "
- << this->MemoryTesterGlobalResults[cc] << std::endl);
- os << "\t\t<Defect Type=\"" << cmCTestMemCheckResultLongStrings[cc]
+ this->ResultStringsLong[cc] << " - "
+ << this->GlobalResults[cc] << std::endl);
+ os << "\t\t<Defect Type=\"" << this->ResultStringsLong[cc]
<< "\"/>" << std::endl;
}
}
@@ -410,13 +465,13 @@ void cmCTestMemCheckHandler::GenerateDartOutput(std::ostream& os)
os << "</DynamicAnalysis>" << std::endl;
this->CTest->EndXML(os);
-
-
}
//----------------------------------------------------------------------
bool cmCTestMemCheckHandler::InitializeMemoryChecking()
{
+ this->MemoryTesterEnvironmentVariable = "";
+ this->MemoryTester = "";
// Setup the command
if ( cmSystemTools::FileExists(this->CTest->GetCTestConfiguration(
"MemoryCheckCommand").c_str()) )
@@ -426,7 +481,9 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
std::string testerName =
cmSystemTools::GetFilenameName(this->MemoryTester);
// determine the checker type
- if ( testerName.find("valgrind") != std::string::npos )
+ if ( testerName.find("valgrind") != std::string::npos ||
+ this->CTest->GetCTestConfiguration("MemoryCheckType")
+ == "Valgrind")
{
this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND;
}
@@ -464,12 +521,38 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
= this->CTest->GetCTestConfiguration("BoundsCheckerCommand").c_str();
this->MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER;
}
- else
+ if ( this->CTest->GetCTestConfiguration("MemoryCheckType")
+ == "ThreadSanitizer")
+ {
+ this->MemoryTester
+ = this->CTest->GetCTestConfiguration("CMakeCommand").c_str();
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::THREAD_SANITIZER;
+ this->LogWithPID = true; // even if we give the log file the pid is added
+ }
+ // Check the MemoryCheckType
+ if(this->MemoryTesterStyle == cmCTestMemCheckHandler::UNKNOWN)
+ {
+ std::string checkType =
+ this->CTest->GetCTestConfiguration("MemoryCheckType");
+ if(checkType == "Purify")
+ {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::PURIFY;
+ }
+ else if(checkType == "BoundsChecker")
+ {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER;
+ }
+ else if(checkType == "Valgrind")
+ {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND;
+ }
+ }
+ if(this->MemoryTester.size() == 0 )
{
cmCTestLog(this->CTest, WARNING,
- "Memory checker (MemoryCheckCommand) "
- "not set, or cannot find the specified program."
- << std::endl);
+ "Memory checker (MemoryCheckCommand) "
+ "not set, or cannot find the specified program."
+ << std::endl);
return false;
}
@@ -568,6 +651,20 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
this->MemoryTesterOptions.push_back("/M");
break;
}
+ case cmCTestMemCheckHandler::THREAD_SANITIZER:
+ {
+ // To pass arguments to ThreadSanitizer the environment variable
+ // TSAN_OPTIONS is used. This is done with the cmake -E env command.
+ // The MemoryTesterDynamicOptions is setup with the -E env
+ // Then the MemoryTesterEnvironmentVariable gets the
+ // TSAN_OPTIONS string with the log_path in it.
+ this->MemoryTesterDynamicOptions.push_back("-E");
+ this->MemoryTesterDynamicOptions.push_back("env");
+ std::string outputFile = "TSAN_OPTIONS=log_path=\""
+ + this->MemoryTesterOutputFile + "\"";
+ this->MemoryTesterEnvironmentVariable = outputFile;
+ break;
+ }
default:
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Do not understand memory checker: " << this->MemoryTester
@@ -575,24 +672,20 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
return false;
}
- std::vector<std::string>::size_type cc;
- for ( cc = 0; cmCTestMemCheckResultStrings[cc]; cc ++ )
- {
- this->MemoryTesterGlobalResults[cc] = 0;
- }
+ this->InitializeResultsVectors();
+ // std::vector<std::string>::size_type cc;
+ // for ( cc = 0; cmCTestMemCheckResultStrings[cc]; cc ++ )
+ // {
+ // this->MemoryTesterGlobalResults[cc] = 0;
+ // }
return true;
}
//----------------------------------------------------------------------
-bool cmCTestMemCheckHandler::ProcessMemCheckOutput(const std::string& str,
- std::string& log, int* results)
+bool cmCTestMemCheckHandler::
+ProcessMemCheckOutput(const std::string& str,
+ std::string& log, std::vector<int>& results)
{
- std::string::size_type cc;
- for ( cc = 0; cc < cmCTestMemCheckHandler::NO_MEMORY_FAULT; cc ++ )
- {
- results[cc] = 0;
- }
-
if ( this->MemoryTesterStyle == cmCTestMemCheckHandler::VALGRIND )
{
return this->ProcessMemCheckValgrindOutput(str, log, results);
@@ -602,6 +695,11 @@ bool cmCTestMemCheckHandler::ProcessMemCheckOutput(const std::string& str,
return this->ProcessMemCheckPurifyOutput(str, log, results);
}
else if ( this->MemoryTesterStyle ==
+ cmCTestMemCheckHandler::THREAD_SANITIZER )
+ {
+ return this->ProcessMemCheckThreadSanitizerOutput(str, log, results);
+ }
+ else if ( this->MemoryTesterStyle ==
cmCTestMemCheckHandler::BOUNDS_CHECKER )
{
return this->ProcessMemCheckBoundsCheckerOutput(str, log, results);
@@ -612,15 +710,68 @@ bool cmCTestMemCheckHandler::ProcessMemCheckOutput(const std::string& str,
log.append("None that I know");
log = str;
}
-
-
return true;
}
+std::vector<int>::size_type cmCTestMemCheckHandler::FindOrAddWarning(
+ const std::string& warning)
+{
+ for(std::vector<std::string>::size_type i =0;
+ i < this->ResultStrings.size(); ++i)
+ {
+ if(this->ResultStrings[i] == warning)
+ {
+ return i;
+ }
+ }
+ this->GlobalResults.push_back(0); // this must stay the same size
+ this->ResultStrings.push_back(warning);
+ this->ResultStringsLong.push_back(warning);
+ return this->ResultStrings.size()-1;
+}
+//----------------------------------------------------------------------
+bool cmCTestMemCheckHandler::ProcessMemCheckThreadSanitizerOutput(
+ const std::string& str, std::string& log,
+ std::vector<int>& result)
+{
+ cmsys::RegularExpression
+ sanitizerWarning("WARNING: ThreadSanitizer: (.*) \\(pid=.*\\)");
+ int defects = 0;
+ std::vector<std::string> lines;
+ cmSystemTools::Split(str.c_str(), lines);
+ cmOStringStream ostr;
+ log = "";
+ for( std::vector<std::string>::iterator i = lines.begin();
+ i != lines.end(); ++i)
+ {
+ if(sanitizerWarning.find(*i))
+ {
+ std::string warning = sanitizerWarning.match(1);
+ std::vector<int>::size_type idx = this->FindOrAddWarning(warning);
+ if(result.size() == 0 || idx > result.size()-1)
+ {
+ result.push_back(1);
+ }
+ else
+ {
+ result[idx]++;
+ }
+ defects++;
+ ostr << "<b>" << this->ResultStrings[idx] << "</b> ";
+ }
+ ostr << cmXMLSafe(*i) << std::endl;
+ }
+ log = ostr.str();
+ if(defects)
+ {
+ return false;
+ }
+ return true;
+}
//----------------------------------------------------------------------
bool cmCTestMemCheckHandler::ProcessMemCheckPurifyOutput(
const std::string& str, std::string& log,
- int* results)
+ std::vector<int>& results)
{
std::vector<std::string> lines;
cmSystemTools::Split(str.c_str(), lines);
@@ -634,19 +785,19 @@ bool cmCTestMemCheckHandler::ProcessMemCheckPurifyOutput(
for( std::vector<std::string>::iterator i = lines.begin();
i != lines.end(); ++i)
{
- int failure = cmCTestMemCheckHandler::NO_MEMORY_FAULT;
+ std::vector<int>::size_type failure = this->ResultStrings.size();
if ( pfW.find(*i) )
{
- int cc;
- for ( cc = 0; cc < cmCTestMemCheckHandler::NO_MEMORY_FAULT; cc ++ )
+ std::vector<int>::size_type cc;
+ for ( cc = 0; cc < this->ResultStrings.size(); cc ++ )
{
- if ( pfW.match(1) == cmCTestMemCheckResultStrings[cc] )
+ if ( pfW.match(1) == this->ResultStrings[cc] )
{
failure = cc;
break;
}
}
- if ( cc == cmCTestMemCheckHandler::NO_MEMORY_FAULT )
+ if ( cc == this->ResultStrings.size() )
{
cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown Purify memory fault: "
<< pfW.match(1) << std::endl);
@@ -654,9 +805,9 @@ bool cmCTestMemCheckHandler::ProcessMemCheckPurifyOutput(
<< std::endl;
}
}
- if ( failure != NO_MEMORY_FAULT )
+ if ( failure != this->ResultStrings.size() )
{
- ostr << "<b>" << cmCTestMemCheckResultStrings[failure] << "</b> ";
+ ostr << "<b>" << this->ResultStrings[failure] << "</b> ";
results[failure] ++;
defects ++;
}
@@ -674,7 +825,7 @@ bool cmCTestMemCheckHandler::ProcessMemCheckPurifyOutput(
//----------------------------------------------------------------------
bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput(
const std::string& str, std::string& log,
- int* results)
+ std::vector<int>& results)
{
std::vector<std::string> lines;
cmSystemTools::Split(str.c_str(), lines);
@@ -803,7 +954,7 @@ bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput(
if ( failure != cmCTestMemCheckHandler::NO_MEMORY_FAULT )
{
- ostr << "<b>" << cmCTestMemCheckResultStrings[failure] << "</b> ";
+ ostr << "<b>" << this->ResultStrings[failure] << "</b> ";
results[failure] ++;
defects ++;
}
@@ -855,7 +1006,7 @@ bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput(
//----------------------------------------------------------------------
bool cmCTestMemCheckHandler::ProcessMemCheckBoundsCheckerOutput(
const std::string& str, std::string& log,
- int* results)
+ std::vector<int>& results)
{
log = "";
double sttime = cmSystemTools::GetTime();
@@ -909,6 +1060,26 @@ bool cmCTestMemCheckHandler::ProcessMemCheckBoundsCheckerOutput(
return true;
}
+// PostProcessTest memcheck results
+void
+cmCTestMemCheckHandler::PostProcessTest(cmCTestTestResult& res,
+ int test)
+{
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "PostProcessTest memcheck results for : "
+ << res.Name << std::endl);
+ if(this->MemoryTesterStyle
+ == cmCTestMemCheckHandler::BOUNDS_CHECKER)
+ {
+ this->PostProcessBoundsCheckerTest(res, test);
+ }
+ else
+ {
+ this->AppendMemTesterOutput(res, test);
+ }
+}
+
+
// This method puts the bounds checker output file into the output
// for the test
void
@@ -951,35 +1122,16 @@ cmCTestMemCheckHandler::PostProcessBoundsCheckerTest(cmCTestTestResult& res,
}
void
-cmCTestMemCheckHandler::PostProcessPurifyTest(cmCTestTestResult& res,
- int test)
-{
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "PostProcessPurifyTest for : "
- << res.Name << std::endl);
- this->AppendMemTesterOutput(res, test);
-}
-
-void
-cmCTestMemCheckHandler::PostProcessValgrindTest(cmCTestTestResult& res,
- int test)
-{
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "PostProcessValgrindTest for : "
- << res.Name << std::endl);
- this->AppendMemTesterOutput(res, test);
-}
-
-void
cmCTestMemCheckHandler::AppendMemTesterOutput(cmCTestTestResult& res,
int test)
{
std::string ofile = this->TestOutputFileName(test);
-
if ( ofile.empty() )
{
return;
}
+ // put ifs in scope so file can be deleted if needed
+ {
cmsys::ifstream ifs(ofile.c_str());
if ( !ifs )
{
@@ -993,6 +1145,12 @@ cmCTestMemCheckHandler::AppendMemTesterOutput(cmCTestTestResult& res,
res.Output += line;
res.Output += "\n";
}
+ }
+ if(this->LogWithPID)
+ {
+ cmSystemTools::RemoveFile(ofile.c_str());
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Remove: "<< ofile <<"\n");
+ }
}
std::string
@@ -1005,14 +1163,29 @@ cmCTestMemCheckHandler::TestOutputFileName(int test)
std::string ofile = this->MemoryTesterOutputFile;
std::string::size_type pos = ofile.find("??");
ofile.replace(pos, 2, index);
-
- if ( !cmSystemTools::FileExists(ofile.c_str()) )
+ if(this->LogWithPID)
+ {
+ ofile += ".*";
+ cmsys::Glob g;
+ g.FindFiles(ofile);
+ if(g.GetFiles().size() == 0)
+ {
+ std::string log = "Cannot find memory tester output file: "
+ + ofile;
+ cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl);
+ ofile = "";
+ }
+ else
+ {
+ ofile = g.GetFiles()[0];
+ }
+ }
+ else if ( !cmSystemTools::FileExists(ofile.c_str()) )
{
std::string log = "Cannot find memory tester output file: "
+ ofile;
cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl);
ofile = "";
}
-
return ofile;
}
diff --git a/Source/CTest/cmCTestMemCheckHandler.h b/Source/CTest/cmCTestMemCheckHandler.h
index 20a38bb..ffe57f6 100644
--- a/Source/CTest/cmCTestMemCheckHandler.h
+++ b/Source/CTest/cmCTestMemCheckHandler.h
@@ -15,7 +15,10 @@
#include "cmCTestTestHandler.h"
+#include "cmStandardIncludes.h"
#include "cmListFileCache.h"
+#include <vector>
+#include <string>
class cmMakefile;
@@ -45,7 +48,9 @@ private:
UNKNOWN = 0,
VALGRIND,
PURIFY,
- BOUNDS_CHECKER
+ BOUNDS_CHECKER,
+ // checkers after hear do not use the standard error list
+ THREAD_SANITIZER
};
public:
enum { // Memory faults
@@ -93,7 +98,17 @@ private:
std::vector<std::string> MemoryTesterOptions;
int MemoryTesterStyle;
std::string MemoryTesterOutputFile;
- int MemoryTesterGlobalResults[NO_MEMORY_FAULT];
+ std::string MemoryTesterEnvironmentVariable;
+ // these are used to store the types of errors that can show up
+ std::vector<std::string> ResultStrings;
+ std::vector<std::string> ResultStringsLong;
+ std::vector<int> GlobalResults;
+ bool LogWithPID; // does log file add pid
+
+ std::vector<int>::size_type FindOrAddWarning(const std::string& warning);
+ // initialize the ResultStrings and ResultStringsLong for
+ // this type of checker
+ void InitializeResultsVectors();
///! Initialize memory checking subsystem.
bool InitializeMemoryChecking();
@@ -110,17 +125,22 @@ private:
//string. After running, log holds the output and results hold the
//different memmory errors.
bool ProcessMemCheckOutput(const std::string& str,
- std::string& log, int* results);
+ std::string& log, std::vector<int>& results);
bool ProcessMemCheckValgrindOutput(const std::string& str,
- std::string& log, int* results);
+ std::string& log,
+ std::vector<int>& results);
bool ProcessMemCheckPurifyOutput(const std::string& str,
- std::string& log, int* results);
+ std::string& log,
+ std::vector<int>& results);
+ bool ProcessMemCheckThreadSanitizerOutput(const std::string& str,
+ std::string& log,
+ std::vector<int>& results);
bool ProcessMemCheckBoundsCheckerOutput(const std::string& str,
- std::string& log, int* results);
+ std::string& log,
+ std::vector<int>& results);
- void PostProcessPurifyTest(cmCTestTestResult& res, int test);
+ void PostProcessTest(cmCTestTestResult& res, int test);
void PostProcessBoundsCheckerTest(cmCTestTestResult& res, int test);
- void PostProcessValgrindTest(cmCTestTestResult& res, int test);
///! append MemoryTesterOutputFile to the test log
void AppendMemTesterOutput(cmCTestTestHandler::cmCTestTestResult& res,
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 385388d..bdd8c02 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -392,20 +392,7 @@ void cmCTestRunTest::MemCheckPostProcess()
<< this->TestResult.Name << std::endl);
cmCTestMemCheckHandler * handler = static_cast<cmCTestMemCheckHandler*>
(this->TestHandler);
- switch ( handler->MemoryTesterStyle )
- {
- case cmCTestMemCheckHandler::VALGRIND:
- handler->PostProcessValgrindTest(this->TestResult, this->Index);
- break;
- case cmCTestMemCheckHandler::PURIFY:
- handler->PostProcessPurifyTest(this->TestResult, this->Index);
- break;
- case cmCTestMemCheckHandler::BOUNDS_CHECKER:
- handler->PostProcessBoundsCheckerTest(this->TestResult, this->Index);
- break;
- default:
- break;
- }
+ handler->PostProcessTest(this->TestResult, this->Index);
}
//----------------------------------------------------------------------
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index eccb06a..64c5822 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -38,7 +38,8 @@ void reportBadObjLib(std::vector<cmSourceFile*> const& badObjLib,
{
e << " " << (*i)->GetLocation().GetName() << "\n";
}
- e << "but may contain only headers and sources that compile.";
+ e << "but may contain only sources that compile, header files, and "
+ "other files that would not affect linking of a normal library.";
cm->IssueMessage(cmake::FATAL_ERROR, e.str(),
target->GetBacktrace());
}
@@ -205,10 +206,6 @@ struct TagVisitor
else
{
DoAccept<IsSameTag<Tag, ExtraSourcesTag>::Result>::Do(this->Data, sf);
- if(this->IsObjLib && ext != "txt")
- {
- this->BadObjLibFiles.push_back(sf);
- }
}
}
};
diff --git a/Source/cmGetSourceFilePropertyCommand.cxx b/Source/cmGetSourceFilePropertyCommand.cxx
index 8a96289..7667a85 100644
--- a/Source/cmGetSourceFilePropertyCommand.cxx
+++ b/Source/cmGetSourceFilePropertyCommand.cxx
@@ -29,7 +29,7 @@ bool cmGetSourceFilePropertyCommand
// for the location we must create a source file first
if (!sf && args[2] == "LOCATION")
{
- sf = this->Makefile->GetOrCreateSource(file);
+ sf = this->Makefile->CreateSource(file);
}
if(sf)
{
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 412c998..2218e2f 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -989,7 +989,7 @@ cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs,
// Choose a source file on which to store the custom command.
cmSourceFile* file = 0;
- if(!main_dependency.empty())
+ if(!commandLines.empty() && !main_dependency.empty())
{
// The main dependency was specified. Use it unless a different
// custom command already used it.
@@ -1010,11 +1010,9 @@ cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs,
file = 0;
}
}
- else
+ else if (!file)
{
- // The main dependency does not have a custom command or we are
- // allowed to replace it. Use it to store the command.
- file = this->GetOrCreateSource(main_dependency);
+ file = this->CreateSource(main_dependency);
}
}
@@ -1041,8 +1039,11 @@ cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs,
}
// Create a cmSourceFile for the rule file.
- file = this->GetOrCreateSource(outName, true);
- file->SetProperty("__CMAKE_RULE", "1");
+ if (!file)
+ {
+ file = this->CreateSource(outName, true);
+ file->SetProperty("__CMAKE_RULE", "1");
+ }
}
// Always create the output sources and mark them generated.
@@ -1055,16 +1056,16 @@ cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs,
}
}
- // Construct a complete list of dependencies.
- std::vector<std::string> depends2(depends);
- if(!main_dependency.empty())
- {
- depends2.push_back(main_dependency);
- }
-
// Attach the custom command to the file.
if(file)
{
+ // Construct a complete list of dependencies.
+ std::vector<std::string> depends2(depends);
+ if(!main_dependency.empty())
+ {
+ depends2.push_back(main_dependency);
+ }
+
cmCustomCommand* cc =
new cmCustomCommand(this, outputs, depends2, commandLines,
comment, workingDir);
@@ -1256,28 +1257,31 @@ cmMakefile::AddUtilityCommand(const std::string& utilityName,
}
// Store the custom command in the target.
- std::string force = this->GetStartOutputDirectory();
- force += cmake::GetCMakeFilesDirectory();
- force += "/";
- force += utilityName;
- std::string no_main_dependency = "";
- bool no_replace = false;
- this->AddCustomCommandToOutput(force, depends,
- no_main_dependency,
- commandLines, comment,
- workingDirectory, no_replace,
- escapeOldStyle);
- cmSourceFile* sf = target->AddSourceCMP0049(force);
-
- // The output is not actually created so mark it symbolic.
- if(sf)
- {
- sf->SetProperty("SYMBOLIC", "1");
- }
- else
- {
- cmSystemTools::Error("Could not get source file entry for ",
- force.c_str());
+ if (!commandLines.empty() || !depends.empty())
+ {
+ std::string force = this->GetStartOutputDirectory();
+ force += cmake::GetCMakeFilesDirectory();
+ force += "/";
+ force += utilityName;
+ std::string no_main_dependency = "";
+ bool no_replace = false;
+ this->AddCustomCommandToOutput(force, depends,
+ no_main_dependency,
+ commandLines, comment,
+ workingDirectory, no_replace,
+ escapeOldStyle);
+ cmSourceFile* sf = target->AddSourceCMP0049(force);
+
+ // The output is not actually created so mark it symbolic.
+ if(sf)
+ {
+ sf->SetProperty("SYMBOLIC", "1");
+ }
+ else
+ {
+ cmSystemTools::Error("Could not get source file entry for ",
+ force.c_str());
+ }
}
return target;
}
@@ -3451,6 +3455,19 @@ cmSourceFile* cmMakefile::GetSource(const std::string& sourceName) const
}
//----------------------------------------------------------------------------
+cmSourceFile* cmMakefile::CreateSource(const std::string& sourceName,
+ bool generated)
+{
+ cmSourceFile* sf = new cmSourceFile(this, sourceName);
+ if(generated)
+ {
+ sf->SetProperty("GENERATED", "1");
+ }
+ this->SourceFiles.push_back(sf);
+ return sf;
+}
+
+//----------------------------------------------------------------------------
cmSourceFile* cmMakefile::GetOrCreateSource(const std::string& sourceName,
bool generated)
{
@@ -3460,13 +3477,7 @@ cmSourceFile* cmMakefile::GetOrCreateSource(const std::string& sourceName,
}
else
{
- cmSourceFile* sf = new cmSourceFile(this, sourceName);
- if(generated)
- {
- sf->SetProperty("GENERATED", "1");
- }
- this->SourceFiles.push_back(sf);
- return sf;
+ return this->CreateSource(sourceName, generated);
}
}
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index d5ffd98..3a40c1c 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -560,6 +560,13 @@ public:
*/
cmSourceFile* GetSource(const std::string& sourceName) const;
+ /** Create the source file and return it. generated
+ * indicates if it is a generated file, this is used in determining
+ * how to create the source file instance e.g. name
+ */
+ cmSourceFile* CreateSource(const std::string& sourceName,
+ bool generated = false);
+
/** Get a cmSourceFile pointer for a given source name, if the name is
* not found, then create the source file and return it. generated
* indicates if it is a generated file, this is used in determining
diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt
index 5e6a226..8ca4360 100644
--- a/Source/kwsys/CMakeLists.txt
+++ b/Source/kwsys/CMakeLists.txt
@@ -1171,10 +1171,9 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestsCxx ${KWSYS_CXX_TEST_SRCS})
SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY LABELS ${KWSYS_LABELS_EXE})
TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE}TestsCxx ${KWSYS_NAMESPACE})
- SET(TEST_SYSTEMTOOLS_BIN_FILE
- "${CMAKE_CURRENT_SOURCE_DIR}/testSystemTools.bin")
- SET(TEST_SYSTEMTOOLS_SRC_FILE
- "${CMAKE_CURRENT_SOURCE_DIR}/testSystemTools.cxx")
+
+ SET(TEST_SYSTEMTOOLS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+ SET(TEST_SYSTEMTOOLS_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}")
CONFIGURE_FILE(
${PROJECT_SOURCE_DIR}/testSystemTools.h.in
${PROJECT_BINARY_DIR}/testSystemTools.h)
diff --git a/Source/kwsys/Directory.cxx b/Source/kwsys/Directory.cxx
index d54e607..b305fd7 100644
--- a/Source/kwsys/Directory.cxx
+++ b/Source/kwsys/Directory.cxx
@@ -113,15 +113,24 @@ bool Directory::Load(const char* name)
#endif
char* buf;
size_t n = strlen(name);
- if ( name[n - 1] == '/' )
+ if ( name[n - 1] == '/' || name[n - 1] == '\\' )
{
buf = new char[n + 1 + 1];
sprintf(buf, "%s*", name);
}
else
{
+ // Make sure the slashes in the wildcard suffix are consistent with the
+ // rest of the path
buf = new char[n + 2 + 1];
- sprintf(buf, "%s/*", name);
+ if ( strchr(name, '\\') )
+ {
+ sprintf(buf, "%s\\*", name);
+ }
+ else
+ {
+ sprintf(buf, "%s/*", name);
+ }
}
struct _wfinddata_t data; // data of current file
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index 704cbbc..db94510 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -187,17 +187,34 @@ static inline char *realpath(const char *path, char *resolved_path)
}
#endif
+#ifdef _WIN32
+static time_t windows_filetime_to_posix_time(const FILETIME& ft)
+{
+ LARGE_INTEGER date;
+ date.HighPart = ft.dwHighDateTime;
+ date.LowPart = ft.dwLowDateTime;
+
+ // removes the diff between 1970 and 1601
+ date.QuadPart -= ((LONGLONG)(369 * 365 + 89) * 24 * 3600 * 10000000);
+
+ // converts back from 100-nanoseconds to seconds
+ return date.QuadPart / 10000000;
+}
+#endif
+
#if defined(_WIN32) && (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) || defined(__MINGW32__))
#include <wctype.h>
inline int Mkdir(const char* dir)
{
- return _wmkdir(KWSYS_NAMESPACE::Encoding::ToWide(dir).c_str());
+ return _wmkdir(
+ KWSYS_NAMESPACE::SystemTools::ConvertToWindowsExtendedPath(dir).c_str());
}
inline int Rmdir(const char* dir)
{
- return _wrmdir(KWSYS_NAMESPACE::Encoding::ToWide(dir).c_str());
+ return _wrmdir(
+ KWSYS_NAMESPACE::SystemTools::ConvertToWindowsExtendedPath(dir).c_str());
}
inline const char* Getcwd(char* buf, unsigned int len)
{
@@ -609,7 +626,7 @@ const char* SystemTools::GetExecutableExtension()
FILE* SystemTools::Fopen(const char* file, const char* mode)
{
#ifdef _WIN32
- return _wfopen(Encoding::ToWide(file).c_str(),
+ return _wfopen(SystemTools::ConvertToWindowsExtendedPath(file).c_str(),
Encoding::ToWide(mode).c_str());
#else
return fopen(file, mode);
@@ -1081,7 +1098,8 @@ bool SystemTools::FileExists(const char* filename)
}
return access(filename, R_OK) == 0;
#elif defined(_WIN32)
- return (GetFileAttributesW(Encoding::ToWide(filename).c_str())
+ return (GetFileAttributesW(
+ SystemTools::ConvertToWindowsExtendedPath(filename).c_str())
!= INVALID_FILE_ATTRIBUTES);
#else
return access(filename, R_OK) == 0;
@@ -1137,10 +1155,11 @@ bool SystemTools::Touch(const char* filename, bool create)
return false;
}
#if defined(_WIN32) && !defined(__CYGWIN__)
- HANDLE h = CreateFileW(Encoding::ToWide(filename).c_str(),
- FILE_WRITE_ATTRIBUTES,
- FILE_SHARE_WRITE, 0, OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS, 0);
+ HANDLE h = CreateFileW(
+ SystemTools::ConvertToWindowsExtendedPath(filename).c_str(),
+ FILE_WRITE_ATTRIBUTES,
+ FILE_SHARE_WRITE, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, 0);
if(!h)
{
return false;
@@ -1242,13 +1261,15 @@ bool SystemTools::FileTimeCompare(const char* f1, const char* f2,
// Windows version. Get the modification time from extended file attributes.
WIN32_FILE_ATTRIBUTE_DATA f1d;
WIN32_FILE_ATTRIBUTE_DATA f2d;
- if(!GetFileAttributesExW(Encoding::ToWide(f1).c_str(),
- GetFileExInfoStandard, &f1d))
+ if(!GetFileAttributesExW(
+ SystemTools::ConvertToWindowsExtendedPath(f1).c_str(),
+ GetFileExInfoStandard, &f1d))
{
return false;
}
- if(!GetFileAttributesExW(Encoding::ToWide(f2).c_str(),
- GetFileExInfoStandard, &f2d))
+ if(!GetFileAttributesExW(
+ SystemTools::ConvertToWindowsExtendedPath(f2).c_str(),
+ GetFileExInfoStandard, &f2d))
{
return false;
}
@@ -1830,6 +1851,71 @@ void SystemTools::ConvertToUnixSlashes(kwsys_stl::string& path)
}
}
+#ifdef _WIN32
+// Convert local paths to UNC style paths
+kwsys_stl::wstring
+SystemTools::ConvertToWindowsExtendedPath(const kwsys_stl::string &source)
+{
+ kwsys_stl::wstring wsource = Encoding::ToWide(source);
+
+ // Resolve any relative paths
+ DWORD wfull_len;
+
+ /* The +3 is a workaround for a bug in some versions of GetFullPathNameW that
+ * won't return a large enough buffer size if the input is too small */
+ wfull_len = GetFullPathNameW(wsource.c_str(), 0, NULL, NULL) + 3;
+ kwsys_stl::vector<wchar_t> wfull(wfull_len);
+ GetFullPathNameW(wsource.c_str(), wfull_len, &wfull[0], NULL);
+
+ /* This should get the correct size without any extra padding from the
+ * previous size workaround. */
+ wfull_len = static_cast<DWORD>(wcslen(&wfull[0]));
+
+ if(wfull_len >= 2 && isalpha(wfull[0]) && wfull[1] == L':')
+ { /* C:\Foo\bar\FooBar.txt */
+ return L"\\\\?\\" + kwsys_stl::wstring(&wfull[0]);
+ }
+ else if(wfull_len >= 2 && wfull[0] == L'\\' && wfull[1] == L'\\')
+ { /* Starts with \\ */
+ if(wfull_len >= 4 && wfull[2] == L'?' && wfull[3] == L'\\')
+ { /* Starts with \\?\ */
+ if(wfull_len >= 8 && wfull[4] == L'U' && wfull[5] == L'N' &&
+ wfull[6] == L'C' && wfull[7] == L'\\')
+ { /* \\?\UNC\Foo\bar\FooBar.txt */
+ return kwsys_stl::wstring(&wfull[0]);
+ }
+ else if(wfull_len >= 6 && isalpha(wfull[4]) && wfull[5] == L':')
+ { /* \\?\C:\Foo\bar\FooBar.txt */
+ return kwsys_stl::wstring(&wfull[0]);
+ }
+ else if(wfull_len >= 5)
+ { /* \\?\Foo\bar\FooBar.txt */
+ return L"\\\\?\\UNC\\" + kwsys_stl::wstring(&wfull[4]);
+ }
+ }
+ else if(wfull_len >= 4 && wfull[2] == L'.' && wfull[3] == L'\\')
+ { /* Starts with \\.\ a device name */
+ if(wfull_len >= 6 && isalpha(wfull[4]) && wfull[5] == L':')
+ { /* \\.\C:\Foo\bar\FooBar.txt */
+ return L"\\\\?\\" + kwsys_stl::wstring(&wfull[4]);
+ }
+ else if(wfull_len >= 5)
+ { /* \\.\Foo\bar\ Device name is left unchanged */
+ return kwsys_stl::wstring(&wfull[0]);
+ }
+ }
+ else if(wfull_len >= 3)
+ { /* \\Foo\bar\FooBar.txt */
+ return L"\\\\?\\UNC\\" + kwsys_stl::wstring(&wfull[2]);
+ }
+ }
+
+ // If this case has been reached, then the path is invalid. Leave it
+ // unchanged
+ return Encoding::ToWide(source);
+}
+#endif
+
// change // to /, and escape any spaces in the path
kwsys_stl::string SystemTools::ConvertToUnixOutputPath(const char* path)
{
@@ -1960,17 +2046,19 @@ bool SystemTools::FilesDiffer(const char* source,
#if defined(_WIN32)
WIN32_FILE_ATTRIBUTE_DATA statSource;
- if (GetFileAttributesExW(Encoding::ToWide(source).c_str(),
- GetFileExInfoStandard,
- &statSource) == 0)
+ if (GetFileAttributesExW(
+ SystemTools::ConvertToWindowsExtendedPath(source).c_str(),
+ GetFileExInfoStandard,
+ &statSource) == 0)
{
return true;
}
WIN32_FILE_ATTRIBUTE_DATA statDestination;
- if (GetFileAttributesExW(Encoding::ToWide(destination).c_str(),
- GetFileExInfoStandard,
- &statDestination) == 0)
+ if (GetFileAttributesExW(
+ SystemTools::ConvertToWindowsExtendedPath(destination).c_str(),
+ GetFileExInfoStandard,
+ &statDestination) == 0)
{
return true;
}
@@ -2191,7 +2279,12 @@ bool SystemTools::CopyADirectory(const char* source, const char* destination,
bool always)
{
Directory dir;
+#ifdef _WIN32
+ dir.Load(Encoding::ToNarrow(
+ SystemTools::ConvertToWindowsExtendedPath(source)).c_str());
+#else
dir.Load(source);
+#endif
size_t fileNum;
if ( !SystemTools::MakeDirectory(destination) )
{
@@ -2234,15 +2327,28 @@ bool SystemTools::CopyADirectory(const char* source, const char* destination,
// return size of file; also returns zero if no file exists
unsigned long SystemTools::FileLength(const char* filename)
{
- struct stat fs;
- if (stat(filename, &fs) != 0)
+ unsigned long length = 0;
+#ifdef _WIN32
+ WIN32_FILE_ATTRIBUTE_DATA fs;
+ if (GetFileAttributesExW(
+ SystemTools::ConvertToWindowsExtendedPath(filename).c_str(),
+ GetFileExInfoStandard, &fs) != 0)
{
- return 0;
+ /* To support the full 64-bit file size, use fs.nFileSizeHigh
+ * and fs.nFileSizeLow to construct the 64 bit size
+
+ length = ((__int64)fs.nFileSizeHigh << 32) + fs.nFileSizeLow;
+ */
+ length = static_cast<unsigned long>(fs.nFileSizeLow);
}
- else
+#else
+ struct stat fs;
+ if (stat(filename, &fs) == 0)
{
- return static_cast<unsigned long>(fs.st_size);
+ length = static_cast<unsigned long>(fs.st_size);
}
+#endif
+ return length;
}
int SystemTools::Strucmp(const char *s1, const char *s2)
@@ -2261,29 +2367,47 @@ int SystemTools::Strucmp(const char *s1, const char *s2)
// return file's modified time
long int SystemTools::ModifiedTime(const char* filename)
{
- struct stat fs;
- if (stat(filename, &fs) != 0)
+ long int mt = 0;
+#ifdef _WIN32
+ WIN32_FILE_ATTRIBUTE_DATA fs;
+ if (GetFileAttributesExW(
+ SystemTools::ConvertToWindowsExtendedPath(filename).c_str(),
+ GetFileExInfoStandard,
+ &fs) != 0)
{
- return 0;
+ mt = windows_filetime_to_posix_time(fs.ftLastWriteTime);
}
- else
+#else
+ struct stat fs;
+ if (stat(filename, &fs) == 0)
{
- return static_cast<long int>(fs.st_mtime);
+ mt = static_cast<long int>(fs.st_mtime);
}
+#endif
+ return mt;
}
// return file's creation time
long int SystemTools::CreationTime(const char* filename)
{
- struct stat fs;
- if (stat(filename, &fs) != 0)
+ long int ct = 0;
+#ifdef _WIN32
+ WIN32_FILE_ATTRIBUTE_DATA fs;
+ if (GetFileAttributesExW(
+ SystemTools::ConvertToWindowsExtendedPath(filename).c_str(),
+ GetFileExInfoStandard,
+ &fs) != 0)
{
- return 0;
+ ct = windows_filetime_to_posix_time(fs.ftCreationTime);
}
- else
+#else
+ struct stat fs;
+ if (stat(filename, &fs) == 0)
{
- return fs.st_ctime >= 0 ? static_cast<long int>(fs.st_ctime) : 0;
+ ct = fs.st_ctime >= 0 ? static_cast<long int>(fs.st_ctime) : 0;
}
+#endif
+ return ct;
}
bool SystemTools::ConvertDateMacroString(const char *str, time_t *tmt)
@@ -2406,7 +2530,8 @@ bool SystemTools::RemoveFile(const char* source)
SystemTools::SetPermissions(source, S_IWRITE);
#endif
#ifdef _WIN32
- bool res = _wunlink(Encoding::ToWide(source).c_str()) != 0 ? false : true;
+ bool res =
+ _wunlink(SystemTools::ConvertToWindowsExtendedPath(source).c_str()) == 0;
#else
bool res = unlink(source) != 0 ? false : true;
#endif
@@ -2435,7 +2560,12 @@ bool SystemTools::RemoveADirectory(const char* source)
}
Directory dir;
+#ifdef _WIN32
+ dir.Load(Encoding::ToNarrow(
+ SystemTools::ConvertToWindowsExtendedPath(source)).c_str());
+#else
dir.Load(source);
+#endif
size_t fileNum;
for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum)
{
@@ -2849,7 +2979,8 @@ bool SystemTools::FileIsDirectory(const char* name)
// Now check the file node type.
#if defined( _WIN32 )
- DWORD attr = GetFileAttributesW(Encoding::ToWide(name).c_str());
+ DWORD attr = GetFileAttributesW(
+ SystemTools::ConvertToWindowsExtendedPath(name).c_str());
if (attr != INVALID_FILE_ATTRIBUTES)
{
return (attr & FILE_ATTRIBUTE_DIRECTORY) != 0;
@@ -4041,7 +4172,7 @@ bool SystemTools::GetShortPath(const kwsys_stl::string& path, kwsys_stl::string&
kwsys_stl::wstring wtempPath = Encoding::ToWide(tempPath);
kwsys_stl::vector<wchar_t> buffer(wtempPath.size()+1);
buffer[0] = 0;
- ret = GetShortPathNameW(Encoding::ToWide(tempPath).c_str(),
+ ret = GetShortPathNameW(wtempPath.c_str(),
&buffer[0], static_cast<DWORD>(wtempPath.size()));
if(buffer[0] == 0 || ret > wtempPath.size())
@@ -4279,7 +4410,8 @@ bool SystemTools::GetPermissions(const char* file, mode_t& mode)
}
#if defined(_WIN32)
- DWORD attr = GetFileAttributesW(Encoding::ToWide(file).c_str());
+ DWORD attr = GetFileAttributesW(
+ SystemTools::ConvertToWindowsExtendedPath(file).c_str());
if(attr == INVALID_FILE_ATTRIBUTES)
{
return false;
@@ -4331,7 +4463,8 @@ bool SystemTools::SetPermissions(const char* file, mode_t mode)
return false;
}
#ifdef _WIN32
- if ( _wchmod(Encoding::ToWide(file).c_str(), mode) < 0 )
+ if ( _wchmod(SystemTools::ConvertToWindowsExtendedPath(file).c_str(),
+ mode) < 0 )
#else
if ( chmod(file, mode) < 0 )
#endif
diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in
index fb55848..b7c7206 100644
--- a/Source/kwsys/SystemTools.hxx.in
+++ b/Source/kwsys/SystemTools.hxx.in
@@ -249,7 +249,18 @@ public:
* Replace Windows file system slashes with Unix-style slashes.
*/
static void ConvertToUnixSlashes(kwsys_stl::string& path);
-
+
+#ifdef _WIN32
+ /**
+ * Convert the path to an extended length path to avoid MAX_PATH length
+ * limitations on Windows. If the input is a local path the result will be
+ * prefixed with \\?\; if the input is instead a network path, the result
+ * will be prefixed with \\?\UNC\. All output will also be converted to
+ * absolute paths with Windows-style backslashes.
+ **/
+ static kwsys_stl::wstring ConvertToWindowsExtendedPath(const kwsys_stl::string&);
+#endif
+
/**
* For windows this calls ConvertToWindowsOutputPath and for unix
* it calls ConvertToUnixOutputPath
diff --git a/Source/kwsys/testDynamicLoader.cxx b/Source/kwsys/testDynamicLoader.cxx
index 1bff707..58adb84 100644
--- a/Source/kwsys/testDynamicLoader.cxx
+++ b/Source/kwsys/testDynamicLoader.cxx
@@ -108,7 +108,7 @@ int testDynamicLoader(int argc, char *argv[])
// Make sure that inexistent lib is giving correct result
res += TestDynamicLoader("azerty_", "foo_bar",0,0,0);
// Make sure that random binary file cannot be assimilated as dylib
- res += TestDynamicLoader(TEST_SYSTEMTOOLS_BIN_FILE, "wp",0,0,0);
+ res += TestDynamicLoader(TEST_SYSTEMTOOLS_SOURCE_DIR "/testSystemTools.bin", "wp",0,0,0);
#endif
#ifdef __linux__
diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx
index 69825a8..8b21081 100644
--- a/Source/kwsys/testSystemTools.cxx
+++ b/Source/kwsys/testSystemTools.cxx
@@ -98,32 +98,124 @@ static bool CheckEscapeChars(kwsys_stl::string input,
static bool CheckFileOperations()
{
bool res = true;
-
- if (kwsys::SystemTools::DetectFileType(TEST_SYSTEMTOOLS_BIN_FILE) !=
+ const kwsys_stl::string testBinFile(TEST_SYSTEMTOOLS_SOURCE_DIR
+ "/testSystemTools.bin");
+ const kwsys_stl::string testTxtFile(TEST_SYSTEMTOOLS_SOURCE_DIR
+ "/testSystemTools.cxx");
+ const kwsys_stl::string testNewDir(TEST_SYSTEMTOOLS_BINARY_DIR
+ "/testSystemToolsNewDir");
+ const kwsys_stl::string testNewFile(testNewDir + "/testNewFile.txt");
+
+ if (kwsys::SystemTools::DetectFileType(testBinFile.c_str()) !=
kwsys::SystemTools::FileTypeBinary)
{
kwsys_ios::cerr
<< "Problem with DetectFileType - failed to detect type of: "
- << TEST_SYSTEMTOOLS_BIN_FILE << kwsys_ios::endl;
+ << testBinFile << kwsys_ios::endl;
res = false;
}
- if (kwsys::SystemTools::DetectFileType(TEST_SYSTEMTOOLS_SRC_FILE) !=
+ if (kwsys::SystemTools::DetectFileType(testTxtFile.c_str()) !=
kwsys::SystemTools::FileTypeText)
{
kwsys_ios::cerr
<< "Problem with DetectFileType - failed to detect type of: "
- << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl;
+ << testTxtFile << kwsys_ios::endl;
res = false;
}
-
- if (kwsys::SystemTools::FileLength(TEST_SYSTEMTOOLS_BIN_FILE) != 766)
+
+ if (kwsys::SystemTools::FileLength(testBinFile.c_str()) != 766)
{
kwsys_ios::cerr
<< "Problem with FileLength - incorrect length for: "
- << TEST_SYSTEMTOOLS_BIN_FILE << kwsys_ios::endl;
- res = false;
+ << testBinFile << kwsys_ios::endl;
+ res = false;
+ }
+
+ if (!kwsys::SystemTools::MakeDirectory(testNewDir.c_str()))
+ {
+ kwsys_ios::cerr
+ << "Problem with MakeDirectory for: "
+ << testNewDir << kwsys_ios::endl;
+ res = false;
+ }
+
+ if (!kwsys::SystemTools::Touch(testNewFile.c_str(), true))
+ {
+ kwsys_ios::cerr
+ << "Problem with Touch for: "
+ << testNewFile << kwsys_ios::endl;
+ res = false;
+ }
+
+ if (!kwsys::SystemTools::RemoveFile(testNewFile.c_str()))
+ {
+ kwsys_ios::cerr
+ << "Problem with RemoveFile: "
+ << testNewFile << kwsys_ios::endl;
+ res = false;
+ }
+
+ kwsys::SystemTools::Touch(testNewFile.c_str(), true);
+ if (!kwsys::SystemTools::RemoveADirectory(testNewDir.c_str()))
+ {
+ kwsys_ios::cerr
+ << "Problem with RemoveADirectory for: "
+ << testNewDir << kwsys_ios::endl;
+ res = false;
+ }
+
+#ifdef KWSYS_TEST_SYSTEMTOOLS_LONG_PATHS
+ // Perform the same file and directory creation and deletion tests but
+ // with paths > 256 characters in length.
+
+ const kwsys_stl::string testNewLongDir(
+ TEST_SYSTEMTOOLS_BINARY_DIR "/"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "01234567890123");
+ const kwsys_stl::string testNewLongFile(testNewLongDir + "/"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "0123456789.txt");
+
+ if (!kwsys::SystemTools::MakeDirectory(testNewLongDir.c_str()))
+ {
+ kwsys_ios::cerr
+ << "Problem with MakeDirectory for: "
+ << testNewLongDir << kwsys_ios::endl;
+ res = false;
+ }
+
+ if (!kwsys::SystemTools::Touch(testNewLongFile.c_str(), true))
+ {
+ kwsys_ios::cerr
+ << "Problem with Touch for: "
+ << testNewLongFile << kwsys_ios::endl;
+ res = false;
+ }
+
+ if (!kwsys::SystemTools::RemoveFile(testNewLongFile.c_str()))
+ {
+ kwsys_ios::cerr
+ << "Problem with RemoveFile: "
+ << testNewLongFile << kwsys_ios::endl;
+ res = false;
+ }
+
+ kwsys::SystemTools::Touch(testNewLongFile.c_str(), true);
+ if (!kwsys::SystemTools::RemoveADirectory(testNewLongDir.c_str()))
+ {
+ kwsys_ios::cerr
+ << "Problem with RemoveADirectory for: "
+ << testNewLongDir << kwsys_ios::endl;
+ res = false;
}
+#endif
return res;
}
@@ -138,7 +230,7 @@ static bool CheckStringOperations()
{
kwsys_ios::cerr
<< "Problem with CapitalizedWords "
- << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl;
+ << '"' << test << '"' << kwsys_ios::endl;
res = false;
}
@@ -148,7 +240,7 @@ static bool CheckStringOperations()
{
kwsys_ios::cerr
<< "Problem with UnCapitalizedWords "
- << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl;
+ << '"' << test << '"' << kwsys_ios::endl;
res = false;
}
@@ -158,7 +250,7 @@ static bool CheckStringOperations()
{
kwsys_ios::cerr
<< "Problem with AddSpaceBetweenCapitalizedWords "
- << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl;
+ << '"' << test << '"' << kwsys_ios::endl;
res = false;
}
@@ -168,7 +260,7 @@ static bool CheckStringOperations()
{
kwsys_ios::cerr
<< "Problem with AppendStrings "
- << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl;
+ << "\"Mary Had A\" \" Little Lamb.\"" << kwsys_ios::endl;
res = false;
}
delete [] cres;
@@ -179,7 +271,7 @@ static bool CheckStringOperations()
{
kwsys_ios::cerr
<< "Problem with AppendStrings "
- << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl;
+ << "\"Mary Had\" \" A \" \"Little Lamb.\"" << kwsys_ios::endl;
res = false;
}
delete [] cres;
@@ -188,7 +280,7 @@ static bool CheckStringOperations()
{
kwsys_ios::cerr
<< "Problem with CountChar "
- << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl;
+ << "\"Mary Had A Little Lamb.\"" << kwsys_ios::endl;
res = false;
}
@@ -198,7 +290,7 @@ static bool CheckStringOperations()
{
kwsys_ios::cerr
<< "Problem with RemoveChars "
- << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl;
+ << "\"Mary Had A Little Lamb.\"" << kwsys_ios::endl;
res = false;
}
delete [] cres;
@@ -209,7 +301,7 @@ static bool CheckStringOperations()
{
kwsys_ios::cerr
<< "Problem with RemoveCharsButUpperHex "
- << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl;
+ << "\"Mary Had A Little Lamb.\"" << kwsys_ios::endl;
res = false;
}
delete [] cres;
@@ -221,7 +313,7 @@ static bool CheckStringOperations()
{
kwsys_ios::cerr
<< "Problem with ReplaceChars "
- << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl;
+ << "\"Mary Had A Little Lamb.\"" << kwsys_ios::endl;
res = false;
}
delete [] cres2;
@@ -231,7 +323,7 @@ static bool CheckStringOperations()
{
kwsys_ios::cerr
<< "Problem with StringStartsWith "
- << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl;
+ << "\"Mary Had A Little Lamb.\"" << kwsys_ios::endl;
res = false;
}
@@ -240,7 +332,7 @@ static bool CheckStringOperations()
{
kwsys_ios::cerr
<< "Problem with StringEndsWith "
- << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl;
+ << "\"Mary Had A Little Lamb.\"" << kwsys_ios::endl;
res = false;
}
@@ -249,7 +341,7 @@ static bool CheckStringOperations()
{
kwsys_ios::cerr
<< "Problem with DuplicateString "
- << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl;
+ << "\"Mary Had A Little Lamb.\"" << kwsys_ios::endl;
res = false;
}
delete [] cres;
@@ -260,7 +352,7 @@ static bool CheckStringOperations()
{
kwsys_ios::cerr
<< "Problem with CropString "
- << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl;
+ << "\"Mary Had A Little Lamb.\"" << kwsys_ios::endl;
res = false;
}
@@ -271,16 +363,124 @@ static bool CheckStringOperations()
{
kwsys_ios::cerr
<< "Problem with Split "
- << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl;
- res = false;
+ << "\"Mary Had A Little Lamb.\"" << kwsys_ios::endl;
+ res = false;
+ }
+
+#ifdef _WIN32
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath
+ ("L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") !=
+ L"\\\\?\\L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo")
+ {
+ kwsys_ios::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\""
+ << kwsys_ios::endl;
+ res = false;
}
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath
+ ("L:/Local Mojo/Hex Power Pack/Iffy Voodoo") !=
+ L"\\\\?\\L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo")
+ {
+ kwsys_ios::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"L:/Local Mojo/Hex Power Pack/Iffy Voodoo\""
+ << kwsys_ios::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath
+ ("\\\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") !=
+ L"\\\\?\\UNC\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo")
+ {
+ kwsys_ios::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"\\\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\""
+ << kwsys_ios::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath
+ ("//Foo/Local Mojo/Hex Power Pack/Iffy Voodoo") !=
+ L"\\\\?\\UNC\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo")
+ {
+ kwsys_ios::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"//Foo/Local Mojo/Hex Power Pack/Iffy Voodoo\""
+ << kwsys_ios::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath("//") !=
+ L"//")
+ {
+ kwsys_ios::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"//\""
+ << kwsys_ios::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath("\\\\.\\") !=
+ L"\\\\.\\")
+ {
+ kwsys_ios::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"\\\\.\\\""
+ << kwsys_ios::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath("\\\\.\\X") !=
+ L"\\\\.\\X")
+ {
+ kwsys_ios::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"\\\\.\\X\""
+ << kwsys_ios::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath("\\\\.\\X:") !=
+ L"\\\\?\\X:")
+ {
+ kwsys_ios::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"\\\\.\\X:\""
+ << kwsys_ios::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath("\\\\.\\X:\\") !=
+ L"\\\\?\\X:\\")
+ {
+ kwsys_ios::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"\\\\.\\X:\\\""
+ << kwsys_ios::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath("NUL") !=
+ L"\\\\.\\NUL")
+ {
+ kwsys_ios::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"NUL\""
+ << kwsys_ios::endl;
+ res = false;
+ }
+
+#endif
+
if (kwsys::SystemTools::ConvertToWindowsOutputPath
("L://Local Mojo/Hex Power Pack/Iffy Voodoo") !=
"\"L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"")
{
kwsys_ios::cerr
<< "Problem with ConvertToWindowsOutputPath "
+ << "\"L://Local Mojo/Hex Power Pack/Iffy Voodoo\""
<< kwsys_ios::endl;
res = false;
}
@@ -291,6 +491,7 @@ static bool CheckStringOperations()
{
kwsys_ios::cerr
<< "Problem with ConvertToWindowsOutputPath "
+ << "\"//grayson/Local Mojo/Hex Power Pack/Iffy Voodoo\""
<< kwsys_ios::endl;
res = false;
}
@@ -301,6 +502,7 @@ static bool CheckStringOperations()
{
kwsys_ios::cerr
<< "Problem with ConvertToUnixOutputPath "
+ << "\"//Local Mojo/Hex Power Pack/Iffy Voodoo\""
<< kwsys_ios::endl;
res = false;
}
@@ -308,14 +510,17 @@ static bool CheckStringOperations()
int targc;
char **targv;
kwsys::SystemTools::ConvertWindowsCommandLineToUnixArguments
- ("\"Local Mojo\\Voodoo.asp\" -CastHex \"D:\\My Secret Mojo\\Voodoo.mp3\"", &targc, &targv);
+ ("\"Local Mojo\\Voodoo.asp\" -CastHex \"D:\\My Secret Mojo\\Voodoo.mp3\"",
+ &targc, &targv);
if (targc != 4 || strcmp(targv[1],"Local Mojo\\Voodoo.asp") ||
strcmp(targv[2],"-CastHex") ||
strcmp(targv[3],"D:\\My Secret Mojo\\Voodoo.mp3"))
{
kwsys_ios::cerr
<< "Problem with ConvertWindowsCommandLineToUnixArguments"
- << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl;
+ << "\'\"Local Mojo\\Voodoo.asp\" "
+ << "-CastHex \"D:\\My Secret Mojo\\Voodoo.mp3\"\'"
+ << kwsys_ios::endl;
res = false;
}
for (;targc >=0; --targc)
diff --git a/Source/kwsys/testSystemTools.h.in b/Source/kwsys/testSystemTools.h.in
index 4b94bb6..66f0f72 100644
--- a/Source/kwsys/testSystemTools.h.in
+++ b/Source/kwsys/testSystemTools.h.in
@@ -14,7 +14,8 @@
#define EXECUTABLE_OUTPUT_PATH "@CMAKE_CURRENT_BINARY_DIR@"
-#define TEST_SYSTEMTOOLS_BIN_FILE "@TEST_SYSTEMTOOLS_BIN_FILE@"
-#define TEST_SYSTEMTOOLS_SRC_FILE "@TEST_SYSTEMTOOLS_SRC_FILE@"
+#define TEST_SYSTEMTOOLS_SOURCE_DIR "@TEST_SYSTEMTOOLS_SOURCE_DIR@"
+#define TEST_SYSTEMTOOLS_BINARY_DIR "@TEST_SYSTEMTOOLS_BINARY_DIR@"
+#cmakedefine KWSYS_TEST_SYSTEMTOOLS_LONG_PATHS
#endif
diff --git a/Tests/CTestTestMemcheck/CMakeLists.txt b/Tests/CTestTestMemcheck/CMakeLists.txt
index 8984463..f470835 100644
--- a/Tests/CTestTestMemcheck/CMakeLists.txt
+++ b/Tests/CTestTestMemcheck/CMakeLists.txt
@@ -103,6 +103,19 @@ unset(CTEST_EXTRA_CONFIG)
unset(CTEST_EXTRA_CODE)
unset(CMAKELISTS_EXTRA_CODE)
+# add ThreadSanitizer test
+set(CTEST_EXTRA_CODE
+"set(CTEST_MEMORYCHECK_COMMAND_OPTIONS \"report_bugs=1 history_size=5 exitcode=55\")
+")
+
+set(CMAKELISTS_EXTRA_CODE
+"add_test(NAME TestSan COMMAND \"${CMAKE_COMMAND}\"
+-P \"${CMAKE_CURRENT_SOURCE_DIR}/testThreadSanitizer.cmake\")
+")
+gen_mc_test_internal(DummyThreadSanitizer "" -DMEMCHECK_TYPE=ThreadSanitizer)
+set(CMAKELISTS_EXTRA_CODE )
+set(CTEST_EXTRA_CODE)
+
gen_mc_test(DummyPurify "\${PSEUDO_PURIFY}")
gen_mc_test(DummyValgrind "\${PSEUDO_VALGRIND}")
gen_mc_test(DummyBC "\${PSEUDO_BC}")
@@ -189,6 +202,11 @@ set_tests_properties(CTestTestMemcheckDummyValgrindTwoTargets PROPERTIES
PASS_REGULAR_EXPRESSION
"\nMemory check project ${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/DummyValgrindTwoTargets\n.*\n *Start 1: RunCMake\n(.*\n)?Memory check command: .* \"--log-file=${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/DummyValgrindTwoTargets/Testing/Temporary/MemoryChecker.1.log\" \"-q\".*\n *Start 2: RunCMakeAgain\n(.*\n)?Memory check command: .* \"--log-file=${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/DummyValgrindTwoTargets/Testing/Temporary/MemoryChecker.2.log\" \"-q\".*\n")
+set_tests_properties(CTestTestMemcheckDummyThreadSanitizer PROPERTIES
+ PASS_REGULAR_EXPRESSION
+ ".*Memory checking results:.*data race.* - 1.*data race on vptr .ctor/dtor vs virtual call. - 1.*heap-use-after-free - 1.*thread leak - 1.*destroy of a locked mutex - 1.*double lock of a mutex - 1.*unlock of an unlocked mutex .or by a wrong thread. - 1.*read lock of a write locked mutex - 1.*read unlock of a write locked mutex - 1.*signal-unsafe call inside of a signal - 1.*signal handler spoils errno - 1.*lock-order-inversion .potential deadlock. - 1.*")
+
+
# Xcode 2.x forgets to create the output directory before linking
# the individual architectures.
if(CMAKE_OSX_ARCHITECTURES AND XCODE AND NOT "${XCODE_VERSION}" MATCHES "^[^12]")
diff --git a/Tests/CTestTestMemcheck/test.cmake.in b/Tests/CTestTestMemcheck/test.cmake.in
index 471e5a5..87195c5 100644
--- a/Tests/CTestTestMemcheck/test.cmake.in
+++ b/Tests/CTestTestMemcheck/test.cmake.in
@@ -15,6 +15,7 @@ set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
set(CTEST_MEMORYCHECK_COMMAND "@CHECKER_COMMAND@")
+set(CTEST_MEMORYCHECK_TYPE "${MEMCHECK_TYPE}")
@CTEST_EXTRA_CODE@
diff --git a/Tests/CTestTestMemcheck/testThreadSanitizer.cmake b/Tests/CTestTestMemcheck/testThreadSanitizer.cmake
new file mode 100644
index 0000000..d591931
--- /dev/null
+++ b/Tests/CTestTestMemcheck/testThreadSanitizer.cmake
@@ -0,0 +1,47 @@
+# this file simulates a program that has been built with thread sanitizer
+# options
+
+message("TSAN_OPTIONS = [$ENV{TSAN_OPTIONS}]")
+string(REGEX REPLACE ".*log_path=\"([^\"]*)\".*" "\\1" LOG_FILE "$ENV{TSAN_OPTIONS}")
+message("LOG_FILE=[${LOG_FILE}]")
+
+set(error_types
+ "data race"
+ "data race on vptr (ctor/dtor vs virtual call)"
+ "heap-use-after-free"
+ "thread leak"
+ "destroy of a locked mutex"
+ "double lock of a mutex"
+ "unlock of an unlocked mutex (or by a wrong thread)"
+ "read lock of a write locked mutex"
+ "read unlock of a write locked mutex"
+ "signal-unsafe call inside of a signal"
+ "signal handler spoils errno"
+ "lock-order-inversion (potential deadlock)"
+ )
+
+# clear the log file
+file(REMOVE "${LOG_FILE}.2343")
+
+# create an error of each type of thread santizer
+# these names come from tsan_report.cc in llvm
+foreach(error_type ${error_types} )
+
+ file(APPEND "${LOG_FILE}.2343"
+"==================
+WARNING: ThreadSanitizer: ${error_type} (pid=27978)
+ Write of size 4 at 0x7fe017ce906c by thread T1:
+ #0 Thread1 ??:0 (exe+0x000000000bb0)
+ #1 <null> <null>:0 (libtsan.so.0+0x00000001b279)
+
+ Previous write of size 4 at 0x7fe017ce906c by main thread:
+ #0 main ??:0 (exe+0x000000000c3c)
+
+ Thread T1 (tid=27979, running) created by main thread at:
+ #0 <null> <null>:0 (libtsan.so.0+0x00000001ed7b)
+ #1 main ??:0 (exe+0x000000000c2c)
+
+SUMMARY: ThreadSanitizer: ${error_type} ??:0 Thread1
+==================
+")
+endforeach()
diff --git a/Tests/ObjectLibrary/A/CMakeLists.txt b/Tests/ObjectLibrary/A/CMakeLists.txt
index 55778ea..c24c5ed 100644
--- a/Tests/ObjectLibrary/A/CMakeLists.txt
+++ b/Tests/ObjectLibrary/A/CMakeLists.txt
@@ -1,18 +1,26 @@
project(ObjectLibraryA C)
# Add -fPIC so objects can be used in shared libraries.
-# TODO: Need property for this.
-if(CMAKE_SHARED_LIBRARY_C_FLAGS AND NOT WATCOM)
- set(CMAKE_C_FLAGS "${CMAKE_SHARED_LIBRARY_C_FLAGS} ${CMAKE_C_FLAGS}")
-endif()
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
add_definitions(-DA_DEF)
add_custom_command(
OUTPUT a1.c
- DEPENDS a1.c.in
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/a1.c.in
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/a1.c.in
${CMAKE_CURRENT_BINARY_DIR}/a1.c
)
-add_library(A OBJECT a1.c a2.c)
+# Remove the custom command output to be sure it runs in an
+# incremental test. Skip this on VS 6 because it sometimes
+# re-runs CMake after the custom command runs.
+if(NOT CMAKE_GENERATOR STREQUAL "Visual Studio 6")
+ file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/a.cmake)
+endif()
+add_custom_command(
+ OUTPUT a.cmake
+ COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/a.cmake
+ )
+
+add_library(A OBJECT a1.c a2.c a.cmake)
target_include_directories(A PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/Tests/ObjectLibrary/B/CMakeLists.txt b/Tests/ObjectLibrary/B/CMakeLists.txt
index a567f96..2158084 100644
--- a/Tests/ObjectLibrary/B/CMakeLists.txt
+++ b/Tests/ObjectLibrary/B/CMakeLists.txt
@@ -5,10 +5,7 @@ if("${CMAKE_GENERATOR}" MATCHES "Visual Studio 6")
endif()
# Add -fPIC so objects can be used in shared libraries.
-# TODO: Need property for this.
-if(CMAKE_SHARED_LIBRARY_C_FLAGS AND NOT WATCOM)
- set(CMAKE_C_FLAGS "${CMAKE_SHARED_LIBRARY_C_FLAGS} ${CMAKE_C_FLAGS}")
-endif()
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
add_library(B OBJECT b1.c b2.c)
target_include_directories(B PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/Tests/ObjectLibrary/CMakeLists.txt b/Tests/ObjectLibrary/CMakeLists.txt
index 75c34d8..e9f553e 100644
--- a/Tests/ObjectLibrary/CMakeLists.txt
+++ b/Tests/ObjectLibrary/CMakeLists.txt
@@ -12,6 +12,7 @@ add_library(Cshared SHARED c.c $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:Bexport>)
add_executable(UseCshared main.c)
set_property(TARGET UseCshared PROPERTY COMPILE_DEFINITIONS SHARED_C)
target_link_libraries(UseCshared Cshared)
+add_custom_command(TARGET UseCshared POST_BUILD COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/A/a.cmake)
add_executable(UseCinternal main.c c.c $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:B>)
diff --git a/Tests/RunCMake/ObjectLibrary/BadObjSource1-stderr.txt b/Tests/RunCMake/ObjectLibrary/BadObjSource1-stderr.txt
index b31225b..a09552b 100644
--- a/Tests/RunCMake/ObjectLibrary/BadObjSource1-stderr.txt
+++ b/Tests/RunCMake/ObjectLibrary/BadObjSource1-stderr.txt
@@ -3,6 +3,7 @@ CMake Error at BadObjSource1.cmake:1 \(add_library\):
bad.def
- but may contain only headers and sources that compile.
+ but may contain only sources that compile, header files, and other files
+ that would not affect linking of a normal library.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/ObjectLibrary/BadObjSource2-stderr.txt b/Tests/RunCMake/ObjectLibrary/BadObjSource2-stderr.txt
index 906cf0b..b91ffd0 100644
--- a/Tests/RunCMake/ObjectLibrary/BadObjSource2-stderr.txt
+++ b/Tests/RunCMake/ObjectLibrary/BadObjSource2-stderr.txt
@@ -3,6 +3,7 @@ CMake Error at BadObjSource2.cmake:1 \(add_library\):
bad.obj
- but may contain only headers and sources that compile.
+ but may contain only sources that compile, header files, and other files
+ that would not affect linking of a normal library.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)