diff options
Diffstat (limited to 'Source')
41 files changed, 1132 insertions, 1929 deletions
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 20e68e9..a18fcf0 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -2,5 +2,5 @@ set(CMake_VERSION_MAJOR 2) set(CMake_VERSION_MINOR 8) set(CMake_VERSION_PATCH 10) -set(CMake_VERSION_TWEAK 20121211) +set(CMake_VERSION_TWEAK 20130107) #set(CMake_VERSION_RC 1) diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx index 8b58625..e8b0ea9 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -221,6 +221,9 @@ bool cmCPackWIXGenerator::CreateWiXVariablesIncludeFile() CopyDefinition(includeFile, "CPACK_PACKAGE_NAME"); CopyDefinition(includeFile, "CPACK_PACKAGE_VERSION"); CopyDefinition(includeFile, "CPACK_WIX_LICENSE_RTF"); + CopyDefinition(includeFile, "CPACK_WIX_PRODUCT_ICON"); + CopyDefinition(includeFile, "CPACK_WIX_UI_BANNER"); + CopyDefinition(includeFile, "CPACK_WIX_UI_DIALOG"); return true; } diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index ebef1ed..76ddeea 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -248,7 +248,12 @@ bool cmCTestMultiProcessHandler::StartTest(int test) //--------------------------------------------------------- void cmCTestMultiProcessHandler::StartNextTests() { - size_t numToStart = this->ParallelLevel - this->RunningCount; + size_t numToStart = 0; + if(this->RunningCount < this->ParallelLevel) + { + numToStart = this->ParallelLevel - this->RunningCount; + } + if(numToStart == 0) { return; diff --git a/Source/cmAddLibraryCommand.h b/Source/cmAddLibraryCommand.h index c144565..e5f27cb 100644 --- a/Source/cmAddLibraryCommand.h +++ b/Source/cmAddLibraryCommand.h @@ -134,6 +134,10 @@ public: "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 systems may not like targets that have only " + "object files, so consider adding at least one real source file " + "to any target that references $<TARGET_OBJECTS:objlib>." ; } diff --git a/Source/cmCommandArgumentParser.cxx b/Source/cmCommandArgumentParser.cxx index 696a6a8..c5146c5 100644 --- a/Source/cmCommandArgumentParser.cxx +++ b/Source/cmCommandArgumentParser.cxx @@ -279,7 +279,7 @@ typedef short int yytype_int16; #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) #ifndef YY_ -# if YYENABLE_NLS +# if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include <libintl.h> /* INFRINGES ON USER NAME SPACE */ # define YY_(msgid) dgettext ("bison-runtime", msgid) @@ -701,7 +701,7 @@ while (YYID (0)) we won't break user code: when these are the locations we know. */ #ifndef YY_LOCATION_PRINT -# if YYLTYPE_IS_TRIVIAL +# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL # define YY_LOCATION_PRINT(File, Loc) \ fprintf (File, "%d.%d-%d.%d", \ (Loc).first_line, (Loc).first_column, \ diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx index ab77c6b..3b15ec1 100644 --- a/Source/cmComputeTargetDepends.cxx +++ b/Source/cmComputeTargetDepends.cxx @@ -214,6 +214,8 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) if(emitted.insert(lib->first).second) { this->AddTargetDepend(depender_index, lib->first.c_str(), true); + this->AddInterfaceDepends(depender_index, lib->first.c_str(), + true, emitted); } } } @@ -237,6 +239,63 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) } //---------------------------------------------------------------------------- +void cmComputeTargetDepends::AddInterfaceDepends(int depender_index, + cmTarget* dependee, + const char *config, + std::set<cmStdString> &emitted) +{ + if(cmTarget::LinkInterface const* iface = + dependee->GetLinkInterface(config)) + { + for(std::vector<std::string>::const_iterator + lib = iface->Libraries.begin(); + lib != iface->Libraries.end(); ++lib) + { + // Don't emit the same library twice for this target. + if(emitted.insert(*lib).second) + { + this->AddTargetDepend(depender_index, lib->c_str(), true); + } + } + } +} + +//---------------------------------------------------------------------------- +void cmComputeTargetDepends::AddInterfaceDepends(int depender_index, + const char* dependee_name, + bool linking, + std::set<cmStdString> &emitted) +{ + cmTarget* depender = this->Targets[depender_index]; + cmTarget* dependee = + depender->GetMakefile()->FindTargetToUse(dependee_name); + // Skip targets that will not really be linked. This is probably a + // name conflict between an external library and an executable + // within the project. + if(linking && dependee && + dependee->GetType() == cmTarget::EXECUTABLE && + !dependee->IsExecutableWithExports()) + { + dependee = 0; + } + + if(dependee) + { + this->AddInterfaceDepends(depender_index, dependee, 0, emitted); + std::vector<std::string> configs; + depender->GetMakefile()->GetConfigurations(configs); + for (std::vector<std::string>::const_iterator it = configs.begin(); + it != configs.end(); ++it) + { + // A target should not depend on itself. + emitted.insert(depender->GetName()); + this->AddInterfaceDepends(depender_index, dependee, + it->c_str(), emitted); + } + } +} + +//---------------------------------------------------------------------------- void cmComputeTargetDepends::AddTargetDepend(int depender_index, const char* dependee_name, bool linking) diff --git a/Source/cmComputeTargetDepends.h b/Source/cmComputeTargetDepends.h index 67bce72..d6131cf 100644 --- a/Source/cmComputeTargetDepends.h +++ b/Source/cmComputeTargetDepends.h @@ -48,7 +48,11 @@ private: bool linking); void AddTargetDepend(int depender_index, cmTarget* dependee, bool linking); bool ComputeFinalDepends(cmComputeComponentGraph const& ccg); - + void AddInterfaceDepends(int depender_index, const char* dependee_name, + bool linking, std::set<cmStdString> &emitted); + void AddInterfaceDepends(int depender_index, cmTarget* dependee, + const char *config, + std::set<cmStdString> &emitted); cmGlobalGenerator* GlobalGenerator; bool DebugMode; bool NoCycles; diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx index 07df7d5..f2f77ee 100644 --- a/Source/cmCustomCommandGenerator.cxx +++ b/Source/cmCustomCommandGenerator.cxx @@ -47,7 +47,7 @@ std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const { return target->GetLocation(this->Config); } - return this->GE->Parse(argv0).Evaluate(this->Makefile, this->Config); + return this->GE->Parse(argv0)->Evaluate(this->Makefile, this->Config); } //---------------------------------------------------------------------------- @@ -58,7 +58,7 @@ cmCustomCommandGenerator cmCustomCommandLine const& commandLine = this->CC.GetCommandLines()[c]; for(unsigned int j=1;j < commandLine.size(); ++j) { - std::string arg = this->GE->Parse(commandLine[j]).Evaluate(this->Makefile, + std::string arg = this->GE->Parse(commandLine[j])->Evaluate(this->Makefile, this->Config); cmd += " "; if(this->OldStyle) diff --git a/Source/cmDocumentGeneratorExpressions.h b/Source/cmDocumentGeneratorExpressions.h index 445fd0e..b8889ac 100644 --- a/Source/cmDocumentGeneratorExpressions.h +++ b/Source/cmDocumentGeneratorExpressions.h @@ -26,6 +26,16 @@ "strings which contain a '>' for example.\n" \ " $<COMMA> = A literal ','. Used to compare " \ "strings which contain a ',' for example.\n" \ + " $<TARGET_NAME:...> = Marks ... as being the name of a " \ + "target. This is required if exporting targets to multiple " \ + "dependent export sets. The '...' must be a literal name of a " \ + "target- it may not contain generator expressions.\n" \ + " $<INSTALL_INTERFACE:...> = content of \"...\" when the property " \ + "is exported using install(EXPORT), and empty otherwise.\n" \ + " $<BUILD_INTERFACE:...> = content of \"...\" when the property " \ + "is exported using export(), or when the target is used by another " \ + "target in the same buildsystem. Expands to the empty string " \ + "otherwise.\n" \ " $<TARGET_FILE:tgt> = main file (.exe, .so.1.2, .a)\n" \ " $<TARGET_LINKER_FILE:tgt> = file used to link (.a, .lib, .so)\n" \ " $<TARGET_SONAME_FILE:tgt> = file with soname (.so.3)\n" \ diff --git a/Source/cmDocumentVariables.cxx b/Source/cmDocumentVariables.cxx index 0a4170b..be45e2d 100644 --- a/Source/cmDocumentVariables.cxx +++ b/Source/cmDocumentVariables.cxx @@ -896,6 +896,15 @@ void cmDocumentVariables::DefineVariables(cmake* cm) " script, it may get fatal error messages from the script.",false, "Variables That Change Behavior"); + cm->DefineProperty + ("CMAKE_DEBUG_TARGET_PROPERTIES", cmProperty::VARIABLE, + "Enables tracing output for target properties.", + "This variable can be populated with a list of properties to generate " + "debug output for when evaluating target properties. Currently it can " + "only be used when evaluating the INCLUDE_DIRECTORIES target property. " + "In that case, it outputs a backtrace for each include directory in " + "the build. Default is unset.",false,"Variables That Change Behavior"); + // Variables defined by CMake that describe the system cm->DefineProperty @@ -1621,7 +1630,15 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "These paths are implicit linker search directories for the compiler's " "language. " "CMake automatically detects these directories for each language and " - "reports the results in this variable.", false, + "reports the results in this variable." + "\n" + "When a library in one of these directories is given by full path to " + "target_link_libraries() CMake will generate the -l<name> form on " + "link lines to ensure the linker searches its implicit directories " + "for the library. " + "Note that some toolchains read implicit directories from an " + "environment variable such as LIBRARY_PATH so keep its value " + "consistent when operating in a given build tree.",false, "Variables for Languages"); cm->DefineProperty diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index cd6a7ab..9533319 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -22,6 +22,7 @@ cmExportBuildFileGenerator::cmExportBuildFileGenerator() //---------------------------------------------------------------------------- bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) { + std::vector<cmTarget*> allTargets; { std::string expectedTargets; std::string sep; @@ -31,20 +32,10 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) { expectedTargets += sep + this->Namespace + (*tei)->GetName(); sep = " "; - } - - this->GenerateExpectedTargetsCode(os, expectedTargets); - } - - // Create all the imported targets. - for(std::vector<cmTarget*>::const_iterator - tei = this->Exports->begin(); - tei != this->Exports->end(); ++tei) - { cmTarget* te = *tei; if(this->ExportedTargets.insert(te).second) { - this->GenerateImportTargetCode(os, te); + allTargets.push_back(te); } else { @@ -58,6 +49,33 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) } } + this->GenerateExpectedTargetsCode(os, expectedTargets); + } + + std::vector<std::string> missingTargets; + + // Create all the imported targets. + for(std::vector<cmTarget*>::const_iterator + tei = allTargets.begin(); + tei != allTargets.end(); ++tei) + { + cmTarget* te = *tei; + this->GenerateImportTargetCode(os, te); + + ImportPropertyMap properties; + + this->PopulateInterfaceProperty("INTERFACE_INCLUDE_DIRECTORIES", te, + cmGeneratorExpression::BuildInterface, + properties, missingTargets); + this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", te, + cmGeneratorExpression::BuildInterface, + properties, missingTargets); + + this->GenerateInterfaceProperties(te, os, properties); + } + + this->GenerateMissingTargetsCheckCode(os, missingTargets); + // Generate import file content for each configuration. for(std::vector<std::string>::const_iterator ci = this->Configurations.begin(); diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 3f738cc..2b133be 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -125,6 +125,201 @@ void cmExportFileGenerator::GenerateImportConfig(std::ostream& os, } //---------------------------------------------------------------------------- +void cmExportFileGenerator::PopulateInterfaceProperty(const char *propName, + const char *outputName, + cmTarget *target, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap &properties, + std::vector<std::string> &missingTargets) +{ + const char *input = target->GetProperty(propName); + if (input) + { + if (!*input) + { + // Set to empty + properties[outputName] = ""; + return; + } + + std::string prepro = cmGeneratorExpression::Preprocess(input, + preprocessRule); + if (!prepro.empty()) + { + this->ResolveTargetsInGeneratorExpressions(prepro, target, + missingTargets); + properties[outputName] = prepro; + } + } +} + +//---------------------------------------------------------------------------- +void cmExportFileGenerator::PopulateInterfaceProperty(const char *propName, + cmTarget *target, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap &properties, + std::vector<std::string> &missingTargets) +{ + this->PopulateInterfaceProperty(propName, propName, target, preprocessRule, + properties, missingTargets); +} + +//---------------------------------------------------------------------------- +void cmExportFileGenerator::GenerateInterfaceProperties(cmTarget *target, + std::ostream& os, + const ImportPropertyMap &properties) +{ + if (!properties.empty()) + { + std::string targetName = this->Namespace; + targetName += target->GetName(); + os << "SET_TARGET_PROPERTIES(" << targetName << " PROPERTIES\n"; + for(ImportPropertyMap::const_iterator pi = properties.begin(); + pi != properties.end(); ++pi) + { + os << " " << pi->first << " \"" << pi->second << "\"\n"; + } + os << ")\n\n"; + } +} + +//---------------------------------------------------------------------------- +void +cmExportFileGenerator::ResolveTargetsInGeneratorExpressions( + std::string &input, + cmTarget* target, + std::vector<std::string> &missingTargets) +{ + std::string::size_type pos = 0; + std::string::size_type lastPos = pos; + + cmMakefile *mf = target->GetMakefile(); + std::string errorString; + + while((pos = input.find("$<TARGET_PROPERTY:", lastPos)) != input.npos) + { + std::string::size_type nameStartPos = pos + + sizeof("$<TARGET_PROPERTY:") - 1; + std::string::size_type closePos = input.find(">", nameStartPos); + std::string::size_type commaPos = input.find(",", nameStartPos); + std::string::size_type nextOpenPos = input.find("$<", nameStartPos); + if (commaPos == input.npos // Implied 'this' target + || closePos == input.npos // Imcomplete expression. + || closePos < commaPos // Implied 'this' target + || nextOpenPos < commaPos) // Non-literal + { + lastPos = nameStartPos; + continue; + } + + const std::string targetName = input.substr(nameStartPos, + commaPos - nameStartPos); + + pos = nameStartPos; // We're not going to replace the entire expression, + // but only the target parameter. + if (cmTarget *tgt = mf->FindTargetToUse(targetName.c_str())) + { + if(tgt->IsImported()) + { + pos += targetName.size(); + } + else if(this->ExportedTargets.find(tgt) != this->ExportedTargets.end()) + { + input.replace(pos, targetName.size(), + this->Namespace + targetName); + pos += this->Namespace.size() + targetName.size(); + } + else + { + std::string namespacedTarget; + this->HandleMissingTarget(namespacedTarget, missingTargets, + mf, target, tgt); + if (!namespacedTarget.empty()) + { + input.replace(pos, targetName.size(), namespacedTarget); + pos += namespacedTarget.size(); + } + } + } + else + { + errorString = "$<TARGET_PROPERTY:" + targetName + ",prop> requires " + "its first parameter to be a reachable target."; + } + lastPos = pos; + if (!errorString.empty()) + { + break; + } + } + if (!errorString.empty()) + { + mf->IssueMessage(cmake::FATAL_ERROR, errorString); + return; + } + + pos = 0; + lastPos = pos; + while((pos = input.find("$<TARGET_NAME:", lastPos)) != input.npos) + { + std::string::size_type nameStartPos = pos + sizeof("$<TARGET_NAME:") - 1; + std::string::size_type endPos = input.find(">", nameStartPos); + if (endPos == input.npos) + { + errorString = "$<TARGET_NAME:...> expression incomplete"; + } + const std::string targetName = input.substr(nameStartPos, + endPos - nameStartPos); + if(targetName.find("$<", lastPos) != input.npos) + { + errorString = "$<TARGET_NAME:...> requires its parameter to be a " + "literal."; + } + if (cmTarget *tgt = mf->FindTargetToUse(targetName.c_str())) + { + if(tgt->IsImported()) + { + input.replace(pos, sizeof("$<TARGET_NAME:") + targetName.size(), + targetName); + pos += sizeof("$<TARGET_NAME:") + targetName.size(); + } + else if(this->ExportedTargets.find(tgt) != this->ExportedTargets.end()) + { + input.replace(pos, sizeof("$<TARGET_NAME:") + targetName.size(), + this->Namespace + targetName); + pos += sizeof("$<TARGET_NAME:") + targetName.size(); + } + else + { + std::string namespacedTarget; + this->HandleMissingTarget(namespacedTarget, missingTargets, + mf, target, tgt); + if (!namespacedTarget.empty()) + { + input.replace(pos, sizeof("$<TARGET_NAME:") + targetName.size(), + namespacedTarget); + pos += sizeof("$<TARGET_NAME:") + targetName.size(); + } + } + } + else + { + errorString = "$<TARGET_NAME:...> requires its parameter to be a " + "reachable target."; + } + lastPos = pos; + if (!errorString.empty()) + { + break; + } + } + if (!errorString.empty()) + { + mf->IssueMessage(cmake::FATAL_ERROR, errorString); + } +} + +//---------------------------------------------------------------------------- void cmExportFileGenerator ::SetImportDetailProperties(const char* config, std::string const& suffix, diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index 4a75c52..7c58ad8 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -13,6 +13,7 @@ #define cmExportFileGenerator_h #include "cmCommand.h" +#include "cmGeneratorExpression.h" /** \class cmExportFileGenerator * \brief Generate a file exporting targets from a build or install tree. @@ -93,6 +94,17 @@ protected: cmMakefile* mf, cmTarget* depender, cmTarget* dependee) = 0; + void PopulateInterfaceProperty(const char *, + cmTarget *target, + cmGeneratorExpression::PreprocessContext, + ImportPropertyMap &properties, + std::vector<std::string> &missingTargets); + void GenerateInterfaceProperties(cmTarget *target, std::ostream& os, + const ImportPropertyMap &properties); + + void ResolveTargetsInGeneratorExpressions(std::string &input, + cmTarget* target, + std::vector<std::string> &missingTargets); // The namespace in which the exports are placed in the generated file. std::string Namespace; @@ -109,6 +121,13 @@ protected: // The set of targets included in the export. std::set<cmTarget*> ExportedTargets; + +private: + void PopulateInterfaceProperty(const char *, const char *, + cmTarget *target, + cmGeneratorExpression::PreprocessContext, + ImportPropertyMap &properties, + std::vector<std::string> &missingTargets); }; #endif diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 6ba7d9f..bc953c9 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -39,6 +39,7 @@ std::string cmExportInstallFileGenerator::GetConfigImportFileGlob() //---------------------------------------------------------------------------- bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) { + std::vector<cmTarget*> allTargets; { std::string expectedTargets; std::string sep; @@ -48,20 +49,10 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) { expectedTargets += sep + this->Namespace + (*tei)->Target->GetName(); sep = " "; - } - - this->GenerateExpectedTargetsCode(os, expectedTargets); - } - - // Create all the imported targets. - for(std::vector<cmTargetExport*>::const_iterator - tei = this->IEGen->GetExportSet()->GetTargetExports()->begin(); - tei != this->IEGen->GetExportSet()->GetTargetExports()->end(); ++tei) - { cmTargetExport const* te = *tei; if(this->ExportedTargets.insert(te->Target).second) { - this->GenerateImportTargetCode(os, te->Target); + allTargets.push_back(te->Target); } else { @@ -75,6 +66,35 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) } } + this->GenerateExpectedTargetsCode(os, expectedTargets); + } + + std::vector<std::string> missingTargets; + + // Create all the imported targets. + for(std::vector<cmTarget*>::const_iterator + tei = allTargets.begin(); + tei != allTargets.end(); ++tei) + { + cmTarget* te = *tei; + this->GenerateImportTargetCode(os, te); + + ImportPropertyMap properties; + + this->PopulateInterfaceProperty("INTERFACE_INCLUDE_DIRECTORIES", + te, + cmGeneratorExpression::InstallInterface, + properties, missingTargets); + this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", + te, + cmGeneratorExpression::InstallInterface, + properties, missingTargets); + + this->GenerateInterfaceProperties(te, os, properties); + } + + this->GenerateMissingTargetsCheckCode(os, missingTargets); + // Now load per-configuration properties for them. os << "# Load information for each installed configuration.\n" << "GET_FILENAME_COMPONENT(_DIR \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n" diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index 25b13e5..0cf9cbb 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -811,6 +811,11 @@ std::string cmExtraCodeBlocksGenerator::BuildMakeCommand( command += " VERBOSE=1 "; command += target; } + else if (strcmp(this->GlobalGenerator->GetName(), "Ninja")==0) + { + command += " -v "; + command += target; + } else { std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile); diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index 32bf941..6d003e1 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -25,55 +25,55 @@ //---------------------------------------------------------------------------- cmGeneratorExpression::cmGeneratorExpression( cmListFileBacktrace const& backtrace): - Backtrace(backtrace), CompiledExpression(0) + Backtrace(backtrace) { } //---------------------------------------------------------------------------- -const cmCompiledGeneratorExpression & +cmsys::auto_ptr<cmCompiledGeneratorExpression> cmGeneratorExpression::Parse(std::string const& input) { return this->Parse(input.c_str()); } //---------------------------------------------------------------------------- -const cmCompiledGeneratorExpression & +cmsys::auto_ptr<cmCompiledGeneratorExpression> cmGeneratorExpression::Parse(const char* input) { - cmGeneratorExpressionLexer l; - std::vector<cmGeneratorExpressionToken> tokens = l.Tokenize(input); - bool needsParsing = l.GetSawGeneratorExpression(); - std::vector<cmGeneratorExpressionEvaluator*> evaluators; - - if (needsParsing) - { - cmGeneratorExpressionParser p(tokens); - p.Parse(evaluators); - } - - delete this->CompiledExpression; - this->CompiledExpression = new cmCompiledGeneratorExpression( - this->Backtrace, - evaluators, - input, - needsParsing); - return *this->CompiledExpression; + return cmsys::auto_ptr<cmCompiledGeneratorExpression>( + new cmCompiledGeneratorExpression( + this->Backtrace, + input)); } cmGeneratorExpression::~cmGeneratorExpression() { - delete this->CompiledExpression; } //---------------------------------------------------------------------------- const char *cmCompiledGeneratorExpression::Evaluate( cmMakefile* mf, const char* config, bool quiet, - cmTarget *target, + cmTarget *headTarget, + cmGeneratorExpressionDAGChecker *dagChecker) const +{ + return this->Evaluate(mf, + config, + quiet, + headTarget, + headTarget, + dagChecker); +} + +//---------------------------------------------------------------------------- +const char *cmCompiledGeneratorExpression::Evaluate( + cmMakefile* mf, const char* config, bool quiet, + cmTarget *headTarget, + cmTarget *currentTarget, cmGeneratorExpressionDAGChecker *dagChecker) const { if (!this->NeedsParsing) { - return this->Input; + return this->Input.c_str(); } this->Output = ""; @@ -88,7 +88,8 @@ const char *cmCompiledGeneratorExpression::Evaluate( context.Config = config; context.Quiet = quiet; context.HadError = false; - context.Target = target; + context.HeadTarget = headTarget; + context.CurrentTarget = currentTarget ? currentTarget : headTarget; context.Backtrace = this->Backtrace; for ( ; it != end; ++it) @@ -108,12 +109,19 @@ const char *cmCompiledGeneratorExpression::Evaluate( cmCompiledGeneratorExpression::cmCompiledGeneratorExpression( cmListFileBacktrace const& backtrace, - const std::vector<cmGeneratorExpressionEvaluator*> &evaluators, - const char *input, bool needsParsing) - : Backtrace(backtrace), Evaluators(evaluators), Input(input), - NeedsParsing(needsParsing) + const char *input) + : Backtrace(backtrace), Input(input ? input : "") { + cmGeneratorExpressionLexer l; + std::vector<cmGeneratorExpressionToken> tokens = + l.Tokenize(this->Input.c_str()); + this->NeedsParsing = l.GetSawGeneratorExpression(); + if (this->NeedsParsing) + { + cmGeneratorExpressionParser p(tokens); + p.Parse(this->Evaluators); + } } @@ -131,15 +139,9 @@ cmCompiledGeneratorExpression::~cmCompiledGeneratorExpression() } } -std::string cmGeneratorExpression::Preprocess(const std::string &input, - PreprocessContext context) +//---------------------------------------------------------------------------- +static std::string stripAllGeneratorExpressions(const std::string &input) { - if (context != StripAllGeneratorExpressions) - { - assert(!"cmGeneratorExpression::Preprocess called with invalid args"); - return std::string(); - } - std::string result; std::string::size_type pos = 0; std::string::size_type lastPos = pos; @@ -178,3 +180,81 @@ std::string cmGeneratorExpression::Preprocess(const std::string &input, result += input.substr(lastPos); return result; } + +//---------------------------------------------------------------------------- +static std::string stripExportInterface(const std::string &input, + cmGeneratorExpression::PreprocessContext context) +{ + std::string result; + + std::string::size_type pos = 0; + std::string::size_type lastPos = pos; + while((pos = input.find("$<BUILD_INTERFACE:", lastPos)) != input.npos + || (pos = input.find("$<INSTALL_INTERFACE:", lastPos)) != input.npos) + { + result += input.substr(lastPos, pos - lastPos); + const bool gotInstallInterface = input[pos + 2] == 'I'; + pos += gotInstallInterface ? sizeof("$<INSTALL_INTERFACE:") - 1 + : sizeof("$<BUILD_INTERFACE:") - 1; + int nestingLevel = 1; + const char *c = input.c_str() + pos; + const char * const cStart = c; + for ( ; *c; ++c) + { + if(c[0] == '$' && c[1] == '<') + { + ++nestingLevel; + ++c; + continue; + } + if(c[0] == '>') + { + --nestingLevel; + if (nestingLevel != 0) + { + continue; + } + if(context == cmGeneratorExpression::BuildInterface + && !gotInstallInterface) + { + result += input.substr(pos, c - cStart); + } + else if(context == cmGeneratorExpression::InstallInterface + && gotInstallInterface) + { + result += input.substr(pos, c - cStart); + } + break; + } + } + const std::string::size_type traversed = (c - cStart) + 1; + if (!*c) + { + result += std::string(gotInstallInterface ? "$<INSTALL_INTERFACE:" + : "$<BUILD_INTERFACE:") + + input.substr(pos, traversed); + } + pos += traversed; + lastPos = pos; + } + result += input.substr(lastPos); + + return result; +} + +//---------------------------------------------------------------------------- +std::string cmGeneratorExpression::Preprocess(const std::string &input, + PreprocessContext context) +{ + if (context == StripAllGeneratorExpressions) + { + return stripAllGeneratorExpressions(input); + } + else if (context == BuildInterface || context == InstallInterface) + { + return stripExportInterface(input, context); + } + + assert(!"cmGeneratorExpression::Preprocess called with invalid args"); + return std::string(); +} diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h index ea3e7d0..dcdfefb 100644 --- a/Source/cmGeneratorExpression.h +++ b/Source/cmGeneratorExpression.h @@ -14,10 +14,12 @@ #define cmGeneratorExpression_h #include "cmStandardIncludes.h" +#include "cmListFileCache.h" #include <stack> #include <cmsys/RegularExpression.hxx> +#include <cmsys/auto_ptr.hxx> class cmTarget; class cmMakefile; @@ -44,11 +46,14 @@ public: cmGeneratorExpression(cmListFileBacktrace const& backtrace); ~cmGeneratorExpression(); - const cmCompiledGeneratorExpression& Parse(std::string const& input); - const cmCompiledGeneratorExpression& Parse(const char* input); + cmsys::auto_ptr<cmCompiledGeneratorExpression> Parse( + std::string const& input); + cmsys::auto_ptr<cmCompiledGeneratorExpression> Parse(const char* input); enum PreprocessContext { - StripAllGeneratorExpressions + StripAllGeneratorExpressions, + BuildInterface, + InstallInterface }; static std::string Preprocess(const std::string &input, @@ -59,7 +64,6 @@ private: void operator=(const cmGeneratorExpression &); cmListFileBacktrace const& Backtrace; - cmCompiledGeneratorExpression *CompiledExpression; }; class cmCompiledGeneratorExpression @@ -67,8 +71,13 @@ class cmCompiledGeneratorExpression public: const char* Evaluate(cmMakefile* mf, const char* config, bool quiet = false, - cmTarget *target = 0, + cmTarget *headTarget = 0, + cmTarget *currentTarget = 0, cmGeneratorExpressionDAGChecker *dagChecker = 0) const; + const char* Evaluate(cmMakefile* mf, const char* config, + bool quiet, + cmTarget *headTarget, + cmGeneratorExpressionDAGChecker *dagChecker) const; /** Get set of targets found during evaluations. */ std::set<cmTarget*> const& GetTargets() const @@ -76,20 +85,29 @@ public: ~cmCompiledGeneratorExpression(); + std::string GetInput() const + { + return this->Input; + } + + cmListFileBacktrace GetBacktrace() const + { + return this->Backtrace; + } + private: cmCompiledGeneratorExpression(cmListFileBacktrace const& backtrace, - const std::vector<cmGeneratorExpressionEvaluator*> &evaluators, - const char *input, bool needsParsing); + const char *input); friend class cmGeneratorExpression; cmCompiledGeneratorExpression(const cmCompiledGeneratorExpression &); void operator=(const cmCompiledGeneratorExpression &); - cmListFileBacktrace const& Backtrace; - const std::vector<cmGeneratorExpressionEvaluator*> Evaluators; - const char* const Input; - const bool NeedsParsing; + cmListFileBacktrace Backtrace; + std::vector<cmGeneratorExpressionEvaluator*> Evaluators; + const std::string Input; + bool NeedsParsing; mutable std::set<cmTarget*> Targets; mutable std::string Output; diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx index bfb0ddf..2e5b5ae 100644 --- a/Source/cmGeneratorExpressionDAGChecker.cxx +++ b/Source/cmGeneratorExpressionDAGChecker.cxx @@ -24,13 +24,14 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker( : Parent(parent), Target(target), Property(property), Content(content), Backtrace(backtrace) { - this->IsDAG = this->isDAG(); + this->CheckResult = this->checkGraph(); } //---------------------------------------------------------------------------- -bool cmGeneratorExpressionDAGChecker::check() const +cmGeneratorExpressionDAGChecker::Result +cmGeneratorExpressionDAGChecker::check() const { - return this->IsDAG; + return this->CheckResult; } //---------------------------------------------------------------------------- @@ -38,7 +39,7 @@ void cmGeneratorExpressionDAGChecker::reportError( cmGeneratorExpressionContext *context, const std::string &expr) { - if (this->IsDAG) + if (this->CheckResult == DAG) { return; } @@ -57,7 +58,7 @@ void cmGeneratorExpressionDAGChecker::reportError( e << "Error evaluating generator expression:\n" << " " << expr << "\n" << "Self reference on target \"" - << context->Target->GetName() << "\".\n"; + << context->HeadTarget->GetName() << "\".\n"; context->Makefile->GetCMakeInstance() ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(), parent->Backtrace); @@ -91,16 +92,17 @@ void cmGeneratorExpressionDAGChecker::reportError( } //---------------------------------------------------------------------------- -bool cmGeneratorExpressionDAGChecker::isDAG() const +cmGeneratorExpressionDAGChecker::Result +cmGeneratorExpressionDAGChecker::checkGraph() const { const cmGeneratorExpressionDAGChecker *parent = this->Parent; while (parent) { if (this->Target == parent->Target && this->Property == parent->Property) { - return false; + return parent->Parent ? CYCLIC_REFERENCE : SELF_REFERENCE; } parent = parent->Parent; } - return true; + return DAG; } diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h index ffc84f8..48f26ed 100644 --- a/Source/cmGeneratorExpressionDAGChecker.h +++ b/Source/cmGeneratorExpressionDAGChecker.h @@ -25,12 +25,18 @@ struct cmGeneratorExpressionDAGChecker const GeneratorExpressionContent *content, cmGeneratorExpressionDAGChecker *parent); - bool check() const; + enum Result { + DAG, + SELF_REFERENCE, + CYCLIC_REFERENCE + }; + + Result check() const; void reportError(cmGeneratorExpressionContext *context, const std::string &expr); private: - bool isDAG() const; + Result checkGraph() const; private: const cmGeneratorExpressionDAGChecker * const Parent; @@ -38,7 +44,7 @@ private: const std::string Property; const GeneratorExpressionContent * const Content; const cmListFileBacktrace Backtrace; - bool IsDAG; + Result CheckResult; }; #endif diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index 102927e..82becaf 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -18,6 +18,8 @@ #include <cmsys/String.h> +#include <assert.h> + //---------------------------------------------------------------------------- #if !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x510 static @@ -47,6 +49,8 @@ struct cmGeneratorExpressionNode virtual bool GeneratesContent() const { return true; } + virtual bool RequiresLiteralInput() const { return false; } + virtual bool AcceptsSingleArbitraryContentParameter() const { return false; } @@ -96,6 +100,12 @@ static const struct OneNode : public cmGeneratorExpressionNode } oneNode; //---------------------------------------------------------------------------- +static const struct OneNode buildInterfaceNode; + +//---------------------------------------------------------------------------- +static const struct ZeroNode installInterfaceNode; + +//---------------------------------------------------------------------------- #define BOOLEAN_OP_NODE(OPNAME, OP, SUCCESS_VALUE, FAILURE_VALUE) \ static const struct OP ## Node : public cmGeneratorExpressionNode \ { \ @@ -257,11 +267,34 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode return parameters.front().empty() ? "1" : "0"; } - return cmsysString_strcasecmp(parameters.begin()->c_str(), - context->Config) == 0 ? "1" : "0"; + if (cmsysString_strcasecmp(parameters.begin()->c_str(), + context->Config) == 0) + { + return "1"; + } + + if (context->CurrentTarget + && context->CurrentTarget->IsImported()) + { + const char* loc = 0; + const char* imp = 0; + std::string suffix; + return context->CurrentTarget->GetMappedConfig(context->Config, + &loc, + &imp, + suffix) ? "1" : "0"; + } + return "0"; } } configurationTestNode; + +//---------------------------------------------------------------------------- +static const char* targetPropertyTransitiveWhitelist[] = { + "INTERFACE_INCLUDE_DIRECTORIES" + , "INTERFACE_COMPILE_DEFINITIONS" +}; + //---------------------------------------------------------------------------- static const struct TargetPropertyNode : public cmGeneratorExpressionNode { @@ -289,8 +322,19 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode cmsys::RegularExpression propertyNameValidator; propertyNameValidator.compile("^[A-Za-z0-9_]+$"); - cmTarget* target = context->Target; + cmTarget* target = context->HeadTarget; std::string propertyName = *parameters.begin(); + + if (!target && parameters.size() == 1) + { + reportError(context, content->GetOriginalExpression(), + "$<TARGET_PROPERTY:prop> may only be used with targets. It may not " + "be used with add_custom_command. Specify the target to read a " + "property from using the $<TARGET_PROPERTY:tgt,prop> signature " + "instead."); + return std::string(); + } + if (parameters.size() == 2) { if (parameters.begin()->empty() && parameters[1].empty()) @@ -351,24 +395,75 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode return std::string(); } + assert(target); + cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace, target->GetName(), propertyName, content, dagCheckerParent); - if (!dagChecker.check()) + switch (dagChecker.check()) { + case cmGeneratorExpressionDAGChecker::SELF_REFERENCE: dagChecker.reportError(context, content->GetOriginalExpression()); return std::string(); + case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: + // No error. We just skip cyclic references. + return std::string(); + case cmGeneratorExpressionDAGChecker::DAG: + break; } const char *prop = target->GetProperty(propertyName.c_str()); - return prop ? prop : ""; + if (!prop) + { + return std::string(); + } + + for (size_t i = 0; + i < (sizeof(targetPropertyTransitiveWhitelist) / + sizeof(*targetPropertyTransitiveWhitelist)); + ++i) + { + if (targetPropertyTransitiveWhitelist[i] == propertyName) + { + cmGeneratorExpression ge(context->Backtrace); + return ge.Parse(prop)->Evaluate(context->Makefile, + context->Config, + context->Quiet, + context->HeadTarget, + target, + &dagChecker); + } + } + return prop; } } targetPropertyNode; //---------------------------------------------------------------------------- +static const struct TargetNameNode : public cmGeneratorExpressionNode +{ + TargetNameNode() {} + + virtual bool GeneratesContent() const { return true; } + + virtual bool AcceptsSingleArbitraryContentParameter() const { return true; } + virtual bool RequiresLiteralInput() const { return true; } + + std::string Evaluate(const std::vector<std::string> ¶meters, + cmGeneratorExpressionContext *, + const GeneratorExpressionContent *, + cmGeneratorExpressionDAGChecker *) const + { + return parameters.front(); + } + + virtual int NumExpectedParameters() const { return 1; } + +} targetNameNode; + +//---------------------------------------------------------------------------- template<bool linker, bool soname> struct TargetFilesystemArtifactResultCreator { @@ -553,13 +648,13 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier) { if (identifier == "0") return &zeroNode; - if (identifier == "1") + else if (identifier == "1") return &oneNode; - if (identifier == "AND") + else if (identifier == "AND") return &andNode; - if (identifier == "OR") + else if (identifier == "OR") return &orNode; - if (identifier == "NOT") + else if (identifier == "NOT") return ¬Node; else if (identifier == "CONFIGURATION") return &configurationNode; @@ -593,6 +688,12 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier) return &commaNode; else if (identifier == "TARGET_PROPERTY") return &targetPropertyNode; + else if (identifier == "TARGET_NAME") + return &targetNameNode; + else if (identifier == "BUILD_INTERFACE") + return &buildInterfaceNode; + else if (identifier == "INSTALL_INTERFACE") + return &installInterfaceNode; return 0; } @@ -682,6 +783,15 @@ std::string GeneratorExpressionContent::Evaluate( = pit->end(); for ( ; it != end; ++it) { + if (node->RequiresLiteralInput()) + { + if ((*it)->GetType() != cmGeneratorExpressionEvaluator::Text) + { + reportError(context, this->GetOriginalExpression(), + "$<" + identifier + "> expression requires literal input."); + return std::string(); + } + } result += (*it)->Evaluate(context, dagChecker); if (context->HadError) { @@ -689,6 +799,12 @@ std::string GeneratorExpressionContent::Evaluate( } } } + if (node->RequiresLiteralInput()) + { + std::vector<std::string> parameters; + parameters.push_back(result); + return node->Evaluate(parameters, context, this, dagChecker); + } return result; } diff --git a/Source/cmGeneratorExpressionEvaluator.h b/Source/cmGeneratorExpressionEvaluator.h index d904b02..59804ff 100644 --- a/Source/cmGeneratorExpressionEvaluator.h +++ b/Source/cmGeneratorExpressionEvaluator.h @@ -26,7 +26,9 @@ struct cmGeneratorExpressionContext std::set<cmTarget*> Targets; cmMakefile *Makefile; const char *Config; - cmTarget *Target; + cmTarget *HeadTarget; // The target whose property is being evaluated. + cmTarget *CurrentTarget; // The dependent of HeadTarget which appears + // directly or indirectly in the property. bool Quiet; bool HadError; }; diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index de8b5e3..62ee26a 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -252,45 +252,7 @@ const char* cmGeneratorTarget::GetCreateRuleVariable() std::vector<std::string> cmGeneratorTarget::GetIncludeDirectories( const char *config) { - std::vector<std::string> includes; - const char *prop = this->Target->GetProperty("INCLUDE_DIRECTORIES"); - if(!prop) - { - return includes; - } - - cmListFileBacktrace lfbt; - cmGeneratorExpression ge(lfbt); - - cmGeneratorExpressionDAGChecker dagChecker(lfbt, - this->GetName(), - "INCLUDE_DIRECTORIES", 0, 0); - - cmSystemTools::ExpandListArgument(ge.Parse(prop) - .Evaluate(this->Makefile, - config, - false, - this->Target, - &dagChecker), - includes); - - std::set<std::string> uniqueIncludes; - std::vector<std::string> orderedAndUniqueIncludes; - for(std::vector<std::string>::const_iterator - li = includes.begin(); li != includes.end(); ++li) - { - std::string inc = *li; - if (!cmSystemTools::IsOff(inc.c_str())) - { - cmSystemTools::ConvertToUnixSlashes(inc); - } - if(uniqueIncludes.insert(inc).second) - { - orderedAndUniqueIncludes.push_back(inc); - } - } - - return orderedAndUniqueIncludes; + return this->Target->GetIncludeDirectories(config); } //---------------------------------------------------------------------------- @@ -315,7 +277,7 @@ std::string cmGeneratorTarget::GetCompileDefinitions(const char *config) cmGeneratorExpressionDAGChecker dagChecker(lfbt, this->GetName(), defPropName, 0, 0); - return ge.Parse(prop).Evaluate(this->Makefile, + return ge.Parse(prop)->Evaluate(this->Makefile, config, false, this->Target, diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index d943c45..b432986 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -1485,9 +1485,12 @@ void cmMakefile::InitializeFromParent() // Initialize definitions with the closure of the parent scope. this->Internal->VarStack.top() = parent->Internal->VarStack.top().Closure(); - // copy include paths - this->SetProperty("INCLUDE_DIRECTORIES", - parent->GetProperty("INCLUDE_DIRECTORIES")); + const std::vector<IncludeDirectoriesEntry> parentIncludes = + parent->GetIncludeDirectoriesEntries(); + this->IncludeDirectoriesEntries.insert(this->IncludeDirectoriesEntries.end(), + parentIncludes.begin(), + parentIncludes.end()); + this->SystemIncludeDirectories = parent->SystemIncludeDirectories; // define flags @@ -1613,41 +1616,6 @@ void cmMakefile::AddSubDirectory(const char* srcPath, const char *binPath, } //---------------------------------------------------------------------------- -void AddStringToProperty(cmProperty *prop, const char* name, const char* s, - bool before) -{ - if (!prop) - { - return; - } - - // Don't worry about duplicates at this point. We eliminate them when - // we convert the property to a vector in GetIncludeDirectories. - - if (before) - { - const char *val = prop->GetValue(); - cmOStringStream oss; - - if(val && *val) - { - oss << s << ";" << val; - } - else - { - oss << s; - } - - std::string newVal = oss.str(); - prop->Set(name, newVal.c_str()); - } - else - { - prop->Append(name, s); - } -} - -//---------------------------------------------------------------------------- void cmMakefile::AddIncludeDirectory(const char* inc, bool before) { if (!inc) @@ -1655,18 +1623,21 @@ void cmMakefile::AddIncludeDirectory(const char* inc, bool before) return; } - // Directory property: - cmProperty *prop = - this->GetProperties().GetOrCreateProperty("INCLUDE_DIRECTORIES"); - AddStringToProperty(prop, "INCLUDE_DIRECTORIES", inc, before); + std::vector<IncludeDirectoriesEntry>::iterator position = + before ? this->IncludeDirectoriesEntries.begin() + : this->IncludeDirectoriesEntries.end(); + + cmListFileBacktrace lfbt; + this->GetBacktrace(lfbt); + IncludeDirectoriesEntry entry(inc, lfbt); + this->IncludeDirectoriesEntries.insert(position, entry); // Property on each target: for (cmTargets::iterator l = this->Targets.begin(); l != this->Targets.end(); ++l) { cmTarget &t = l->second; - prop = t.GetProperties().GetOrCreateProperty("INCLUDE_DIRECTORIES"); - AddStringToProperty(prop, "INCLUDE_DIRECTORIES", inc, before); + t.InsertInclude(entry, before); } } @@ -3451,6 +3422,15 @@ void cmMakefile::SetProperty(const char* prop, const char* value) this->SetLinkDirectories(varArgsExpanded); return; } + if (propname == "INCLUDE_DIRECTORIES") + { + this->IncludeDirectoriesEntries.clear(); + cmListFileBacktrace lfbt; + this->GetBacktrace(lfbt); + this->IncludeDirectoriesEntries.push_back( + IncludeDirectoriesEntry(value, lfbt)); + return; + } if ( propname == "INCLUDE_REGULAR_EXPRESSION" ) { @@ -3482,6 +3462,14 @@ void cmMakefile::AppendProperty(const char* prop, const char* value, // handle special props std::string propname = prop; + if (propname == "INCLUDE_DIRECTORIES") + { + cmListFileBacktrace lfbt; + this->GetBacktrace(lfbt); + this->IncludeDirectoriesEntries.push_back( + IncludeDirectoriesEntry(value, lfbt)); + return; + } if ( propname == "LINK_DIRECTORIES" ) { std::vector<std::string> varArgsExpanded; @@ -3593,6 +3581,20 @@ const char *cmMakefile::GetProperty(const char* prop, output = str.str(); return output.c_str(); } + else if (!strcmp("INCLUDE_DIRECTORIES",prop)) + { + std::string sep; + for (std::vector<IncludeDirectoriesEntry>::const_iterator + it = this->IncludeDirectoriesEntries.begin(), + end = this->IncludeDirectoriesEntries.end(); + it != end; ++it) + { + output += sep; + output += it->Value; + sep = ";"; + } + return output.c_str(); + } bool chain = false; const char *retVal = diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index eff05d0..a85015f 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -22,6 +22,7 @@ #include "cmNewLineStyle.h" #include "cmGeneratorTarget.h" #include "cmake.h" +#include "cmMakefileIncludeDirectoriesEntry.h" #if defined(CMAKE_BUILD_WITH_CMAKE) #include "cmSourceGroup.h" @@ -861,6 +862,13 @@ public: /** Set whether or not to report a CMP0000 violation. */ void SetCheckCMP0000(bool b) { this->CheckCMP0000 = b; } + typedef cmMakefileIncludeDirectoriesEntry IncludeDirectoriesEntry; + + std::vector<IncludeDirectoriesEntry> GetIncludeDirectoriesEntries() const + { + return this->IncludeDirectoriesEntries; + } + protected: // add link libraries and directories to the target void AddGlobalLinkInformation(const char* name, cmTarget& target); @@ -909,6 +917,8 @@ protected: std::vector<std::string> HeaderFileExtensions; std::string DefineFlags; + std::vector<IncludeDirectoriesEntry> IncludeDirectoriesEntries; + // Track the value of the computed DEFINITIONS property. void AddDefineFlag(const char*, std::string&); void RemoveDefineFlag(const char*, std::string::size_type, std::string&); diff --git a/Source/cmMakefileIncludeDirectoriesEntry.h b/Source/cmMakefileIncludeDirectoriesEntry.h new file mode 100644 index 0000000..f35642d --- /dev/null +++ b/Source/cmMakefileIncludeDirectoriesEntry.h @@ -0,0 +1,28 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2012 Stephen Kelly <steveire@gmail.com> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmMakefileIncludeDirectoriesEntry_h +#define cmMakefileIncludeDirectoriesEntry_h + +#include <string> +#include "cmListFileCache.h" + +struct cmMakefileIncludeDirectoriesEntry { + cmMakefileIncludeDirectoriesEntry(const std::string &value, + const cmListFileBacktrace &bt) + : Value(value), Backtrace(bt) + {} + std::string Value; + cmListFileBacktrace Backtrace; +}; + +#endif diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index de3b23c..ca53a39 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -21,6 +21,7 @@ #include "cmDocumentLocationUndefined.h" #include "cmListFileCache.h" #include "cmGeneratorExpression.h" +#include "cmGeneratorExpressionDAGChecker.h" #include <cmsys/RegularExpression.hxx> #include <map> #include <set> @@ -118,6 +119,14 @@ public: struct SourceEntry { std::vector<cmSourceFile*> Depends; }; typedef std::map<cmSourceFile*, SourceEntry> SourceEntriesType; SourceEntriesType SourceEntries; + + struct IncludeDirectoriesEntry { + IncludeDirectoriesEntry(cmsys::auto_ptr<cmCompiledGeneratorExpression> cge) + : ge(cge) + {} + const cmsys::auto_ptr<cmCompiledGeneratorExpression> ge; + }; + std::vector<IncludeDirectoriesEntry*> IncludeDirectoriesEntries; }; //---------------------------------------------------------------------------- @@ -711,6 +720,28 @@ void cmTarget::DefineProperties(cmake *cm) "for the named configuration."); cm->DefineProperty + ("INTERFACE_INCLUDE_DIRECTORIES", cmProperty::TARGET, + "List of public include directories for a library.", + "Targets may populate this property to publish the include directories " + "required to compile against the headers for the target. Consuming " + "targets can add entries to their own INCLUDE_DIRECTORIES property such " + "as $<TARGET_PROPERTY:foo,INTERFACE_INCLUDE_DIRECTORIES> to use the " + "include directories specified in the interface of 'foo'." + "\n" + CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS); + + cm->DefineProperty + ("INTERFACE_COMPILE_DEFINITIONS", cmProperty::TARGET, + "List of public compile definitions for a library.", + "Targets may populate this property to publish the compile definitions " + "required to compile against the headers for the target. Consuming " + "targets can add entries to their own COMPILE_DEFINITIONS property such " + "as $<TARGET_PROPERTY:foo,INTERFACE_COMPILE_DEFINITIONS> to use the " + "compile definitions specified in the interface of 'foo'." + "\n" + CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS); + + cm->DefineProperty ("LINK_INTERFACE_MULTIPLICITY", cmProperty::TARGET, "Repetition count for STATIC libraries with cyclic dependencies.", "When linking to a STATIC library target with cyclic dependencies the " @@ -1392,8 +1423,14 @@ void cmTarget::SetMakefile(cmMakefile* mf) // Initialize the INCLUDE_DIRECTORIES property based on the current value // of the same directory property: - this->SetProperty("INCLUDE_DIRECTORIES", - this->Makefile->GetProperty("INCLUDE_DIRECTORIES")); + const std::vector<cmMakefileIncludeDirectoriesEntry> parentIncludes = + this->Makefile->GetIncludeDirectoriesEntries(); + + for (std::vector<cmMakefileIncludeDirectoriesEntry>::const_iterator it + = parentIncludes.begin(); it != parentIncludes.end(); ++it) + { + this->InsertInclude(*it); + } if(this->TargetTypeValue == cmTarget::SHARED_LIBRARY || this->TargetTypeValue == cmTarget::MODULE_LIBRARY) @@ -1728,9 +1765,10 @@ cmTargetTraceDependencies for(cmCustomCommandLine::const_iterator cli = cit->begin(); cli != cit->end(); ++cli) { - const cmCompiledGeneratorExpression &cge = ge.Parse(*cli); - cge.Evaluate(this->Makefile, 0, true); - std::set<cmTarget*> geTargets = cge.GetTargets(); + const cmsys::auto_ptr<cmCompiledGeneratorExpression> cge + = ge.Parse(*cli); + cge->Evaluate(this->Makefile, 0, true); + std::set<cmTarget*> geTargets = cge->GetTargets(); for(std::set<cmTarget*>::const_iterator it = geTargets.begin(); it != geTargets.end(); ++it) { @@ -2445,6 +2483,20 @@ void cmTarget::GatherDependencies( const cmMakefile& mf, } //---------------------------------------------------------------------------- +void deleteAndClear( + std::vector<cmTargetInternals::IncludeDirectoriesEntry*> &entries) +{ + for (std::vector<cmTargetInternals::IncludeDirectoriesEntry*>::const_iterator + it = entries.begin(), + end = entries.end(); + it != end; ++it) + { + delete *it; + } + entries.clear(); +} + +//---------------------------------------------------------------------------- void cmTarget::SetProperty(const char* prop, const char* value) { if (!prop) @@ -2452,6 +2504,17 @@ void cmTarget::SetProperty(const char* prop, const char* value) return; } + if(strcmp(prop,"INCLUDE_DIRECTORIES") == 0) + { + cmListFileBacktrace lfbt; + this->Makefile->GetBacktrace(lfbt); + cmGeneratorExpression ge(lfbt); + deleteAndClear(this->Internal->IncludeDirectoriesEntries); + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value); + this->Internal->IncludeDirectoriesEntries.push_back( + new cmTargetInternals::IncludeDirectoriesEntry(cge)); + return; + } this->Properties.SetProperty(prop, value, cmProperty::TARGET); this->MaybeInvalidatePropertyCache(prop); } @@ -2464,11 +2527,100 @@ void cmTarget::AppendProperty(const char* prop, const char* value, { return; } + if(strcmp(prop,"INCLUDE_DIRECTORIES") == 0) + { + cmListFileBacktrace lfbt; + this->Makefile->GetBacktrace(lfbt); + cmGeneratorExpression ge(lfbt); + this->Internal->IncludeDirectoriesEntries.push_back( + new cmTargetInternals::IncludeDirectoriesEntry(ge.Parse(value))); + return; + } this->Properties.AppendProperty(prop, value, cmProperty::TARGET, asString); this->MaybeInvalidatePropertyCache(prop); } //---------------------------------------------------------------------------- +void cmTarget::InsertInclude(const cmMakefileIncludeDirectoriesEntry &entry, + bool before) +{ + cmGeneratorExpression ge(entry.Backtrace); + + std::vector<cmTargetInternals::IncludeDirectoriesEntry*>::iterator position + = before ? this->Internal->IncludeDirectoriesEntries.begin() + : this->Internal->IncludeDirectoriesEntries.end(); + + this->Internal->IncludeDirectoriesEntries.insert(position, + new cmTargetInternals::IncludeDirectoriesEntry(ge.Parse(entry.Value))); +} + +//---------------------------------------------------------------------------- +std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config) +{ + std::vector<std::string> includes; + std::set<std::string> uniqueIncludes; + cmListFileBacktrace lfbt; + + cmGeneratorExpressionDAGChecker dagChecker(lfbt, + this->GetName(), + "INCLUDE_DIRECTORIES", 0, 0); + + + std::vector<std::string> debugProperties; + const char *debugProp = + this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES"); + if (debugProp) + { + cmSystemTools::ExpandListArgument(debugProp, debugProperties); + } + + bool debugIncludes = std::find(debugProperties.begin(), + debugProperties.end(), + "INCLUDE_DIRECTORIES") + != debugProperties.end(); + + for (std::vector<cmTargetInternals::IncludeDirectoriesEntry*>::const_iterator + it = this->Internal->IncludeDirectoriesEntries.begin(), + end = this->Internal->IncludeDirectoriesEntries.end(); + it != end; ++it) + { + std::vector<std::string> entryIncludes; + cmSystemTools::ExpandListArgument((*it)->ge->Evaluate(this->Makefile, + config, + false, + this, + &dagChecker), + entryIncludes); + std::string usedIncludes; + for(std::vector<std::string>::const_iterator + li = entryIncludes.begin(); li != entryIncludes.end(); ++li) + { + std::string inc = *li; + if (!cmSystemTools::IsOff(inc.c_str())) + { + cmSystemTools::ConvertToUnixSlashes(inc); + } + + if(uniqueIncludes.insert(inc).second) + { + includes.push_back(*li); + if (debugIncludes) + { + usedIncludes += " * " + *li + "\n"; + } + } + } + if (!usedIncludes.empty()) + { + this->Makefile->GetCMakeInstance()->IssueMessage(cmake::LOG, + "Used includes:\n" + usedIncludes, + (*it)->ge->GetBacktrace()); + } + } + return includes; +} + +//---------------------------------------------------------------------------- void cmTarget::MaybeInvalidatePropertyCache(const char* prop) { // Wipe out maps caching information affected by this property. @@ -2795,6 +2947,24 @@ const char *cmTarget::GetProperty(const char* prop, } } } + if(strcmp(prop,"INCLUDE_DIRECTORIES") == 0) + { + static std::string output; + output = ""; + std::string sep; + typedef cmTargetInternals::IncludeDirectoriesEntry + IncludeDirectoriesEntry; + for (std::vector<IncludeDirectoriesEntry*>::const_iterator + it = this->Internal->IncludeDirectoriesEntries.begin(), + end = this->Internal->IncludeDirectoriesEntries.end(); + it != end; ++it) + { + output += sep; + output += (*it)->ge->GetInput(); + sep = ";"; + } + return output.c_str(); + } if (strcmp(prop,"IMPORTED") == 0) { @@ -4217,27 +4387,15 @@ cmTarget::GetImportInfo(const char* config) return &i->second; } -//---------------------------------------------------------------------------- -void cmTarget::ComputeImportInfo(std::string const& desired_config, - ImportInfo& info) +bool cmTarget::GetMappedConfig(std::string const& desired_config, + const char** loc, + const char** imp, + std::string& suffix) { - // This method finds information about an imported target from its - // properties. The "IMPORTED_" namespace is reserved for properties - // defined by the project exporting the target. - - // Initialize members. - info.NoSOName = false; - // Track the configuration-specific property suffix. - std::string suffix = "_"; + suffix = "_"; suffix += desired_config; - // On a DLL platform there may be only IMPORTED_IMPLIB for a shared - // library or an executable with exports. - bool allowImp = this->HasImportLibrary(); - - // Look for a mapping from the current project's configuration to - // the imported project's configuration. std::vector<std::string> mappedConfigs; { std::string mapProp = "MAP_IMPORTED_CONFIG_"; @@ -4248,26 +4406,29 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config, } } + // If we needed to find one of the mapped configurations but did not + // On a DLL platform there may be only IMPORTED_IMPLIB for a shared + // library or an executable with exports. + bool allowImp = this->HasImportLibrary(); + // If a mapping was found, check its configurations. - const char* loc = 0; - const char* imp = 0; for(std::vector<std::string>::const_iterator mci = mappedConfigs.begin(); - !loc && !imp && mci != mappedConfigs.end(); ++mci) + !*loc && !*imp && mci != mappedConfigs.end(); ++mci) { // Look for this configuration. std::string mcUpper = cmSystemTools::UpperCase(mci->c_str()); std::string locProp = "IMPORTED_LOCATION_"; locProp += mcUpper; - loc = this->GetProperty(locProp.c_str()); + *loc = this->GetProperty(locProp.c_str()); if(allowImp) { std::string impProp = "IMPORTED_IMPLIB_"; impProp += mcUpper; - imp = this->GetProperty(impProp.c_str()); + *imp = this->GetProperty(impProp.c_str()); } // If it was found, use it for all properties below. - if(loc || imp) + if(*loc || *imp) { suffix = "_"; suffix += mcUpper; @@ -4277,45 +4438,45 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config, // If we needed to find one of the mapped configurations but did not // then the target is not found. The project does not want any // other configuration. - if(!mappedConfigs.empty() && !loc && !imp) + if(!mappedConfigs.empty() && !*loc && !*imp) { - return; + return false; } // If we have not yet found it then there are no mapped // configurations. Look for an exact-match. - if(!loc && !imp) + if(!*loc && !*imp) { std::string locProp = "IMPORTED_LOCATION"; locProp += suffix; - loc = this->GetProperty(locProp.c_str()); + *loc = this->GetProperty(locProp.c_str()); if(allowImp) { std::string impProp = "IMPORTED_IMPLIB"; impProp += suffix; - imp = this->GetProperty(impProp.c_str()); + *imp = this->GetProperty(impProp.c_str()); } } // If we have not yet found it then there are no mapped // configurations and no exact match. - if(!loc && !imp) + if(!*loc && !*imp) { // The suffix computed above is not useful. suffix = ""; // Look for a configuration-less location. This may be set by // manually-written code. - loc = this->GetProperty("IMPORTED_LOCATION"); + *loc = this->GetProperty("IMPORTED_LOCATION"); if(allowImp) { - imp = this->GetProperty("IMPORTED_IMPLIB"); + *imp = this->GetProperty("IMPORTED_IMPLIB"); } } // If we have not yet found it then the project is willing to try // any available configuration. - if(!loc && !imp) + if(!*loc && !*imp) { std::vector<std::string> availableConfigs; if(const char* iconfigs = this->GetProperty("IMPORTED_CONFIGURATIONS")) @@ -4324,24 +4485,45 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config, } for(std::vector<std::string>::const_iterator aci = availableConfigs.begin(); - !loc && !imp && aci != availableConfigs.end(); ++aci) + !*loc && !*imp && aci != availableConfigs.end(); ++aci) { suffix = "_"; suffix += cmSystemTools::UpperCase(*aci); std::string locProp = "IMPORTED_LOCATION"; locProp += suffix; - loc = this->GetProperty(locProp.c_str()); + *loc = this->GetProperty(locProp.c_str()); if(allowImp) { std::string impProp = "IMPORTED_IMPLIB"; impProp += suffix; - imp = this->GetProperty(impProp.c_str()); + *imp = this->GetProperty(impProp.c_str()); } } } - // If we have not yet found it then the target is not available. - if(!loc && !imp) + if(!*loc && !*imp) + { + return false; + } + + return true; +} + +//---------------------------------------------------------------------------- +void cmTarget::ComputeImportInfo(std::string const& desired_config, + ImportInfo& info) +{ + // This method finds information about an imported target from its + // properties. The "IMPORTED_" namespace is reserved for properties + // defined by the project exporting the target. + + // Initialize members. + info.NoSOName = false; + + const char* loc = 0; + const char* imp = 0; + std::string suffix; + if (!this->GetMappedConfig(desired_config, &loc, &imp, suffix)) { return; } @@ -4918,6 +5100,7 @@ cmTargetInternalPointer //---------------------------------------------------------------------------- cmTargetInternalPointer::~cmTargetInternalPointer() { + deleteAndClear(this->Pointer->IncludeDirectoriesEntries); delete this->Pointer; } diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 0dfbc68..52d5ca6 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -15,6 +15,7 @@ #include "cmCustomCommand.h" #include "cmPropertyMap.h" #include "cmPolicies.h" +#include "cmMakefileIncludeDirectoriesEntry.h" #include <cmsys/auto_ptr.hxx> @@ -403,6 +404,11 @@ public: // Get the properties cmPropertyMap &GetProperties() { return this->Properties; }; + bool GetMappedConfig(std::string const& desired_config, + const char** loc, + const char** imp, + std::string& suffix); + // Define the properties static void DefineProperties(cmake *cm); @@ -470,6 +476,9 @@ public: /** @return the Mac framework directory without the base. */ std::string GetFrameworkDirectory(const char* config = 0); + std::vector<std::string> GetIncludeDirectories(const char *config); + void InsertInclude(const cmMakefileIncludeDirectoriesEntry &entry, + bool before = false); private: /** * A list of direct dependencies. Use in conjunction with DependencyMap. diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx index 2f650e7..42f511e 100644 --- a/Source/cmTestGenerator.cxx +++ b/Source/cmTestGenerator.cxx @@ -112,7 +112,7 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os, else { // Use the command name given. - exe = ge.Parse(exe.c_str()).Evaluate(mf, config); + exe = ge.Parse(exe.c_str())->Evaluate(mf, config); cmSystemTools::ConvertToUnixSlashes(exe); } @@ -122,7 +122,7 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os, for(std::vector<std::string>::const_iterator ci = command.begin()+1; ci != command.end(); ++ci) { - os << " " << lg->EscapeForCMake(ge.Parse(*ci).Evaluate(mf, config)); + os << " " << lg->EscapeForCMake(ge.Parse(*ci)->Evaluate(mf, config)); } // Finish the test command. diff --git a/Source/cmake.cxx b/Source/cmake.cxx index fba4860..a44c825 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -953,7 +953,7 @@ int cmake::AddCMakePaths() cMakeSelf = cmSystemTools::GetRealPath(cMakeSelf.c_str()); cMakeSelf += "/cmake"; cMakeSelf += cmSystemTools::GetExecutableExtension(); -#if __APPLE__ +#ifdef __APPLE__ // on the apple this might be the gui bundle if(!cmSystemTools::FileExists(cMakeSelf.c_str())) { diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index 777d76f..ccdff12 100644 --- a/Source/kwsys/CMakeLists.txt +++ b/Source/kwsys/CMakeLists.txt @@ -116,7 +116,6 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) SET(KWSYS_USE_MD5 1) SET(KWSYS_USE_Process 1) SET(KWSYS_USE_RegularExpression 1) - SET(KWSYS_USE_Registry 1) SET(KWSYS_USE_System 1) SET(KWSYS_USE_SystemTools 1) SET(KWSYS_USE_CommandLineArguments 1) @@ -762,7 +761,7 @@ SET(KWSYS_HXX_FILES Configure String # Add selected C++ classes. SET(cppclasses Directory DynamicLoader Glob RegularExpression SystemTools - CommandLineArguments Registry IOStream SystemInformation + CommandLineArguments IOStream SystemInformation ) FOREACH(cpp ${cppclasses}) IF(KWSYS_USE_${cpp}) @@ -800,12 +799,8 @@ SET(KWSYS_CXX_SRCS) # Add the proper sources for this platform's Process implementation. IF(KWSYS_USE_Process) IF(NOT UNIX) - # Use the Windows implementation. We need the encoded forwarding executable. - SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessWin32.c - ${PROJECT_BINARY_DIR}/${KWSYS_NAMESPACE}ProcessFwd9xEnc.c) - SET_SOURCE_FILES_PROPERTIES( - ${PROJECT_BINARY_DIR}/${KWSYS_NAMESPACE}ProcessFwd9xEnc.c - PROPERTIES GENERATED 1) + # Use the Windows implementation. + SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessWin32.c) ELSE(NOT UNIX) # Use the UNIX implementation. SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessUNIX.c) @@ -938,43 +933,6 @@ IF(KWSYS_USE_String) ENDIF(KWSYS_USE_String) #----------------------------------------------------------------------------- -# Process execution on windows needs to build a forwarding executable -# that works around a Win9x bug. We encode the executable into a C -# file and build it into the library. Win9x platforms reproduce the -# executable into a temporary directory when it is needed. -IF(KWSYS_USE_Process) - IF(NOT UNIX) - # Build the forwarding executable itself and a program that will - # encode it into a C file. - ADD_EXECUTABLE(${KWSYS_NAMESPACE}ProcessFwd9x ProcessFwd9x.c) - ADD_EXECUTABLE(${KWSYS_NAMESPACE}EncodeExecutable EncodeExecutable.c) - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}ProcessFwd9x PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}EncodeExecutable PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}ProcessFwd9x PROPERTY LABELS ${KWSYS_LABELS_EXE}) - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}EncodeExecutable PROPERTY LABELS ${KWSYS_LABELS_EXE}) - - SET(CFG_INTDIR "/${CMAKE_CFG_INTDIR}") - IF(CMAKE_BUILD_TOOL MATCHES "make") - SET(CFG_INTDIR "") - ENDIF(CMAKE_BUILD_TOOL MATCHES "make") - - # Take advantage of a better custom command syntax if possible. - SET(CMD ${CMAKE_CURRENT_BINARY_DIR}${CFG_INTDIR}/${KWSYS_NAMESPACE}EncodeExecutable.exe) - SET(FWD ${CMAKE_CURRENT_BINARY_DIR}${CFG_INTDIR}/${KWSYS_NAMESPACE}ProcessFwd9x.exe) - ADD_CUSTOM_COMMAND( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${KWSYS_NAMESPACE}ProcessFwd9xEnc.c - COMMAND ${CMD} - ARGS ${FWD} ${CMAKE_CURRENT_BINARY_DIR}/${KWSYS_NAMESPACE}ProcessFwd9xEnc.c - ${KWSYS_NAMESPACE} ProcessFwd9x - DEPENDS ${CMD} ${FWD}) - - # Make sure build occurs in proper order. - ADD_DEPENDENCIES(${KWSYS_NAMESPACE} ${KWSYS_NAMESPACE}ProcessFwd9x - ${KWSYS_NAMESPACE}EncodeExecutable) - ENDIF(NOT UNIX) -ENDIF(KWSYS_USE_Process) - -#----------------------------------------------------------------------------- # Setup testing if not being built as part of another project. IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) IF(BUILD_TESTING) @@ -1012,7 +970,6 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) ) ENDIF(NOT WATCOM) SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} - testRegistry testIOS testSystemTools testCommandLineArguments @@ -1116,8 +1073,6 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) # We expect test to fail SET_TESTS_PROPERTIES(kwsys.testFail PROPERTIES WILL_FAIL ON) GET_TEST_PROPERTY(kwsys.testFail WILL_FAIL wfv) - SET_TESTS_PROPERTIES(kwsys.testRegistry PROPERTIES FAIL_REGULAR_EXPRESSION "ERROR_NOT_VALGRIND;FAIL;Test failed") - SET_TESTS_PROPERTIES(kwsys.testRegistry PROPERTIES PASS_REGULAR_EXPRESSION "Test passed") SET_TESTS_PROPERTIES(kwsys.testFail PROPERTIES MEASUREMENT "Some Key=Some Value") MESSAGE(STATUS "GET_TEST_PROPERTY returned: ${wfv}") ENDIF() diff --git a/Source/kwsys/CPU.h.in b/Source/kwsys/CPU.h.in index ecd29d1..2e1a584 100644 --- a/Source/kwsys/CPU.h.in +++ b/Source/kwsys/CPU.h.in @@ -98,6 +98,14 @@ #elif defined(__SYSC_ZARCH__) # define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_BIG +/* Aarch64 */ +#elif defined(__aarch64__) +# if !defined(__AARCH64EB__) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_LITTLE +# else +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_BIG +# endif + /* Unknown CPU */ #else # define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID 0 diff --git a/Source/kwsys/EncodeExecutable.c b/Source/kwsys/EncodeExecutable.c deleted file mode 100644 index bc30568..0000000 --- a/Source/kwsys/EncodeExecutable.c +++ /dev/null @@ -1,114 +0,0 @@ -/*============================================================================ - KWSys - Kitware System Library - Copyright 2000-2009 Kitware, Inc., Insight Software Consortium - - Distributed under the OSI-approved BSD License (the "License"); - see accompanying file Copyright.txt for details. - - This software is distributed WITHOUT ANY WARRANTY; without even the - implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the License for more information. -============================================================================*/ -#include <stdio.h> -#ifdef __WATCOMC__ -#define _unlink unlink -#endif -int main(int argc, char* argv[]) -{ - FILE* ifp; - FILE* ofp; - int i; - int n; - int count = 0; - unsigned char buffer[1024]; - - /* Check arguments. */ - if(argc != 5) - { - fprintf(stderr, "Usage: %s <input> <output> <kwsys-name> <array>\n", - argv[0]); - return 1; - } - - /* Open the input file. */ - ifp = fopen(argv[1], "rb"); - if(!ifp) - { - fprintf(stderr, "Cannot open input file: \"%s\"\n", argv[1]); - return 2; - } - ofp = fopen(argv[2], "w"); - if(!ofp) - { - fprintf(stderr, "Cannot open output file: \"%s\"\n", argv[2]); - fclose(ifp); - return 2; - } - - /* Prepend header comment. */ - fprintf(ofp, "/*\n * DO NOT EDIT\n * This file is generated by:\n"); - fprintf(ofp, " * %s\n */\n\n", argv[0]); - fprintf(ofp, "#include \"kwsysPrivate.h\"\n"); - fprintf(ofp, "#include KWSYS_HEADER(Configure.h)\n\n"); - fprintf(ofp, "#include <stdio.h>\n\n"); - fprintf(ofp, "#if defined(_WIN32)\n"); - fprintf(ofp, "# include <io.h>\n"); - fprintf(ofp, "#else\n"); - fprintf(ofp, "# include <unistd.h>\n"); - fprintf(ofp, "#endif\n"); - fprintf(ofp, "\n"); - fprintf(ofp, "static void kwsys_unlink(const char* fname)\n"); - fprintf(ofp, "{\n"); - fprintf(ofp, "#if defined(__WATCOMC__)\n"); - fprintf(ofp, " unlink(fname);\n"); - fprintf(ofp, "#else\n"); - fprintf(ofp, " _unlink(fname);\n"); - fprintf(ofp, "#endif\n"); - fprintf(ofp, "}\n"); - fprintf(ofp, "\n"); - - /* Split file up in 1024-byte chunks. */ - while((n = (int)fread(buffer, 1, 1024, ifp)) > 0) - { - fprintf(ofp, "static unsigned char kwsysEncodedArray%s_%d[%d] = {\n", - argv[4], count++, n); - for(i=0; i < n-1; ++i) - { - fprintf(ofp, "0x%02X", buffer[i]); - if(i%10 == 9) - { - fprintf(ofp, ",\n"); - } - else - { - fprintf(ofp, ", "); - } - } - fprintf(ofp, "0x%02X};\n\n", buffer[n-1]); - } - fclose(ifp); - - /* Provide a function to write the data to a file. */ - fprintf(ofp, "extern %s_EXPORT int %sEncodedWriteArray%s(const char* fname)\n", - argv[3], argv[3], argv[4]); - fprintf(ofp, "{\n"); - fprintf(ofp, " FILE* ofp = fopen(fname, \"wb\");\n"); - fprintf(ofp, " if(!ofp) { return 0; }\n"); - for(i=0; i < count; ++i) - { - fprintf(ofp, " if(fwrite(kwsysEncodedArray%s_%d, 1,\n" - " sizeof(kwsysEncodedArray%s_%d), ofp) !=\n" - " sizeof(kwsysEncodedArray%s_%d))\n", - argv[4], i, argv[4], i, argv[4], i); - fprintf(ofp, " {\n"); - fprintf(ofp, " fclose(ofp);\n"); - fprintf(ofp, " kwsys_unlink(fname);\n"); - fprintf(ofp, " return 0;\n"); - fprintf(ofp, " }\n"); - } - fprintf(ofp, " fclose(ofp);\n"); - fprintf(ofp, " return 1;\n"); - fprintf(ofp, "}\n"); - fclose(ofp); - return 0; -} diff --git a/Source/kwsys/ProcessFwd9x.c b/Source/kwsys/ProcessFwd9x.c deleted file mode 100644 index 536c54b..0000000 --- a/Source/kwsys/ProcessFwd9x.c +++ /dev/null @@ -1,211 +0,0 @@ -/*============================================================================ - KWSys - Kitware System Library - Copyright 2000-2009 Kitware, Inc., Insight Software Consortium - - Distributed under the OSI-approved BSD License (the "License"); - see accompanying file Copyright.txt for details. - - This software is distributed WITHOUT ANY WARRANTY; without even the - implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the License for more information. -============================================================================*/ - -/* - On Windows9x platforms, this executable is spawned between a parent - process and the child it is invoking to work around a bug. See the - Win32 implementation file for details. - - Future Work: This executable must be linked statically against the C - runtime library before being encoded into the library. Building it - in this way may be hard because CMake has limited abilities to build - different targets with different configurations in the same - directory. We may just have to create and encode the executable - once instead of generating it during the build. This would be an - acceptable solution because the forwarding executable should not - change very often and is pretty simple. -*/ - -#ifdef _MSC_VER -#pragma warning (push, 1) -#endif -#include <windows.h> -#include <stdio.h> - -void ReportLastError(HANDLE errorPipe); - -int main() -{ - /* Process startup information for the real child. */ - STARTUPINFO si; - PROCESS_INFORMATION pi; - - /* The result of waiting for the child to exit. */ - DWORD waitResult; - - /* The child's process return code. */ - DWORD retVal; - - /* The command line used to invoke this process. */ - LPSTR commandLine = GetCommandLine(); - - /* Pointer that will be advanced to the beginning of the command - line of the real child process. */ - LPSTR cmdLine = commandLine; - - /* Handle to the error reporting pipe provided by the parent. This - is parsed off the command line. */ - HANDLE errorPipe = 0; - HANDLE errorPipeOrig = 0; - - /* Handle to the event the parent uses to tell us to resume the child. - This is parsed off the command line. */ - HANDLE resumeEvent = 0; - - /* Handle to the event the parent uses to tell us to kill the child. - This is parsed off the command line. */ - HANDLE killEvent = 0; - - /* Flag for whether to hide window of child process. */ - int hideWindow = 0; - - /* An array of the handles on which we wait when the child is - running. */ - HANDLE waitHandles[2] = {0, 0}; - - /* Move the pointer past the name of this executable. */ - if(*cmdLine == '"') - { - ++cmdLine; - while(*cmdLine && *cmdLine != '"') { ++cmdLine; } - if(*cmdLine) { ++cmdLine; } - } - else - { - while(*cmdLine && *cmdLine != ' ') { ++cmdLine; } - } - - /* Parse the error pipe handle. */ - while(*cmdLine && *cmdLine == ' ') { ++cmdLine; } - sscanf(cmdLine, "%p", &errorPipeOrig); - - /* Parse the resume event handle. */ - while(*cmdLine && *cmdLine != ' ') { ++cmdLine; } - while(*cmdLine && *cmdLine == ' ') { ++cmdLine; } - sscanf(cmdLine, "%p", &resumeEvent); - - /* Parse the kill event handle. */ - while(*cmdLine && *cmdLine != ' ') { ++cmdLine; } - while(*cmdLine && *cmdLine == ' ') { ++cmdLine; } - sscanf(cmdLine, "%p", &killEvent); - - /* Parse the hide window flag. */ - while(*cmdLine && *cmdLine != ' ') { ++cmdLine; } - while(*cmdLine && *cmdLine == ' ') { ++cmdLine; } - sscanf(cmdLine, "%d", &hideWindow); - - /* Skip to the beginning of the command line of the real child. */ - while(*cmdLine && *cmdLine != ' ') { ++cmdLine; } - while(*cmdLine && *cmdLine == ' ') { ++cmdLine; } - - /* Create a non-inherited copy of the error pipe. We do not want - the child to get it. */ - if(DuplicateHandle(GetCurrentProcess(), errorPipeOrig, - GetCurrentProcess(), &errorPipe, - 0, FALSE, DUPLICATE_SAME_ACCESS)) - { - /* Have a non-inherited duplicate. Close the inherited one. */ - CloseHandle(errorPipeOrig); - } - else - { - /* Could not duplicate handle. Report the error. */ - ReportLastError(errorPipeOrig); - return 1; - } - - /* Create the subprocess. */ - ZeroMemory(&si, sizeof(si)); - ZeroMemory(&pi, sizeof(pi)); - si.cb = sizeof(si); - si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; - si.wShowWindow = hideWindow?SW_HIDE:SW_SHOWDEFAULT; - si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); - si.hStdError = GetStdHandle(STD_ERROR_HANDLE); - if(CreateProcess(0, cmdLine, 0, 0, TRUE, CREATE_SUSPENDED, 0, 0, &si, &pi)) - { - /* Process created successfully. Close the error reporting pipe - to notify the parent of success. */ - CloseHandle(errorPipe); - } - else - { - /* Error creating the process. Report the error to the parent - process through the special error reporting pipe. */ - ReportLastError(errorPipe); - return 1; - } - - /* Wait for resume or kill event from parent. */ - waitHandles[0] = killEvent; - waitHandles[1] = resumeEvent; - waitResult = WaitForMultipleObjects(2, waitHandles, 0, INFINITE); - - /* Check what happened. */ - if(waitResult == WAIT_OBJECT_0) - { - /* We were asked to kill the child. */ - TerminateProcess(pi.hProcess, 255); - WaitForSingleObject(pi.hProcess, INFINITE); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - return 1; - } - else - { - /* We were asked to resume the child. */ - ResumeThread(pi.hThread); - CloseHandle(pi.hThread); - } - - /* Wait for subprocess to exit or for kill event from parent. */ - waitHandles[0] = killEvent; - waitHandles[1] = pi.hProcess; - waitResult = WaitForMultipleObjects(2, waitHandles, 0, INFINITE); - - /* Check what happened. */ - if(waitResult == WAIT_OBJECT_0) - { - /* We were asked to kill the child. */ - TerminateProcess(pi.hProcess, 255); - WaitForSingleObject(pi.hProcess, INFINITE); - CloseHandle(pi.hProcess); - return 1; - } - else - { - /* The child exited. Get the return code. */ - GetExitCodeProcess(pi.hProcess, &retVal); - CloseHandle(pi.hProcess); - return retVal; - } -} - -void ReportLastError(HANDLE errorPipe) -{ - LPVOID lpMsgBuf; - DWORD n; - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPTSTR) &lpMsgBuf, - 0, - NULL - ); - WriteFile(errorPipe, lpMsgBuf, strlen(lpMsgBuf)+1, &n, 0); - LocalFree( lpMsgBuf ); -} diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c index 5aa4d8b..c836f9b 100644 --- a/Source/kwsys/ProcessWin32.c +++ b/Source/kwsys/ProcessWin32.c @@ -28,14 +28,6 @@ On windows, a thread is created to wait for data on each pipe. The threads are synchronized with the main thread to simulate the use of a UNIX-style select system call. -On Windows9x platforms, a small WIN32 console application is spawned -in-between the calling process and the actual child to be executed. -This is to work-around a problem with connecting pipes from WIN16 -console applications to WIN32 applications. - -For more information, please check Microsoft Knowledge Base Articles -Q190351 and Q150956. - */ #ifdef _MSC_VER @@ -91,18 +83,12 @@ Q190351 and Q150956. # define KWSYSPE_DEBUG(x) (void)1 #endif -#define kwsysEncodedWriteArrayProcessFwd9x kwsys_ns(EncodedWriteArrayProcessFwd9x) - typedef LARGE_INTEGER kwsysProcessTime; typedef struct kwsysProcessCreateInformation_s { /* Windows child startup control data. */ STARTUPINFO StartupInfo; - - /* Special error reporting pipe for Win9x forwarding executable. */ - HANDLE ErrorPipeRead; - HANDLE ErrorPipeWrite; } kwsysProcessCreateInformation; /*--------------------------------------------------------------------------*/ @@ -146,7 +132,6 @@ static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProc static void kwsysProcessSetExitException(kwsysProcess* cp, int code); static void kwsysProcessKillTree(int pid); static void kwsysProcessDisablePipeThreads(kwsysProcess* cp); -extern kwsysEXPORT int kwsysEncodedWriteArrayProcessFwd9x(const char* fname); /*--------------------------------------------------------------------------*/ /* A structure containing synchronization data for each thread. */ @@ -233,15 +218,6 @@ struct kwsysProcess_s /* Whether to treat command lines as verbatim. */ int Verbatim; - /* On Win9x platforms, the path to the forwarding executable. */ - char* Win9x; - - /* On Win9x platforms, the resume event for the forwarding executable. */ - HANDLE Win9xResumeEvent; - - /* On Win9x platforms, the kill event for the forwarding executable. */ - HANDLE Win9xKillEvent; - /* Mutex to protect the shared index used by threads to report data. */ HANDLE SharedIndexMutex; @@ -269,9 +245,6 @@ struct kwsysProcess_s HANDLE PipeNativeSTDOUT[2]; HANDLE PipeNativeSTDERR[2]; - /* Handle to automatically delete the Win9x forwarding executable. */ - HANDLE Win9xHandle; - /* ------------- Data managed per call to Execute ------------- */ /* The exceptional behavior that terminated the process, if any. */ @@ -311,7 +284,7 @@ struct kwsysProcess_s for pipes to close after process termination. */ int PipesLeft; - /* Buffer for error messages (possibly from Win9x child). */ + /* Buffer for error messages. */ char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE+1]; /* Description for the ExitException. */ @@ -337,9 +310,6 @@ kwsysProcess* kwsysProcess_New(void) /* Process control structure. */ kwsysProcess* cp; - /* Path to Win9x forwarding executable. */ - char* win9x = 0; - /* Windows version number data. */ OSVERSIONINFO osv; @@ -365,73 +335,11 @@ kwsysProcess* kwsysProcess_New(void) GetVersionEx(&osv); if(osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { - /* This is Win9x. We need the console forwarding executable to - work-around a Windows 9x bug. */ - char fwdName[_MAX_FNAME+1] = ""; - char tempDir[_MAX_PATH+1] = ""; - - /* We will try putting the executable in the system temp - directory. Note that the returned path already has a trailing - slash. */ - DWORD length = GetTempPath(_MAX_PATH+1, tempDir); - - /* Construct the executable name from the process id and kwsysProcess - instance. This should be unique. */ - sprintf(fwdName, KWSYS_NAMESPACE_STRING "pew9xfwd_%ld_%p.exe", - GetCurrentProcessId(), cp); - - /* If we have a temp directory, use it. */ - if(length > 0 && length <= _MAX_PATH) - { - /* Allocate a buffer to hold the forwarding executable path. */ - size_t tdlen = strlen(tempDir); - win9x = (char*)malloc(tdlen + strlen(fwdName) + 2); - if(!win9x) - { - kwsysProcess_Delete(cp); - return 0; - } - - /* Construct the full path to the forwarding executable. */ - sprintf(win9x, "%s%s", tempDir, fwdName); - } - - /* If we found a place to put the forwarding executable, try to - write it. */ - if(win9x) - { - if(!kwsysEncodedWriteArrayProcessFwd9x(win9x)) - { - /* Failed to create forwarding executable. Give up. */ - free(win9x); - kwsysProcess_Delete(cp); - return 0; - } - - /* Get a handle to the file that will delete it when closed. */ - cp->Win9xHandle = CreateFile(win9x, GENERIC_READ, FILE_SHARE_READ, 0, - OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, 0); - if(cp->Win9xHandle == INVALID_HANDLE_VALUE) - { - /* We were not able to get a read handle for the forwarding - executable. It will not be deleted properly. Give up. */ - _unlink(win9x); - free(win9x); - kwsysProcess_Delete(cp); - return 0; - } - } - else - { - /* Failed to find a place to put forwarding executable. */ - kwsysProcess_Delete(cp); - return 0; - } + /* Win9x no longer supported. */ + kwsysProcess_Delete(cp); + return 0; } - /* Save the path to the forwarding executable. */ - cp->Win9x = win9x; - /* Initially no thread owns the mutex. Initialize semaphore to 1. */ if(!(cp->SharedIndexMutex = CreateSemaphore(0, 1, 1, 0))) { @@ -446,30 +354,6 @@ kwsysProcess* kwsysProcess_New(void) return 0; } - if(cp->Win9x) - { - SECURITY_ATTRIBUTES sa; - ZeroMemory(&sa, sizeof(sa)); - sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - - /* Create an event to tell the forwarding executable to resume the - child. */ - if(!(cp->Win9xResumeEvent = CreateEvent(&sa, TRUE, 0, 0))) - { - kwsysProcess_Delete(cp); - return 0; - } - - /* Create an event to tell the forwarding executable to kill the - child. */ - if(!(cp->Win9xKillEvent = CreateEvent(&sa, TRUE, 0, 0))) - { - kwsysProcess_Delete(cp); - return 0; - } - } - /* Create the thread to read each pipe. */ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i) { @@ -620,13 +504,6 @@ void kwsysProcess_Delete(kwsysProcess* cp) kwsysProcessCleanupHandle(&cp->SharedIndexMutex); kwsysProcessCleanupHandle(&cp->Full); - /* Close the Win9x resume and kill event handles. */ - if(cp->Win9x) - { - kwsysProcessCleanupHandle(&cp->Win9xResumeEvent); - kwsysProcessCleanupHandle(&cp->Win9xKillEvent); - } - /* Free memory. */ kwsysProcess_SetCommand(cp, 0); kwsysProcess_SetWorkingDirectory(cp, 0); @@ -637,12 +514,6 @@ void kwsysProcess_Delete(kwsysProcess* cp) { free(cp->CommandExitCodes); } - if(cp->Win9x) - { - /* Close our handle to the forwarding executable file. This will - cause it to be deleted. */ - kwsysProcessCleanupHandle(&cp->Win9xHandle); - } free(cp); } @@ -1017,21 +888,6 @@ void kwsysProcess_Execute(kwsysProcess* cp) SetCurrentDirectory(cp->WorkingDirectory); } - /* Reset the Win9x resume and kill events. */ - if(cp->Win9x) - { - if(!ResetEvent(cp->Win9xResumeEvent)) - { - kwsysProcessCleanup(cp, 1); - return; - } - if(!ResetEvent(cp->Win9xKillEvent)) - { - kwsysProcessCleanup(cp, 1); - return; - } - } - /* Initialize startup info data. */ ZeroMemory(&si, sizeof(si)); si.StartupInfo.cb = sizeof(si.StartupInfo); @@ -1130,8 +986,6 @@ void kwsysProcess_Execute(kwsysProcess* cp) STD_OUTPUT_HANDLE); kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdError, STD_ERROR_HANDLE); - kwsysProcessCleanupHandle(&si.ErrorPipeRead); - kwsysProcessCleanupHandle(&si.ErrorPipeWrite); return; } } @@ -1160,16 +1014,9 @@ void kwsysProcess_Execute(kwsysProcess* cp) /* All processes in the pipeline have been started in suspended mode. Resume them all now. */ - if(cp->Win9x) - { - SetEvent(cp->Win9xResumeEvent); - } - else + for(i=0; i < cp->NumberOfCommands; ++i) { - for(i=0; i < cp->NumberOfCommands; ++i) - { - ResumeThread(cp->ProcessInformation[i].hThread); - } + ResumeThread(cp->ProcessInformation[i].hThread); } /* ---- It is no longer safe to call kwsysProcessCleanup. ----- */ @@ -1480,21 +1327,12 @@ void kwsysProcess_Kill(kwsysProcess* cp) /* Kill the children. */ cp->Killed = 1; - if(cp->Win9x) - { - /* Windows 9x. Tell the forwarding executable to kill the child. */ - SetEvent(cp->Win9xKillEvent); - } - else + for(i=0; i < cp->NumberOfCommands; ++i) { - /* Not Windows 9x. Just terminate the children. */ - for(i=0; i < cp->NumberOfCommands; ++i) - { - kwsysProcessKillTree(cp->ProcessInformation[i].dwProcessId); - // close the handle if we kill it - kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread); - kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess); - } + kwsysProcessKillTree(cp->ProcessInformation[i].dwProcessId); + // close the handle if we kill it + kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread); + kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess); } /* We are killing the children and ignoring all data. Do not wait @@ -1815,97 +1653,13 @@ int kwsysProcessCreate(kwsysProcess* cp, int index, } } - /* Create the child process. */ - { - BOOL r; - char* realCommand; - if(cp->Win9x) - { - /* Create an error reporting pipe for the forwarding executable. - Neither end is directly inherited. */ - if(!CreatePipe(&si->ErrorPipeRead, &si->ErrorPipeWrite, 0, 0)) - { - return 0; - } - - /* Create an inherited duplicate of the write end. This also closes - the non-inherited version. */ - if(!DuplicateHandle(GetCurrentProcess(), si->ErrorPipeWrite, - GetCurrentProcess(), &si->ErrorPipeWrite, - 0, TRUE, (DUPLICATE_CLOSE_SOURCE | - DUPLICATE_SAME_ACCESS))) - { - return 0; - } - - /* The forwarding executable is given a handle to the error pipe - and resume and kill events. */ - realCommand = (char*)malloc(strlen(cp->Win9x)+strlen(cp->Commands[index])+100); - if(!realCommand) - { - return 0; - } - sprintf(realCommand, "%s %p %p %p %d %s", cp->Win9x, - si->ErrorPipeWrite, cp->Win9xResumeEvent, cp->Win9xKillEvent, - cp->HideWindow, cp->Commands[index]); - } - else - { - realCommand = cp->Commands[index]; - } - /* Create the child in a suspended state so we can wait until all children have been created before running any one. */ - r = CreateProcess(0, realCommand, 0, 0, TRUE, - cp->Win9x? 0 : CREATE_SUSPENDED, 0, 0, - &si->StartupInfo, &cp->ProcessInformation[index]); - if(cp->Win9x) - { - /* Free memory. */ - free(realCommand); - - /* Close the error pipe write end so we can detect when the - forwarding executable closes it. */ - kwsysProcessCleanupHandle(&si->ErrorPipeWrite); - if(r) - { - /* Wait for the forwarding executable to report an error or - close the error pipe to report success. */ - DWORD total = 0; - DWORD n = 1; - while(total < KWSYSPE_PIPE_BUFFER_SIZE && n > 0) - { - if(ReadFile(si->ErrorPipeRead, cp->ErrorMessage+total, - KWSYSPE_PIPE_BUFFER_SIZE-total, &n, 0)) - { - total += n; - } - else - { - n = 0; - } - } - if(total > 0 || GetLastError() != ERROR_BROKEN_PIPE) - { - /* The forwarding executable could not run the process, or - there was an error reading from its error pipe. Preserve - the last error while cleaning up the forwarding executable - so the cleanup our caller does reports the proper error. */ - DWORD error = GetLastError(); - kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hThread); - kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess); - SetLastError(error); - return 0; - } - } - kwsysProcessCleanupHandle(&si->ErrorPipeRead); - } - - if(!r) + if(!CreateProcess(0, cp->Commands[index], 0, 0, TRUE, CREATE_SUSPENDED, 0, + 0, &si->StartupInfo, &cp->ProcessInformation[index])) { return 0; } - } /* Successfully created this child process. Close the current process's copies of the inherited stdout and stdin handles. The @@ -2152,19 +1906,12 @@ void kwsysProcessCleanup(kwsysProcess* cp, int error) /* Cleanup any processes already started in a suspended state. */ if(cp->ProcessInformation) { - if(cp->Win9x) - { - SetEvent(cp->Win9xKillEvent); - } - else + for(i=0; i < cp->NumberOfCommands; ++i) { - for(i=0; i < cp->NumberOfCommands; ++i) + if(cp->ProcessInformation[i].hProcess) { - if(cp->ProcessInformation[i].hProcess) - { - TerminateProcess(cp->ProcessInformation[i].hProcess, 255); - WaitForSingleObject(cp->ProcessInformation[i].hProcess, INFINITE); - } + TerminateProcess(cp->ProcessInformation[i].hProcess, 255); + WaitForSingleObject(cp->ProcessInformation[i].hProcess, INFINITE); } } for(i=0; i < cp->NumberOfCommands; ++i) diff --git a/Source/kwsys/Registry.cxx b/Source/kwsys/Registry.cxx deleted file mode 100644 index cd521c9..0000000 --- a/Source/kwsys/Registry.cxx +++ /dev/null @@ -1,818 +0,0 @@ -/*============================================================================ - KWSys - Kitware System Library - Copyright 2000-2009 Kitware, Inc., Insight Software Consortium - - Distributed under the OSI-approved BSD License (the "License"); - see accompanying file Copyright.txt for details. - - This software is distributed WITHOUT ANY WARRANTY; without even the - implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the License for more information. -============================================================================*/ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(Registry.hxx) - -#include KWSYS_HEADER(Configure.hxx) -#include KWSYS_HEADER(ios/iostream) -#include KWSYS_HEADER(stl/string) -#include KWSYS_HEADER(stl/map) -#include KWSYS_HEADER(ios/iostream) -#include KWSYS_HEADER(ios/fstream) -#include KWSYS_HEADER(ios/sstream) -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "Registry.hxx.in" -# include "Configure.hxx.in" -# include "kwsys_stl.hxx.in" -# include "kwsys_stl_string.hxx.in" -# include "kwsys_stl_map.hxx.in" -# include "kwsys_ios_iostream.h.in" -# include "kwsys_ios_fstream.h.in" -# include "kwsys_ios_sstream.h.in" -#endif - -#include <ctype.h> // for isspace -#include <stdio.h> -#include <string.h> /* strlen, strncpy */ -#include <stdlib.h> /* getenv */ - -#ifdef _WIN32 -# include <windows.h> -#endif - - -namespace KWSYS_NAMESPACE -{ -class RegistryHelper { -public: - RegistryHelper(Registry::RegistryType registryType); - virtual ~RegistryHelper(); - - // Read a value from the registry. - virtual bool ReadValue(const char *key, const char **value); - - // Delete a key from the registry. - virtual bool DeleteKey(const char *key); - - // Delete a value from a given key. - virtual bool DeleteValue(const char *key); - - // Set value in a given key. - virtual bool SetValue(const char *key, const char *value); - - // Open the registry at toplevel/subkey. - virtual bool Open(const char *toplevel, const char *subkey, - int readonly); - - // Close the registry. - virtual bool Close(); - - // Set the value of changed - void SetChanged(bool b) { m_Changed = b; } - void SetTopLevel(const char* tl); - const char* GetTopLevel() { return m_TopLevel.c_str(); } - - //! Read from local or global scope. On Windows this mean from local machine - // or local user. On unix this will read from $HOME/.Projectrc or - // /etc/Project - void SetGlobalScope(bool b); - bool GetGlobalScope(); - - kwsys_stl::string EncodeKey(const char* str); - kwsys_stl::string EncodeValue(const char* str); - kwsys_stl::string DecodeValue(const char* str); - -protected: - bool m_Changed; - kwsys_stl::string m_TopLevel; - bool m_GlobalScope; - -#ifdef _WIN32 - HKEY HKey; -#endif - // Strip trailing and ending spaces. - char *Strip(char *str); - void SetSubKey(const char* sk); - kwsys_stl::string CreateKey(const char *key); - - typedef kwsys_stl::map<kwsys_stl::string, kwsys_stl::string> StringToStringMap; - StringToStringMap EntriesMap; - kwsys_stl::string m_SubKey; - bool m_Empty; - bool m_SubKeySpecified; - kwsys_stl::string m_HomeDirectory; - - Registry::RegistryType m_RegistryType; -}; - -//---------------------------------------------------------------------------- -#define Registry_BUFFER_SIZE 8192 - -//---------------------------------------------------------------------------- -Registry::Registry(Registry::RegistryType registryType) -{ - m_Opened = false; - m_Locked = false; - this->Helper = 0; - this->Helper = new RegistryHelper(registryType); -} - -//---------------------------------------------------------------------------- -Registry::~Registry() -{ - if ( m_Opened ) - { - kwsys_ios::cerr << "Registry::Close should be " - "called here. The registry is not closed." - << kwsys_ios::endl; - } - delete this->Helper; -} - -//---------------------------------------------------------------------------- -void Registry::SetGlobalScope(bool b) -{ - this->Helper->SetGlobalScope(b); -} - -//---------------------------------------------------------------------------- -bool Registry::GetGlobalScope() -{ - return this->Helper->GetGlobalScope(); -} - -//---------------------------------------------------------------------------- -bool Registry::Open(const char *toplevel, - const char *subkey, int readonly) -{ - bool res = false; - if ( m_Locked ) - { - return res; - } - if ( m_Opened ) - { - if ( !this->Close() ) - { - return res; - } - } - if ( !toplevel || !*toplevel ) - { - kwsys_ios::cerr << "Registry::Opened() Toplevel not defined" - << kwsys_ios::endl; - return res; - } - - if ( isspace(toplevel[0]) || - isspace(toplevel[strlen(toplevel)-1]) ) - { - kwsys_ios::cerr << "Toplevel has to start with letter or number and end" - " with one" << kwsys_ios::endl; - return res; - } - - res = this->Helper->Open(toplevel, subkey, readonly); - if ( readonly != Registry::READONLY ) - { - m_Locked = true; - } - - if ( res ) - { - m_Opened = true; - this->Helper->SetTopLevel(toplevel); - } - return res; -} - -//---------------------------------------------------------------------------- -bool Registry::Close() -{ - bool res = false; - if ( m_Opened ) - { - res = this->Helper->Close(); - } - - if ( res ) - { - m_Opened = false; - m_Locked = false; - this->Helper->SetChanged(false); - } - return res; -} - -//---------------------------------------------------------------------------- -bool Registry::ReadValue(const char *subkey, - const char *key, - const char **value) -{ - bool res = false; - bool open = false; - if ( ! value ) - { - return res; - } - *value = 0; - if ( !m_Opened ) - { - if ( !this->Open(this->GetTopLevel(), subkey, - Registry::READONLY) ) - { - return res; - } - open = true; - } - res = this->Helper->ReadValue(key, value); - - if ( open ) - { - if ( !this->Close() ) - { - res = false; - } - } - return res; -} - -//---------------------------------------------------------------------------- -bool Registry::DeleteKey(const char *subkey, const char *key) -{ - bool res = false; - bool open = false; - if ( !m_Opened ) - { - if ( !this->Open(this->GetTopLevel(), subkey, - Registry::READWRITE) ) - { - return res; - } - open = true; - } - - res = this->Helper->DeleteKey(key); - if ( res ) - { - this->Helper->SetChanged(true); - } - - if ( open ) - { - if ( !this->Close() ) - { - res = false; - } - } - return res; -} - -//---------------------------------------------------------------------------- -bool Registry::DeleteValue(const char *subkey, const char *key) -{ - bool res = false; - bool open = false; - if ( !m_Opened ) - { - if ( !this->Open(this->GetTopLevel(), subkey, - Registry::READWRITE) ) - { - return res; - } - open = true; - } - - res = this->Helper->DeleteValue(key); - if ( res ) - { - this->Helper->SetChanged(true); - } - - if ( open ) - { - if ( !this->Close() ) - { - res = false; - } - } - return res; -} - -//---------------------------------------------------------------------------- -bool Registry::SetValue(const char *subkey, const char *key, - const char *value) -{ - bool res = false; - bool open = false; - if ( !m_Opened ) - { - if ( !this->Open(this->GetTopLevel(), subkey, - Registry::READWRITE) ) - { - return res; - } - open = true; - } - - res = this->Helper->SetValue( key, value ); - if ( res ) - { - this->Helper->SetChanged(true); - } - - if ( open ) - { - if ( !this->Close() ) - { - res = false; - } - } - return res; -} - -//---------------------------------------------------------------------------- -const char* Registry::GetTopLevel() -{ - return this->Helper->GetTopLevel(); -} - -//---------------------------------------------------------------------------- -void Registry::SetTopLevel(const char* tl) -{ - this->Helper->SetTopLevel(tl); -} - -//---------------------------------------------------------------------------- -void RegistryHelper::SetTopLevel(const char* tl) -{ - if ( tl ) - { - m_TopLevel = tl; - } - else - { - m_TopLevel = ""; - } -} - -//---------------------------------------------------------------------------- -RegistryHelper::RegistryHelper(Registry::RegistryType registryType) -{ - m_Changed = false; - m_TopLevel = ""; - m_SubKey = ""; - m_SubKeySpecified = false; - m_Empty = true; - m_GlobalScope = false; - m_RegistryType = registryType; -} - -//---------------------------------------------------------------------------- -RegistryHelper::~RegistryHelper() -{ -} - - -//---------------------------------------------------------------------------- -bool RegistryHelper::Open(const char *toplevel, const char *subkey, - int readonly) -{ - this->EntriesMap.clear(); - m_Empty = 1; - -#ifdef _WIN32 - if ( m_RegistryType == Registry::WIN32_REGISTRY) - { - HKEY scope = HKEY_CURRENT_USER; - if ( this->GetGlobalScope() ) - { - scope = HKEY_LOCAL_MACHINE; - } - int res = 0; - kwsys_ios::ostringstream str; - DWORD dwDummy; - str << "Software\\Kitware\\" << toplevel << "\\" << subkey; - if ( readonly == Registry::READONLY ) - { - res = ( RegOpenKeyEx(scope, str.str().c_str(), - 0, KEY_READ, &this->HKey) == ERROR_SUCCESS ); - } - else - { - char lpClass[] = ""; - res = ( RegCreateKeyEx(scope, str.str().c_str(), - 0, lpClass, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, - NULL, &this->HKey, &dwDummy) == ERROR_SUCCESS ); - } - if ( res != 0 ) - { - this->SetSubKey( subkey ); - } - return (res != 0); - } -#endif - if ( m_RegistryType == Registry::FILE_REGISTRY ) - { - bool res = false; - int cc; - kwsys_ios::ostringstream str; - const char* homeDirectory; - if ( (homeDirectory = getenv("HOME")) == 0 ) - { - if ( (homeDirectory = getenv("USERPROFILE")) == 0 ) - { - return false; - } - } - m_HomeDirectory = homeDirectory; - str << m_HomeDirectory.c_str() << "/." << toplevel << "rc"; - if ( readonly == Registry::READWRITE ) - { - kwsys_ios::ofstream ofs( str.str().c_str(), kwsys_ios::ios::out|kwsys_ios::ios::app ); - if ( ofs.fail() ) - { - return false; - } - ofs.close(); - } - - kwsys_ios::ifstream *ifs = new kwsys_ios::ifstream(str.str().c_str(), kwsys_ios::ios::in -#ifndef KWSYS_IOS_USE_ANSI - | kwsys_ios::ios::nocreate -#endif - ); - if ( !ifs ) - { - return false; - } - if ( ifs->fail()) - { - delete ifs; - return false; - } - - res = true; - char buffer[Registry_BUFFER_SIZE]; - while( !ifs->fail() ) - { - ifs->getline(buffer, Registry_BUFFER_SIZE); - if ( ifs->fail() || ifs->eof() ) - { - break; - } - char *line = this->Strip(buffer); - if ( *line == '#' || *line == 0 ) - { - // Comment - continue; - } - int linelen = static_cast<int>(strlen(line)); - for ( cc = 0; cc < linelen; cc++ ) - { - if ( line[cc] == '=' ) - { - char *key = new char[ cc+1 ]; - strncpy( key, line, cc ); - key[cc] = 0; - char *value = line + cc + 1; - char *nkey = this->Strip(key); - char *nvalue = this->Strip(value); - this->EntriesMap[nkey] = this->DecodeValue(nvalue); - m_Empty = 0; - delete [] key; - break; - } - } - } - ifs->close(); - this->SetSubKey( subkey ); - delete ifs; - return res; - } - return false; -} - -//---------------------------------------------------------------------------- -bool RegistryHelper::Close() -{ -#ifdef _WIN32 - if ( m_RegistryType == Registry::WIN32_REGISTRY) - { - int res; - res = ( RegCloseKey(this->HKey) == ERROR_SUCCESS ); - return (res != 0); - } -#endif - if ( m_RegistryType == Registry::FILE_REGISTRY ) - { - if ( !m_Changed ) - { - this->SetSubKey(0); - return true; - } - - kwsys_ios::ostringstream str; - str << m_HomeDirectory.c_str() << "/." << this->GetTopLevel() << "rc"; - kwsys_ios::ofstream *ofs = new kwsys_ios::ofstream(str.str().c_str(), kwsys_ios::ios::out); - if ( !ofs ) - { - return false; - } - if ( ofs->fail()) - { - delete ofs; - return false; - } - *ofs << "# This file is automatically generated by the application" << kwsys_ios::endl - << "# If you change any lines or add new lines, note that all" << kwsys_ios::endl - << "# comments and empty lines will be deleted. Every line has" << kwsys_ios::endl - << "# to be in format: " << kwsys_ios::endl - << "# key = value" << kwsys_ios::endl - << "#" << kwsys_ios::endl; - - if ( !this->EntriesMap.empty() ) - { - RegistryHelper::StringToStringMap::iterator it; - for ( it = this->EntriesMap.begin(); - it != this->EntriesMap.end(); - ++ it ) - { - *ofs << it->first.c_str() << " = " << this->EncodeValue(it->second.c_str()).c_str() << kwsys_ios::endl; - } - } - this->EntriesMap.clear(); - ofs->close(); - delete ofs; - this->SetSubKey(0); - m_Empty = 1; - return true; - } - return false; -} - -//---------------------------------------------------------------------------- -bool RegistryHelper::ReadValue(const char *skey, const char **value) - -{ -#ifdef _WIN32 - if ( m_RegistryType == Registry::WIN32_REGISTRY) - { - kwsys_stl::string key = this->CreateKey( skey ); - if ( key.empty() ) - { - return false; - } - DWORD dwType, dwSize; - dwType = REG_SZ; - char buffer[1024]; // Replace with RegQueryInfoKey - dwSize = sizeof(buffer); - int res = ( RegQueryValueEx(this->HKey, skey, NULL, &dwType, - (BYTE *)buffer, &dwSize) == ERROR_SUCCESS ); - if ( !res ) - { - return false; - } - this->EntriesMap[key] = buffer; - RegistryHelper::StringToStringMap::iterator it - = this->EntriesMap.find(key); - *value = it->second.c_str(); - return true; - } -#endif - if ( m_RegistryType == Registry::FILE_REGISTRY ) - { - bool res = false; - kwsys_stl::string key = this->CreateKey( skey ); - if ( key.empty() ) - { - return false; - } - - RegistryHelper::StringToStringMap::iterator it - = this->EntriesMap.find(key); - if ( it != this->EntriesMap.end() ) - { - *value = it->second.c_str(); - res = true; - } - return res; - } - return false; -} - -//---------------------------------------------------------------------------- -bool RegistryHelper::DeleteKey(const char* skey) -{ -#ifdef _WIN32 - if ( m_RegistryType == Registry::WIN32_REGISTRY) - { - int res = ( RegDeleteKey( this->HKey, skey ) == ERROR_SUCCESS ); - return (res != 0); - } -#endif - if ( m_RegistryType == Registry::FILE_REGISTRY ) - { - kwsys_stl::string key = this->CreateKey( skey ); - if ( key.empty() ) - { - return false; - } - this->EntriesMap.erase(key); - return true; - } - return false; -} - -//---------------------------------------------------------------------------- -bool RegistryHelper::DeleteValue(const char *skey) -{ -#ifdef _WIN32 - if ( m_RegistryType == Registry::WIN32_REGISTRY) - { - int res = ( RegDeleteValue( this->HKey, skey ) == ERROR_SUCCESS ); - return (res != 0); - } -#endif - if ( m_RegistryType == Registry::FILE_REGISTRY ) - { - kwsys_stl::string key = this->CreateKey( skey ); - if ( key.empty() ) - { - return false; - } - this->EntriesMap.erase(key); - return true; - } - return false; -} - -//---------------------------------------------------------------------------- -bool RegistryHelper::SetValue(const char *skey, const char *value) -{ -#ifdef _WIN32 - if ( m_RegistryType == Registry::WIN32_REGISTRY) - { - DWORD len = (DWORD)(value ? strlen(value) : 0); - int res = ( RegSetValueEx(this->HKey, skey, 0, REG_SZ, - (CONST BYTE *)(const char *)value, - len+1) == ERROR_SUCCESS ); - return (res != 0); - } -#endif - if ( m_RegistryType == Registry::FILE_REGISTRY ) - { - kwsys_stl::string key = this->CreateKey( skey ); - if ( key.empty() ) - { - return 0; - } - this->EntriesMap[key] = value; - return 1; - } - return false; -} - -//---------------------------------------------------------------------------- -kwsys_stl::string RegistryHelper::CreateKey( const char *key ) -{ - if ( !m_SubKeySpecified || m_SubKey.empty() || !key ) - { - return ""; - } - kwsys_ios::ostringstream ostr; - ostr << this->EncodeKey(this->m_SubKey.c_str()).c_str() - << "\\" << this->EncodeKey(key).c_str(); - return ostr.str(); -} - -//---------------------------------------------------------------------------- -void RegistryHelper::SetSubKey(const char* sk) -{ - if ( !sk ) - { - m_SubKey = ""; - m_SubKeySpecified = false; - } - else - { - m_SubKey = sk; - m_SubKeySpecified = true; - } -} - -//---------------------------------------------------------------------------- -char *RegistryHelper::Strip(char *str) -{ - int cc; - size_t len; - char *nstr; - if ( !str ) - { - return NULL; - } - len = strlen(str); - nstr = str; - for( cc=0; cc < static_cast<int>(len); cc++ ) - { - if ( !isspace( *nstr ) ) - { - break; - } - nstr ++; - } - for( cc= static_cast<int>(strlen(nstr))-1; cc>=0; cc-- ) - { - if ( !isspace( nstr[cc] ) ) - { - nstr[cc+1] = 0; - break; - } - } - return nstr; -} - -//---------------------------------------------------------------------------- -void RegistryHelper::SetGlobalScope(bool b) -{ - m_GlobalScope = b; -} - -//---------------------------------------------------------------------------- -bool RegistryHelper::GetGlobalScope() -{ - return m_GlobalScope; -} - -//---------------------------------------------------------------------------- -kwsys_stl::string RegistryHelper::EncodeKey(const char* str) -{ - kwsys_ios::ostringstream ostr; - while ( *str ) - { - switch ( *str ) - { - case '%': case '=': case '\n': case '\r': case '\t': - char buffer[4]; - sprintf(buffer, "%%%02X", *str); - ostr << buffer; - break; - default: - ostr << *str; - } - str ++; - } - return ostr.str(); -} - -//---------------------------------------------------------------------------- -kwsys_stl::string RegistryHelper::EncodeValue(const char* str) -{ - kwsys_ios::ostringstream ostr; - while ( *str ) - { - switch ( *str ) - { - case '%': case '=': case '\n': case '\r': case '\t': - char buffer[4]; - sprintf(buffer, "%%%02X", *str); - ostr << buffer; - break; - default: - ostr << *str; - } - str ++; - } - return ostr.str(); -} - -//---------------------------------------------------------------------------- -kwsys_stl::string RegistryHelper::DecodeValue(const char* str) -{ - kwsys_ios::ostringstream ostr; - while ( *str ) - { - unsigned int val; - switch ( *str ) - { - case '%': - if ( *(str+1) && *(str+2) && sscanf(str+1, "%x", &val) == 1 ) - { - ostr << static_cast<char>(val); - str += 2; - } - else - { - ostr << *str; - } - break; - default: - ostr << *str; - } - str ++; - } - return ostr.str(); -} - -} // namespace KWSYS_NAMESPACE diff --git a/Source/kwsys/Registry.hxx.in b/Source/kwsys/Registry.hxx.in deleted file mode 100644 index ed9b010..0000000 --- a/Source/kwsys/Registry.hxx.in +++ /dev/null @@ -1,107 +0,0 @@ -/*============================================================================ - KWSys - Kitware System Library - Copyright 2000-2009 Kitware, Inc., Insight Software Consortium - - Distributed under the OSI-approved BSD License (the "License"); - see accompanying file Copyright.txt for details. - - This software is distributed WITHOUT ANY WARRANTY; without even the - implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the License for more information. -============================================================================*/ -#ifndef @KWSYS_NAMESPACE@_Registry_hxx -#define @KWSYS_NAMESPACE@_Registry_hxx - -#include <@KWSYS_NAMESPACE@/Configure.h> - -#include <@KWSYS_NAMESPACE@/stl/string> - -namespace @KWSYS_NAMESPACE@ -{ - -class RegistryHelper; - -/** \class Registry - * \brief Portable registry class - * - * This class abstracts the storing of data that can be restored - * when the program executes again. On Win32 platform it is - * implemented using the registry and on unix as a file in - * the user's home directory. - */ -class @KWSYS_NAMESPACE@_EXPORT Registry -{ -public: - enum RegistryType - { -#ifdef _WIN32 - WIN32_REGISTRY, -#endif - FILE_REGISTRY - }; - -#ifdef _WIN32 - Registry(RegistryType registryType = WIN32_REGISTRY); -#else - Registry(RegistryType registryType = FILE_REGISTRY); -#endif - - virtual ~Registry(); - - //! Read a value from the registry. - bool ReadValue(const char *subkey, const char *key, const char **value); - - //! Delete a key from the registry. - bool DeleteKey(const char *subkey, const char *key); - - //! Delete a value from a given key. - bool DeleteValue(const char *subkey, const char *key); - - //! Set value in a given key. - bool SetValue(const char *subkey, const char *key, - const char *value); - - //! Open the registry at toplevel/subkey. - bool Open(const char *toplevel, const char *subkey, - int readonly); - - //! Close the registry. - bool Close(); - - //! Read from local or global scope. On Windows this mean from local machine - // or local user. On unix this will read from $HOME/.Projectrc or - // /etc/Project - void GlobalScopeOn() { this->SetGlobalScope(1); } - void GlobalScopeOff() { this->SetGlobalScope(0); } - void SetGlobalScope(bool b); - bool GetGlobalScope(); - - // Set or get the toplevel registry key. - void SetTopLevel(const char* tl); - const char* GetTopLevel(); - - // Return true if registry opened - bool GetOpened() { return m_Opened; } - - // Should the registry be locked? - bool GetLocked() { return m_Locked; } - - enum { - READONLY, - READWRITE - }; - - // Return true if the character is space. - int IsSpace(char c); - -private: - RegistryHelper* Helper; - - bool m_Opened; - - bool m_Locked; -}; // End Class: Registry - -} // namespace @KWSYS_NAMESPACE@ - -#endif diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx index 6d990a9..bfdb0ed 100644 --- a/Source/kwsys/SystemInformation.cxx +++ b/Source/kwsys/SystemInformation.cxx @@ -307,7 +307,7 @@ public: enum Manufacturer { AMD, Intel, NSC, UMC, Cyrix, NexGen, IDT, Rise, Transmeta, Sun, IBM, - Motorola, UnknownManufacturer + Motorola, HP, UnknownManufacturer }; protected: @@ -346,7 +346,7 @@ protected: static void Delay (unsigned int); static void DelayOverhead (unsigned int); - void FindManufacturer(); + void FindManufacturer(const kwsys_stl::string &family = ""); // For Mac bool ParseSysCtl(); @@ -1144,6 +1144,7 @@ void SystemInformationImplementation::RunCPUCheck() { // Retrieve the CPU details. RetrieveCPUIdentity(); + this->FindManufacturer(); RetrieveCPUFeatures(); } @@ -1415,6 +1416,8 @@ const char * SystemInformationImplementation::GetVendorID() return "IBM"; case Motorola: return "Motorola"; + case HP: + return "Hewlett-Packard"; default: return "Unknown Manufacturer"; } @@ -1670,7 +1673,7 @@ bool SystemInformationImplementation::RetrieveCPUFeatures() #endif ; <<CPUID>> ; eax = 1 --> eax: CPU ID - bits 31..16 - unused, bits 15..12 - type, bits 11..8 - family, bits 7..4 - model, bits 3..0 - mask revision - ; ebx: 31..24 - default APIC ID, 23..16 - logical processsor ID, 15..8 - CFLUSH chunk size , 7..0 - brand ID + ; ebx: 31..24 - default APIC ID, 23..16 - logical processor ID, 15..8 - CFLUSH chunk size , 7..0 - brand ID ; edx: CPU feature flags mov eax,1 CPUID_INSTRUCTION @@ -1755,7 +1758,7 @@ bool SystemInformationImplementation::RetrieveCPUFeatures() /** Find the manufacturer given the vendor id */ -void SystemInformationImplementation::FindManufacturer() +void SystemInformationImplementation::FindManufacturer(const kwsys_stl::string& family) { if (this->ChipID.Vendor == "GenuineIntel") this->ChipManufacturer = Intel; // Intel Corp. else if (this->ChipID.Vendor == "UMC UMC UMC ") this->ChipManufacturer = UMC; // United Microelectronics Corp. @@ -1771,6 +1774,7 @@ void SystemInformationImplementation::FindManufacturer() else if (this->ChipID.Vendor == "Sun") this->ChipManufacturer = Sun; // Sun Microelectronics else if (this->ChipID.Vendor == "IBM") this->ChipManufacturer = IBM; // IBM Microelectronics else if (this->ChipID.Vendor == "Motorola") this->ChipManufacturer = Motorola; // Motorola Microelectronics + else if (family.substr(0, 7) == "PA-RISC") this->ChipManufacturer = HP; // Hewlett-Packard else this->ChipManufacturer = UnknownManufacturer; // Unknown manufacturer } @@ -1809,7 +1813,7 @@ bool SystemInformationImplementation::RetrieveCPUIdentity() ; <<CPUID>> ; eax = 1 --> eax: CPU ID - bits 31..16 - unused, bits 15..12 - type, bits 11..8 - family, bits 7..4 - model, bits 3..0 - mask revision - ; ebx: 31..24 - default APIC ID, 23..16 - logical processsor ID, 15..8 - CFLUSH chunk size , 7..0 - brand ID + ; ebx: 31..24 - default APIC ID, 23..16 - logical processor ID, 15..8 - CFLUSH chunk size , 7..0 - brand ID ; edx: CPU feature flags mov eax,1 CPUID_INSTRUCTION @@ -1836,8 +1840,6 @@ bool SystemInformationImplementation::RetrieveCPUIdentity() vbuf[12] = '\0'; this->ChipID.Vendor = vbuf; - this->FindManufacturer(); - // Retrieve the family of CPU present. this->ChipID.ExtendedFamily = ((localCPUSignature & 0x0FF00000) >> 20); // Bits 27..20 Used this->ChipID.ExtendedModel = ((localCPUSignature & 0x000F0000) >> 16); // Bits 19..16 Used @@ -2436,7 +2438,7 @@ bool SystemInformationImplementation::RetrieveExtendedCPUFeatures() #endif ; <<CPUID>> ; eax = 0x80000001 --> eax: CPU ID - bits 31..16 - unused, bits 15..12 - type, bits 11..8 - family, bits 7..4 - model, bits 3..0 - mask revision - ; ebx: 31..24 - default APIC ID, 23..16 - logical processsor ID, 15..8 - CFLUSH chunk size , 7..0 - brand ID + ; ebx: 31..24 - default APIC ID, 23..16 - logical processor ID, 15..8 - CFLUSH chunk size , 7..0 - brand ID ; edx: CPU feature flags mov eax,0x80000001 CPUID_INSTRUCTION @@ -3002,6 +3004,16 @@ kwsys_stl::string SystemInformationImplementation::ExtractValueFromCpuInfoFile(k size_t pos2 = buffer.find("\n",pos); if(pos!=buffer.npos && pos2!=buffer.npos) { + // It may happen that the beginning matches, but this is still not the requested key. + // An example is looking for "cpu" when "cpu family" comes first. So we check that + // we have only spaces from here to pos, otherwise we search again. + for(size_t i=this->CurrentPositionInFile+strlen(word); i < pos; ++i) + { + if(buffer[i] != ' ' && buffer[i] != '\t') + { + return this->ExtractValueFromCpuInfoFile(buffer, word, pos2); + } + } return buffer.substr(pos+2,pos2-pos-2); } } @@ -3073,7 +3085,7 @@ int SystemInformationImplementation::RetreiveInformationFromCpuInfoFile() this->NumberOfLogicalCPU = atoi(cpucount.c_str()); #endif // gotta have one, and if this is 0 then we get a / by 0n - // beter to have a bad answer than a crash + // better to have a bad answer than a crash if(this->NumberOfPhysicalCPU <= 0) { this->NumberOfPhysicalCPU = 1; @@ -3082,32 +3094,83 @@ int SystemInformationImplementation::RetreiveInformationFromCpuInfoFile() this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical= this->NumberOfLogicalCPU/this->NumberOfPhysicalCPU; - // CPU speed (checking only the first proc + // CPU speed (checking only the first processor) kwsys_stl::string CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer,"cpu MHz"); this->CPUSpeedInMHz = static_cast<float>(atof(CPUSpeed.c_str())); // Chip family - this->ChipID.Family = atoi(this->ExtractValueFromCpuInfoFile(buffer,"cpu family").c_str()); + kwsys_stl::string familyStr = + this->ExtractValueFromCpuInfoFile(buffer,"cpu family"); + if(familyStr.empty()) + { + familyStr = this->ExtractValueFromCpuInfoFile(buffer,"CPU architecture"); + } + this->ChipID.Family = atoi(familyStr.c_str()); // Chip Vendor this->ChipID.Vendor = this->ExtractValueFromCpuInfoFile(buffer,"vendor_id"); - this->FindManufacturer(); + this->FindManufacturer(familyStr); + + // second try for setting family + if (this->ChipID.Family == 0 && this->ChipManufacturer == HP) + { + if (familyStr == "PA-RISC 1.1a") + this->ChipID.Family = 0x11a; + else if (familyStr == "PA-RISC 2.0") + this->ChipID.Family = 0x200; + // If you really get CMake to work on a machine not belonging to + // any of those families I owe you a dinner if you get it to + // contribute nightly builds regularly. + } // Chip Model this->ChipID.Model = atoi(this->ExtractValueFromCpuInfoFile(buffer,"model").c_str()); - this->RetrieveClassicalCPUIdentity(); + if(!this->RetrieveClassicalCPUIdentity()) + { + // Some platforms (e.g. PA-RISC) tell us their CPU name here. + // Note: x86 does not. + kwsys_stl::string cpuname = this->ExtractValueFromCpuInfoFile(buffer,"cpu"); + if(!cpuname.empty()) + { + this->ChipID.ProcessorName = cpuname; + } + } + + // Chip revision + kwsys_stl::string cpurev = this->ExtractValueFromCpuInfoFile(buffer,"stepping"); + if(cpurev.empty()) + { + cpurev = this->ExtractValueFromCpuInfoFile(buffer,"CPU revision"); + } + this->ChipID.Revision = atoi(cpurev.c_str()); // Chip Model Name this->ChipID.ModelName = this->ExtractValueFromCpuInfoFile(buffer,"model name").c_str(); // L1 Cache size - kwsys_stl::string cacheSize = this->ExtractValueFromCpuInfoFile(buffer,"cache size"); - pos = cacheSize.find(" KB"); - if(pos!=cacheSize.npos) + // Different architectures may show different names for the caches. + // Sum up everything we find. + kwsys_stl::vector<const char*> cachename; + cachename.clear(); + + cachename.push_back("cache size"); // e.g. x86 + cachename.push_back("I-cache"); // e.g. PA-RISC + cachename.push_back("D-cache"); // e.g. PA-RISC + + this->Features.L1CacheSize = 0; + for (size_t index = 0; index < cachename.size(); index ++) { - cacheSize = cacheSize.substr(0,pos); + kwsys_stl::string cacheSize = this->ExtractValueFromCpuInfoFile(buffer,cachename[index]); + if (!cacheSize.empty()) + { + pos = cacheSize.find(" KB"); + if(pos!=cacheSize.npos) + { + cacheSize = cacheSize.substr(0,pos); + } + this->Features.L1CacheSize += atoi(cacheSize.c_str()); + } } - this->Features.L1CacheSize = atoi(cacheSize.c_str()); return 1; } diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index 085d988..1054d65 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -2754,9 +2754,15 @@ kwsys_stl::string SystemTools::GetRealPath(const char* path) bool SystemTools::FileIsDirectory(const char* name) { + size_t length = strlen(name); + if (length == 0) + { + return false; + } + // Remove any trailing slash from the name. char buffer[KWSYS_SYSTEMTOOLS_MAXPATH]; - size_t last = strlen(name)-1; + size_t last = length-1; if(last > 0 && (name[last] == '/' || name[last] == '\\') && strcmp(name, "/") !=0) { diff --git a/Source/kwsys/testProcess.c b/Source/kwsys/testProcess.c index 877002a..ec561ea 100644 --- a/Source/kwsys/testProcess.c +++ b/Source/kwsys/testProcess.c @@ -82,6 +82,14 @@ int test3(int argc, const char* argv[]) int test4(int argc, const char* argv[]) { + /* Prepare a pointer to an invalid address. Don't use null, because + dereferencing null is undefined behaviour and compilers are free to + do whatever they want. ex: Clang will warn at compile time, or even + optimize away the write. We hope to 'outsmart' them by using + 'volatile' and a slightly larger address, based on a runtime value. */ + volatile int* invalidAddress = 0; + invalidAddress += argc?1:2; + #if defined(_WIN32) /* Avoid error diagnostic popups since we are crashing on purpose. */ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); @@ -94,11 +102,8 @@ int test4(int argc, const char* argv[]) fprintf(stderr, "Output before crash on stderr from crash test.\n"); fflush(stdout); fflush(stderr); -#if defined(__clang__) - *(int*)1 = 0; /* Clang warns about 0-ptr; undefined behavior. */ -#else - *(int*)0 = 0; -#endif + /* Provoke deliberate crash by writing to the invalid address. */ + *invalidAddress = 0; fprintf(stdout, "Output after crash on stdout from crash test.\n"); fprintf(stderr, "Output after crash on stderr from crash test.\n"); return 0; diff --git a/Source/kwsys/testRegistry.cxx b/Source/kwsys/testRegistry.cxx deleted file mode 100644 index 7e9b0d4..0000000 --- a/Source/kwsys/testRegistry.cxx +++ /dev/null @@ -1,109 +0,0 @@ -/*============================================================================ - KWSys - Kitware System Library - Copyright 2000-2009 Kitware, Inc., Insight Software Consortium - - Distributed under the OSI-approved BSD License (the "License"); - see accompanying file Copyright.txt for details. - - This software is distributed WITHOUT ANY WARRANTY; without even the - implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the License for more information. -============================================================================*/ -#include "kwsysPrivate.h" - -#include KWSYS_HEADER(Registry.hxx) -#include KWSYS_HEADER(ios/iostream) -#include <string.h> - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "Registry.hxx.in" -# include "kwsys_ios_iostream.h.in" -#endif - -#define IFT(x,res) if ( !x ) \ - { \ - res = 1; \ - kwsys_ios::cout << "Error in: " << #x << kwsys_ios::endl; \ - } -#define IFNT(x,res) if ( x ) \ - { \ - res = 1; \ - kwsys_ios::cout << "Error in: " << #x << kwsys_ios::endl; \ - } - -#define CHE(x,y,res) if ( x && strcmp(x,y) ) \ - { \ - res = 1; \ - kwsys_ios::cout << "Error, " << x << " != " << y << kwsys_ios::endl; \ - } - -int testRegistry(int, char*[]) -{ - int res = 0; - - kwsys::Registry reg; - reg.SetTopLevel("TestRegistry"); - - IFT(reg.SetValue("TestSubkey", "TestKey1", "Test Value 1"), res); - IFT(reg.SetValue("TestSubkey1", "TestKey2", "Test Value 2"), res); - IFT(reg.SetValue("TestSubkey", "TestKey3", "Test Value 3"), res); - IFT(reg.SetValue("TestSubkey2", "TestKey4", "Test Value 4"), res); - - const char *buffer; - IFT(reg.ReadValue("TestSubkey", "TestKey1", &buffer), res); - CHE(buffer, "Test Value 1", res); - IFT(reg.ReadValue("TestSubkey1", "TestKey2", &buffer), res); - CHE(buffer, "Test Value 2", res); - IFT(reg.ReadValue("TestSubkey", "TestKey3", &buffer), res); - CHE(buffer, "Test Value 3", res); - IFT(reg.ReadValue("TestSubkey2", "TestKey4", &buffer), res); - CHE(buffer, "Test Value 4", res); - - IFT(reg.SetValue("TestSubkey", "TestKey1", "New Test Value 1"), res); - IFT(reg.SetValue("TestSubkey1", "TestKey2", "New Test Value 2"), res); - IFT(reg.SetValue("TestSubkey", "TestKey3", "New Test Value 3"), res); - IFT(reg.SetValue("TestSubkey2", "TestKey4", "New Test Value 4"), res); - - IFT(reg.ReadValue("TestSubkey", "TestKey1", &buffer), res); - CHE(buffer, "New Test Value 1", res); - IFT(reg.ReadValue("TestSubkey1", "TestKey2", &buffer), res); - CHE(buffer, "New Test Value 2", res); - IFT(reg.ReadValue("TestSubkey", "TestKey3", &buffer), res); - CHE(buffer, "New Test Value 3", res); - IFT(reg.ReadValue("TestSubkey2", "TestKey4", &buffer), res); - CHE(buffer, "New Test Value 4", res); - - IFT( reg.DeleteValue("TestSubkey", "TestKey1"), res); - IFNT(reg.ReadValue( "TestSubkey", "TestKey1", &buffer), res); - IFT( reg.DeleteValue("TestSubkey1", "TestKey2"), res); - IFNT(reg.ReadValue( "TestSubkey1", "TestKey2", &buffer), res); - IFT( reg.DeleteValue("TestSubkey", "TestKey3"), res); - IFNT(reg.ReadValue( "TestSubkey", "TestKey3", &buffer), res); - IFT( reg.DeleteValue("TestSubkey2", "TestKey4"), res); - IFNT(reg.ReadValue( "TestSubkey2", "TestKey5", &buffer), res); - - const char* longStringWithNewLines = "Value with embedded CR and LF characters CR='\015' LF='\012' CRLF='\015\012'"; - IFT(reg.SetValue("TestSubkeyWithVeryLongInFactSoLongItsHardToImagineAnybodyWouldReallyDoItLongName", "TestKey1", longStringWithNewLines), res); - IFT(reg.ReadValue("TestSubkeyWithVeryLongInFactSoLongItsHardToImagineAnybodyWouldReallyDoItLongName", "TestKey1", &buffer), res); - CHE(buffer, longStringWithNewLines, res); - IFT(reg.DeleteValue("TestSubkeyWithVeryLongInFactSoLongItsHardToImagineAnybodyWouldReallyDoItLongName", "TestKey1"), res); - IFNT(reg.ReadValue("TestSubkeyWithVeryLongInFactSoLongItsHardToImagineAnybodyWouldReallyDoItLongName", "TestKey1", &buffer), res); - - IFT(reg.SetValue("TestSubkeyWith = EqualSignChar", "TestKey = 1", "Some value"), res); - IFT(reg.ReadValue("TestSubkeyWith = EqualSignChar", "TestKey = 1", &buffer), res); - CHE(buffer, "Some value", res); - IFT(reg.DeleteValue("TestSubkeyWith = EqualSignChar", "TestKey = 1"), res); - IFNT(reg.ReadValue("TestSubkeyWith = EqualSignChar", "TestKey = 1", &buffer), res); - - if ( res ) - { - kwsys_ios::cout << "Test failed" << kwsys_ios::endl; - } - else - { - kwsys_ios::cout << "Test passed" << kwsys_ios::endl; - } - return res; -} diff --git a/Source/kwsys/testSystemInformation.cxx b/Source/kwsys/testSystemInformation.cxx index 41fcf38..cfd7ce2 100644 --- a/Source/kwsys/testSystemInformation.cxx +++ b/Source/kwsys/testSystemInformation.cxx @@ -66,6 +66,7 @@ int testSystemInformation(int, char*[]) printMethod(info, GetFamilyID); printMethod(info, GetModelID); printMethod(info, GetExtendedProcessorName); + printMethod(info, GetSteppingCode); printMethod(info, GetProcessorSerialNumber); printMethod2(info, GetProcessorCacheSize, "KB"); printMethod(info, GetLogicalProcessorsPerPhysical); |