diff options
Diffstat (limited to 'Source')
84 files changed, 4053 insertions, 2899 deletions
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 18c4835..73e99df 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 20121210) +set(CMake_VERSION_TWEAK 20130118) #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/CPack/cmCPackGeneratorFactory.cxx b/Source/CPack/cmCPackGeneratorFactory.cxx index 55776739..b36c2a2 100644 --- a/Source/CPack/cmCPackGeneratorFactory.cxx +++ b/Source/CPack/cmCPackGeneratorFactory.cxx @@ -33,7 +33,7 @@ #endif #if !defined(_WIN32) \ - && !defined(__QNXNTO__) && !defined(__BEOS__) + && !defined(__QNXNTO__) && !defined(__BEOS__) && !defined(__HAIKU__) # include "cmCPackDebGenerator.h" # include "cmCPackRPMGenerator.h" #endif @@ -126,7 +126,7 @@ cmCPackGeneratorFactory::cmCPackGeneratorFactory() } #endif #if !defined(_WIN32) \ - && !defined(__QNXNTO__) && !defined(__BEOS__) + && !defined(__QNXNTO__) && !defined(__BEOS__) && !defined(__HAIKU__) if (cmCPackDebGenerator::CanGenerate()) { this->RegisterGenerator("DEB", "Debian packages", diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index 4d1e249..20aded2 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -1097,10 +1097,17 @@ int cmCTestCoverageHandler::HandleGCovCoverage( } else { - cmCTestLog(this->CTest, ERROR_MESSAGE, - "Unknown gcov output line: [" << line->c_str() << "]" << std::endl); - cont->Error ++; - //abort(); + // gcov 4.7 can have output lines saying "No executable lines" and + // "Removing 'filename.gcov'"... Don't log those as "errors." + if(*line != "No executable lines" && + !cmSystemTools::StringStartsWith(line->c_str(), "Removing ")) + { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Unknown gcov output line: [" << line->c_str() << "]" + << std::endl); + cont->Error ++; + //abort(); + } } 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/cmBootstrapCommands.cxx b/Source/cmBootstrapCommands.cxx index 9097a74..e3a2ad4 100644 --- a/Source/cmBootstrapCommands.cxx +++ b/Source/cmBootstrapCommands.cxx @@ -89,6 +89,7 @@ #include "cmStringCommand.cxx" #include "cmSubdirCommand.cxx" #include "cmTargetLinkLibrariesCommand.cxx" +#include "cmTimestamp.cxx" #include "cmTryCompileCommand.cxx" #include "cmTryRunCommand.cxx" #include "cmUnsetCommand.cxx" diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index bb6f3f2..322a6a2 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -53,7 +53,7 @@ #include <cm_zlib.h> #include <cmsys/Base64.h> -#if defined(__BEOS__) && !defined(__HAIKU__) +#if defined(__BEOS__) #include <be/kernel/OS.h> /* disable_debugger() API. */ #endif 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/cmCommands.cxx b/Source/cmCommands.cxx index 49ed967..227b226 100644 --- a/Source/cmCommands.cxx +++ b/Source/cmCommands.cxx @@ -28,6 +28,9 @@ #include "cmRemoveDefinitionsCommand.cxx" #include "cmSourceGroupCommand.cxx" #include "cmSubdirDependsCommand.cxx" +#include "cmTargetCompileDefinitionsCommand.cxx" +#include "cmTargetIncludeDirectoriesCommand.cxx" +#include "cmTargetPropCommandBase.cxx" #include "cmUseMangledMesaCommand.cxx" #include "cmUtilitySourceCommand.cxx" #include "cmVariableRequiresCommand.cxx" @@ -66,6 +69,8 @@ void GetPredefinedCommands(std::list<cmCommand*>& commands.push_back(new cmRemoveDefinitionsCommand); commands.push_back(new cmSourceGroupCommand); commands.push_back(new cmSubdirDependsCommand); + commands.push_back(new cmTargetIncludeDirectoriesCommand); + commands.push_back(new cmTargetCompileDefinitionsCommand); commands.push_back(new cmUseMangledMesaCommand); commands.push_back(new cmUtilitySourceCommand); commands.push_back(new cmVariableRequiresCommand); diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index 055aab0..dec2b54 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -172,10 +172,11 @@ satisfy dependencies. //---------------------------------------------------------------------------- cmComputeLinkDepends -::cmComputeLinkDepends(cmTarget* target, const char* config) +::cmComputeLinkDepends(cmTarget* target, const char* config, cmTarget* head) { // Store context information. this->Target = target; + this->HeadTarget = head; this->Makefile = this->Target->GetMakefile(); this->LocalGenerator = this->Makefile->GetLocalGenerator(); this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator(); @@ -352,7 +353,7 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe) { // Follow the target dependencies. if(cmTarget::LinkInterface const* iface = - entry.Target->GetLinkInterface(this->Config)) + entry.Target->GetLinkInterface(this->Config, this->HeadTarget)) { // This target provides its own link interface information. this->AddLinkEntries(depender_index, iface->Libraries); @@ -444,7 +445,7 @@ void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep) if(entry.Target) { if(cmTarget::LinkInterface const* iface = - entry.Target->GetLinkInterface(this->Config)) + entry.Target->GetLinkInterface(this->Config, this->HeadTarget)) { // Follow public and private dependencies transitively. this->FollowSharedDeps(index, iface, true); @@ -533,7 +534,7 @@ void cmComputeLinkDepends::AddDirectLinkEntries() { // Add direct link dependencies in this configuration. cmTarget::LinkImplementation const* impl = - this->Target->GetLinkImplementation(this->Config); + this->Target->GetLinkImplementation(this->Config, this->HeadTarget); this->AddLinkEntries(-1, impl->Libraries); for(std::vector<std::string>::const_iterator wi = impl->WrongConfigLibraries.begin(); @@ -944,7 +945,7 @@ int cmComputeLinkDepends::ComputeComponentCount(NodeList const& nl) if(cmTarget* target = this->EntryList[*ni].Target) { if(cmTarget::LinkInterface const* iface = - target->GetLinkInterface(this->Config)) + target->GetLinkInterface(this->Config, this->HeadTarget)) { if(iface->Multiplicity > count) { diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h index 80a0454..1d5d1b9 100644 --- a/Source/cmComputeLinkDepends.h +++ b/Source/cmComputeLinkDepends.h @@ -32,7 +32,7 @@ class cmake; class cmComputeLinkDepends { public: - cmComputeLinkDepends(cmTarget* target, const char* config); + cmComputeLinkDepends(cmTarget* target, const char* config, cmTarget *head); ~cmComputeLinkDepends(); // Basic information about each link item. @@ -59,6 +59,7 @@ private: // Context information. cmTarget* Target; + cmTarget* HeadTarget; cmMakefile* Makefile; cmLocalGenerator* LocalGenerator; cmGlobalGenerator* GlobalGenerator; diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index d8ffb5e..08cdcb5 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -239,10 +239,12 @@ because this need be done only for shared libraries without soname-s. //---------------------------------------------------------------------------- cmComputeLinkInformation -::cmComputeLinkInformation(cmTarget* target, const char* config) +::cmComputeLinkInformation(cmTarget* target, const char* config, + cmTarget *headTarget) { // Store context information. this->Target = target; + this->HeadTarget = headTarget; this->Makefile = this->Target->GetMakefile(); this->LocalGenerator = this->Makefile->GetLocalGenerator(); this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator(); @@ -265,7 +267,7 @@ cmComputeLinkInformation this->OrderDependentRPath = 0; // Get the language used for linking this target. - this->LinkLanguage = this->Target->GetLinkerLanguage(config); + this->LinkLanguage = this->Target->GetLinkerLanguage(config, headTarget); if(!this->LinkLanguage) { // The Compute method will do nothing, so skip the rest of the @@ -503,7 +505,7 @@ bool cmComputeLinkInformation::Compute() } // Compute the ordered link line items. - cmComputeLinkDepends cld(this->Target, this->Config); + cmComputeLinkDepends cld(this->Target, this->Config, this->HeadTarget); cld.SetOldLinkDirMode(this->OldLinkDirMode); cmComputeLinkDepends::EntryVector const& linkEntries = cld.Compute(); @@ -569,7 +571,8 @@ bool cmComputeLinkInformation::Compute() void cmComputeLinkInformation::AddImplicitLinkInfo() { // The link closure lists all languages whose implicit info is needed. - cmTarget::LinkClosure const* lc=this->Target->GetLinkClosure(this->Config); + cmTarget::LinkClosure const* lc=this->Target->GetLinkClosure(this->Config, + this->HeadTarget); for(std::vector<std::string>::const_iterator li = lc->Languages.begin(); li != lc->Languages.end(); ++li) { @@ -1376,10 +1379,31 @@ void cmComputeLinkInformation::DropDirectoryItem(std::string const& item) //---------------------------------------------------------------------------- void cmComputeLinkInformation::ComputeFrameworkInfo() { - // Avoid adding system framework paths. See "man ld" on OS X. - this->FrameworkPathsEmmitted.insert("/Library/Frameworks"); - this->FrameworkPathsEmmitted.insert("/Network/Library/Frameworks"); - this->FrameworkPathsEmmitted.insert("/System/Library/Frameworks"); + // Avoid adding implicit framework paths. + std::vector<std::string> implicitDirVec; + + // Get platform-wide implicit directories. + if(const char* implicitLinks = this->Makefile->GetDefinition + ("CMAKE_PLATFORM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES")) + { + cmSystemTools::ExpandListArgument(implicitLinks, implicitDirVec); + } + + // Get language-specific implicit directories. + std::string implicitDirVar = "CMAKE_"; + implicitDirVar += this->LinkLanguage; + implicitDirVar += "_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES"; + if(const char* implicitDirs = + this->Makefile->GetDefinition(implicitDirVar.c_str())) + { + cmSystemTools::ExpandListArgument(implicitDirs, implicitDirVec); + } + + for(std::vector<std::string>::const_iterator i = implicitDirVec.begin(); + i != implicitDirVec.end(); ++i) + { + this->FrameworkPathsEmmitted.insert(*i); + } // Regular expression to extract a framework path and name. this->SplitFramework.compile("(.*)/(.*)\\.framework$"); diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index e0078af..1a76922 100644 --- a/Source/cmComputeLinkInformation.h +++ b/Source/cmComputeLinkInformation.h @@ -29,7 +29,8 @@ class cmOrderDirectories; class cmComputeLinkInformation { public: - cmComputeLinkInformation(cmTarget* target, const char* config); + cmComputeLinkInformation(cmTarget* target, const char* config, + cmTarget* headTarget); ~cmComputeLinkInformation(); bool Compute(); @@ -74,6 +75,7 @@ private: // Context information. cmTarget* Target; + cmTarget* HeadTarget; cmMakefile* Makefile; cmLocalGenerator* LocalGenerator; cmGlobalGenerator* GlobalGenerator; diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx index ab77c6b..8fd95b9 100644 --- a/Source/cmComputeTargetDepends.cxx +++ b/Source/cmComputeTargetDepends.cxx @@ -200,20 +200,48 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) // Get the depender. cmTarget* depender = this->Targets[depender_index]; - // Loop over all targets linked directly. + // Loop over all targets linked directly in all configs. + // We need to make targets depend on the union of all config-specific + // dependencies in all targets, because the generated build-systems can't + // deal with config-specific dependencies. { - cmTarget::LinkLibraryVectorType const& tlibs = - depender->GetOriginalLinkLibraries(); std::set<cmStdString> emitted; + { + std::vector<std::string> tlibs; + depender->GetDirectLinkLibraries(0, tlibs, depender); // A target should not depend on itself. emitted.insert(depender->GetName()); - for(cmTarget::LinkLibraryVectorType::const_iterator lib = tlibs.begin(); + for(std::vector<std::string>::const_iterator lib = tlibs.begin(); lib != tlibs.end(); ++lib) { // Don't emit the same library twice for this target. - if(emitted.insert(lib->first).second) + if(emitted.insert(*lib).second) { - this->AddTargetDepend(depender_index, lib->first.c_str(), true); + this->AddTargetDepend(depender_index, lib->c_str(), true); + this->AddInterfaceDepends(depender_index, lib->c_str(), + true, emitted); + } + } + } + std::vector<std::string> configs; + depender->GetMakefile()->GetConfigurations(configs); + for (std::vector<std::string>::const_iterator it = configs.begin(); + it != configs.end(); ++it) + { + std::vector<std::string> tlibs; + depender->GetDirectLinkLibraries(it->c_str(), tlibs, depender); + // A target should not depend on itself. + emitted.insert(depender->GetName()); + for(std::vector<std::string>::const_iterator lib = tlibs.begin(); + lib != tlibs.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); + this->AddInterfaceDepends(depender_index, lib->c_str(), + true, emitted); + } } } } @@ -237,6 +265,64 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) } //---------------------------------------------------------------------------- +void cmComputeTargetDepends::AddInterfaceDepends(int depender_index, + cmTarget* dependee, + const char *config, + std::set<cmStdString> &emitted) +{ + cmTarget* depender = this->Targets[depender_index]; + if(cmTarget::LinkInterface const* iface = + dependee->GetLinkInterface(config, depender)) + { + 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..fa21907 100644 --- a/Source/cmDocumentGeneratorExpressions.h +++ b/Source/cmDocumentGeneratorExpressions.h @@ -26,7 +26,18 @@ "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_DEFINED:tgt> = '1' if tgt is a target, else '0'\n" \ " $<TARGET_LINKER_FILE:tgt> = file used to link (.a, .lib, .so)\n" \ " $<TARGET_SONAME_FILE:tgt> = file with soname (.so.3)\n" \ "where \"tgt\" is the name of a target. " \ diff --git a/Source/cmDocumentVariables.cxx b/Source/cmDocumentVariables.cxx index 55d70f8..08b3ef1 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 @@ -1138,6 +1147,17 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "Variables that Control the Build"); cm->DefineProperty + ("CMAKE_BUILD_INTERFACE_INCLUDES", cmProperty::VARIABLE, + "Automatically add the current source- and build directories " + "to the INTERFACE_INCLUDE_DIRECTORIES.", + "If this variable is enabled, CMake automatically adds for each " + "target ${CMAKE_CURRENT_SOURCE_DIR} and ${CMAKE_CURRENT_BINARY_DIR} " + "to the INTERFACE_INCLUDE_DIRECTORIES." + "By default CMAKE_BUILD_INTERFACE_INCLUDES is OFF.", + false, + "Variables that Control the Build"); + + cm->DefineProperty ("CMAKE_INSTALL_RPATH", cmProperty::VARIABLE, "The rpath to use for installed targets.", "A semicolon-separated list specifying the rpath " @@ -1621,6 +1641,23 @@ 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." + "\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 + ("CMAKE_<LANG>_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES", cmProperty::VARIABLE, + "Implicit linker framework search path detected for language <LANG>.", + "These paths are implicit linker framework search directories for " + "the compiler's language. " + "CMake automatically detects these directories for each language and " "reports the results in this variable.", false, "Variables for Languages"); diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index cd6a7ab..61e130d 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,14 +49,45 @@ 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); + + te->AppendBuildInterfaceIncludes(); + + ImportPropertyMap properties; + + this->PopulateInterfaceProperty("INTERFACE_INCLUDE_DIRECTORIES", te, + cmGeneratorExpression::BuildInterface, + properties, missingTargets); + this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", te, + cmGeneratorExpression::BuildInterface, + properties, missingTargets); + this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", + te, properties); + + this->GenerateInterfaceProperties(te, os, properties); + } + // Generate import file content for each configuration. for(std::vector<std::string>::const_iterator ci = this->Configurations.begin(); ci != this->Configurations.end(); ++ci) { - this->GenerateImportConfig(os, ci->c_str()); + this->GenerateImportConfig(os, ci->c_str(), missingTargets); } + this->GenerateMissingTargetsCheckCode(os, missingTargets); + return true; } @@ -73,7 +95,8 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) void cmExportBuildFileGenerator ::GenerateImportTargetsConfig(std::ostream& os, - const char* config, std::string const& suffix) + const char* config, std::string const& suffix, + std::vector<std::string> &missingTargets) { for(std::vector<cmTarget*>::const_iterator tei = this->Exports->begin(); @@ -86,9 +109,12 @@ cmExportBuildFileGenerator if(!properties.empty()) { // Get the rest of the target details. - std::vector<std::string> missingTargets; this->SetImportDetailProperties(config, suffix, target, properties, missingTargets); + this->SetImportLinkInterface(config, suffix, + cmGeneratorExpression::BuildInterface, + target, properties, missingTargets); + // TOOD: PUBLIC_HEADER_LOCATION // This should wait until the build feature propagation stuff @@ -97,7 +123,6 @@ cmExportBuildFileGenerator // properties); // Generate code in the export file. - this->GenerateMissingTargetsCheckCode(os, missingTargets); this->GenerateImportPropertyCode(os, config, target, properties); } } diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h index 726537b..5e1be16 100644 --- a/Source/cmExportBuildFileGenerator.h +++ b/Source/cmExportBuildFileGenerator.h @@ -44,7 +44,8 @@ protected: virtual bool GenerateMainFile(std::ostream& os); virtual void GenerateImportTargetsConfig(std::ostream& os, const char* config, - std::string const& suffix); + std::string const& suffix, + std::vector<std::string> &missingTargets); virtual void HandleMissingTarget(std::string& link_libs, std::vector<std::string>& missingTargets, cmMakefile* mf, diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 3f738cc..4a7c6f9 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -107,7 +107,8 @@ bool cmExportFileGenerator::GenerateImportFile() //---------------------------------------------------------------------------- void cmExportFileGenerator::GenerateImportConfig(std::ostream& os, - const char* config) + const char* config, + std::vector<std::string> &missingTargets) { // Construct the property configuration suffix. std::string suffix = "_"; @@ -121,7 +122,297 @@ void cmExportFileGenerator::GenerateImportConfig(std::ostream& os, } // Generate the per-config target information. - this->GenerateImportTargetsConfig(os, config, suffix); + this->GenerateImportTargetsConfig(os, config, suffix, missingTargets); +} + +//---------------------------------------------------------------------------- +void cmExportFileGenerator::PopulateInterfaceProperty(const char *propName, + cmTarget *target, + ImportPropertyMap &properties) +{ + const char *input = target->GetProperty(propName); + if (input) + { + properties[propName] = input; + } +} + +//---------------------------------------------------------------------------- +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"; + } +} + +//---------------------------------------------------------------------------- +bool +cmExportFileGenerator::AddTargetNamespace(std::string &input, + cmTarget* target, + std::vector<std::string> &missingTargets) +{ + cmMakefile *mf = target->GetMakefile(); + + cmTarget *tgt = mf->FindTargetToUse(input.c_str()); + if (!tgt) + { + return false; + } + + if(tgt->IsImported()) + { + return true; + } + if(this->ExportedTargets.find(tgt) != this->ExportedTargets.end()) + { + input = this->Namespace + input; + } + else + { + std::string namespacedTarget; + this->HandleMissingTarget(namespacedTarget, missingTargets, + mf, target, tgt); + if (!namespacedTarget.empty()) + { + input = namespacedTarget; + } + } + return true; +} + +//---------------------------------------------------------------------------- +static bool isGeneratorExpression(const std::string &lib) +{ + const std::string::size_type openpos = lib.find("$<"); + return (openpos != std::string::npos) + && (lib.find(">", openpos) != std::string::npos); +} + +//---------------------------------------------------------------------------- +void +cmExportFileGenerator::ResolveTargetsInGeneratorExpressions( + std::string &input, + cmTarget* target, + std::vector<std::string> &missingTargets, + FreeTargetsReplace replace) +{ + if (replace == NoReplaceFreeTargets) + { + this->ResolveTargetsInGeneratorExpression(input, target, missingTargets); + return; + } + std::vector<std::string> parts; + cmGeneratorExpression::Split(input, parts); + + std::string sep; + input = ""; + for(std::vector<std::string>::iterator li = parts.begin(); + li != parts.end(); ++li) + { + if (!isGeneratorExpression(*li)) + { + this->AddTargetNamespace(*li, target, missingTargets); + } + else + { + this->ResolveTargetsInGeneratorExpression( + *li, + target, + missingTargets); + } + input += sep + *li; + sep = ";"; + } +} + +//---------------------------------------------------------------------------- +void +cmExportFileGenerator::ResolveTargetsInGeneratorExpression( + 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; + } + + std::string targetName = input.substr(nameStartPos, + commaPos - nameStartPos); + + if (!this->AddTargetNamespace(targetName, target, missingTargets)) + { + errorString = "$<TARGET_PROPERTY:" + targetName + ",prop> requires " + "its first parameter to be a reachable target."; + break; + } + input.replace(nameStartPos, commaPos - nameStartPos, targetName); + lastPos = pos + targetName.size(); + } + 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"; + break; + } + std::string targetName = input.substr(nameStartPos, + endPos - nameStartPos); + if(targetName.find("$<") != input.npos) + { + errorString = "$<TARGET_NAME:...> requires its parameter to be a " + "literal."; + break; + } + if (!this->AddTargetNamespace(targetName, target, missingTargets)) + { + errorString = "$<TARGET_NAME:...> requires its parameter to be a " + "reachable target."; + break; + } + input.replace(pos, endPos - pos + 1, targetName); + lastPos = endPos; + } + if (!errorString.empty()) + { + mf->IssueMessage(cmake::FATAL_ERROR, errorString); + } +} + +//---------------------------------------------------------------------------- +void +cmExportFileGenerator +::SetImportLinkInterface(const char* config, std::string const& suffix, + cmGeneratorExpression::PreprocessContext preprocessRule, + cmTarget* target, ImportPropertyMap& properties, + std::vector<std::string>& missingTargets) +{ + // Add the transitive link dependencies for this configuration. + cmTarget::LinkInterface const* iface = target->GetLinkInterface(config, + target); + if (!iface) + { + return; + } + + if (iface->ImplementationIsInterface) + { + this->SetImportLinkProperty(suffix, target, + "IMPORTED_LINK_INTERFACE_LIBRARIES", + iface->Libraries, properties, missingTargets); + return; + } + + const char *propContent; + + if (const char *prop_suffixed = target->GetProperty( + ("LINK_INTERFACE_LIBRARIES" + suffix).c_str())) + { + propContent = prop_suffixed; + } + else if (const char *prop = target->GetProperty( + "LINK_INTERFACE_LIBRARIES")) + { + propContent = prop; + } + else + { + return; + } + + if (!*propContent) + { + properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix] = ""; + return; + } + + std::string prepro = cmGeneratorExpression::Preprocess(propContent, + preprocessRule); + if (!prepro.empty()) + { + this->ResolveTargetsInGeneratorExpressions(prepro, target, + missingTargets, + ReplaceFreeTargets); + properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix] = prepro; + } } //---------------------------------------------------------------------------- @@ -162,14 +453,13 @@ cmExportFileGenerator } // Add the transitive link dependencies for this configuration. - if(cmTarget::LinkInterface const* iface = target->GetLinkInterface(config)) + if(cmTarget::LinkInterface const* iface = target->GetLinkInterface(config, + target)) { this->SetImportLinkProperty(suffix, target, "IMPORTED_LINK_INTERFACE_LANGUAGES", iface->Languages, properties, missingTargets); - this->SetImportLinkProperty(suffix, target, - "IMPORTED_LINK_INTERFACE_LIBRARIES", - iface->Libraries, properties, missingTargets); + this->SetImportLinkProperty(suffix, target, "IMPORTED_LINK_DEPENDENT_LIBRARIES", iface->SharedDeps, properties, missingTargets); @@ -201,9 +491,6 @@ cmExportFileGenerator return; } - // Get the makefile in which to lookup target information. - cmMakefile* mf = target->GetMakefile(); - // Construct the property value. std::string link_libs; const char* sep = ""; @@ -214,33 +501,9 @@ cmExportFileGenerator link_libs += sep; sep = ";"; - // Append this entry. - if(cmTarget* tgt = mf->FindTargetToUse(li->c_str())) - { - // This is a target. - if(tgt->IsImported()) - { - // The target is imported (and therefore is not in the - // export). Append the raw name. - link_libs += *li; - } - else if(this->ExportedTargets.find(tgt) != this->ExportedTargets.end()) - { - // The target is in the export. Append it with the export - // namespace. - link_libs += this->Namespace; - link_libs += *li; - } - else - { - this->HandleMissingTarget(link_libs, missingTargets, mf, target, tgt); - } - } - else - { - // Append the raw name. - link_libs += *li; - } + std::string temp = *li; + this->AddTargetNamespace(temp, target, missingTargets); + link_libs += temp; } // Store the property. @@ -415,21 +678,29 @@ cmExportFileGenerator void cmExportFileGenerator::GenerateMissingTargetsCheckCode(std::ostream& os, const std::vector<std::string>& missingTargets) { + if (missingTargets.empty()) + { + return; + } os << "# Make sure the targets which have been exported in some other \n" "# export set exist.\n"; + std::set<std::string> emitted; for(unsigned int i=0; i<missingTargets.size(); ++i) { - os << "IF(NOT TARGET \"" << missingTargets[i] << "\" )\n" - << " IF(CMAKE_FIND_PACKAGE_NAME)\n" - << " SET( ${CMAKE_FIND_PACKAGE_NAME}_FOUND FALSE)\n" - << " SET( ${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE " - << "\"Required imported target \\\"" << missingTargets[i] - << "\\\" not found ! \")\n" - << " ELSE()\n" - << " MESSAGE(FATAL_ERROR \"Required imported target \\\"" - << missingTargets[i] << "\\\" not found ! \")\n" - << " ENDIF()\n" - << "ENDIF()\n"; + if (emitted.insert(missingTargets[i]).second) + { + os << "IF(NOT TARGET \"" << missingTargets[i] << "\" )\n" + << " IF(CMAKE_FIND_PACKAGE_NAME)\n" + << " SET( ${CMAKE_FIND_PACKAGE_NAME}_FOUND FALSE)\n" + << " SET( ${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE " + << "\"Required imported target \\\"" << missingTargets[i] + << "\\\" not found ! \")\n" + << " ELSE()\n" + << " MESSAGE(FATAL_ERROR \"Required imported target \\\"" + << missingTargets[i] << "\\\" not found ! \")\n" + << " ENDIF()\n" + << "ENDIF()\n"; + } } os << "\n"; } diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index 4a75c52..eb3f3c3 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. @@ -46,7 +47,8 @@ protected: // Generate per-configuration target information to the given output // stream. - void GenerateImportConfig(std::ostream& os, const char* config); + void GenerateImportConfig(std::ostream& os, const char* config, + std::vector<std::string> &missingTargets); // Methods to implement export file code generation. void GenerateImportHeaderCode(std::ostream& os, const char* config = 0); @@ -84,7 +86,8 @@ protected: /** Each subclass knows where the target files are located. */ virtual void GenerateImportTargetsConfig(std::ostream& os, const char* config, - std::string const& suffix) = 0; + std::string const& suffix, + std::vector<std::string> &missingTargets) = 0; /** Each subclass knows how to deal with a target that is missing from an * export set. */ @@ -93,6 +96,30 @@ protected: cmMakefile* mf, cmTarget* depender, cmTarget* dependee) = 0; + void PopulateInterfaceProperty(const char *, + cmTarget *target, + cmGeneratorExpression::PreprocessContext, + ImportPropertyMap &properties, + std::vector<std::string> &missingTargets); + void PopulateInterfaceProperty(const char *propName, cmTarget *target, + ImportPropertyMap &properties); + void GenerateInterfaceProperties(cmTarget *target, std::ostream& os, + const ImportPropertyMap &properties); + + void SetImportLinkInterface(const char* config, std::string const& suffix, + cmGeneratorExpression::PreprocessContext preprocessRule, + cmTarget* target, ImportPropertyMap& properties, + std::vector<std::string>& missingTargets); + + enum FreeTargetsReplace { + ReplaceFreeTargets, + NoReplaceFreeTargets + }; + + void ResolveTargetsInGeneratorExpressions(std::string &input, + cmTarget* target, + std::vector<std::string> &missingTargets, + FreeTargetsReplace replace = NoReplaceFreeTargets); // The namespace in which the exports are placed in the generated file. std::string Namespace; @@ -109,6 +136,20 @@ 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); + + bool AddTargetNamespace(std::string &input, cmTarget* target, + std::vector<std::string> &missingTargets); + + void ResolveTargetsInGeneratorExpression(std::string &input, + cmTarget* target, + std::vector<std::string> &missingTargets); }; #endif diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 6ba7d9f..965f63d 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,36 @@ 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->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", + te, properties); + + this->GenerateInterfaceProperties(te, os, properties); + } + + // 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" @@ -85,23 +106,29 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) << "ENDFOREACH(f)\n" << "\n"; + this->GenerateImportedFileCheckLoop(os); + // Generate an import file for each configuration. bool result = true; for(std::vector<std::string>::const_iterator ci = this->Configurations.begin(); ci != this->Configurations.end(); ++ci) { - if(!this->GenerateImportFileConfig(ci->c_str())) + if(!this->GenerateImportFileConfig(ci->c_str(), missingTargets)) { result = false; } } + + this->GenerateMissingTargetsCheckCode(os, missingTargets); + return result; } //---------------------------------------------------------------------------- bool -cmExportInstallFileGenerator::GenerateImportFileConfig(const char* config) +cmExportInstallFileGenerator::GenerateImportFileConfig(const char* config, + std::vector<std::string> &missingTargets) { // Skip configurations not enabled for this export. if(!this->IEGen->InstallsForConfig(config)) @@ -141,7 +168,7 @@ cmExportInstallFileGenerator::GenerateImportFileConfig(const char* config) this->GenerateImportHeaderCode(os, config); // Generate the per-config target information. - this->GenerateImportConfig(os, config); + this->GenerateImportConfig(os, config, missingTargets); // End with the import file footer. this->GenerateImportFooterCode(os); @@ -156,7 +183,8 @@ cmExportInstallFileGenerator::GenerateImportFileConfig(const char* config) void cmExportInstallFileGenerator ::GenerateImportTargetsConfig(std::ostream& os, - const char* config, std::string const& suffix) + const char* config, std::string const& suffix, + std::vector<std::string> &missingTargets) { // Add code to compute the installation prefix relative to the // import file location. @@ -205,10 +233,13 @@ cmExportInstallFileGenerator if(!properties.empty()) { // Get the rest of the target details. - std::vector<std::string> missingTargets; this->SetImportDetailProperties(config, suffix, te->Target, properties, missingTargets); + this->SetImportLinkInterface(config, suffix, + cmGeneratorExpression::InstallInterface, + te->Target, properties, missingTargets); + // TOOD: PUBLIC_HEADER_LOCATION // This should wait until the build feature propagation stuff // is done. Then this can be a propagated include directory. @@ -216,15 +247,12 @@ cmExportInstallFileGenerator // properties); // Generate code in the export file. - this->GenerateMissingTargetsCheckCode(os, missingTargets); this->GenerateImportPropertyCode(os, config, te->Target, properties); this->GenerateImportedFileChecksCode(os, te->Target, properties, importedLocations); } } - this->GenerateImportedFileCheckLoop(os); - // Cleanup the import prefix variable. if(!this->ImportPrefix.empty()) { diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h index e719ecc..e187749 100644 --- a/Source/cmExportInstallFileGenerator.h +++ b/Source/cmExportInstallFileGenerator.h @@ -56,7 +56,8 @@ protected: virtual bool GenerateMainFile(std::ostream& os); virtual void GenerateImportTargetsConfig(std::ostream& os, const char* config, - std::string const& suffix); + std::string const& suffix, + std::vector<std::string> &missingTargets); virtual void HandleMissingTarget(std::string& link_libs, std::vector<std::string>& missingTargets, cmMakefile* mf, @@ -72,7 +73,8 @@ protected: /** Generate a per-configuration file for the targets. */ - bool GenerateImportFileConfig(const char* config); + bool GenerateImportFileConfig(const char* config, + std::vector<std::string> &missingTargets); /** Fill in properties indicating installed file locations. */ void SetImportLocationProperty(const char* config, 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/cmFileCommand.cxx b/Source/cmFileCommand.cxx index b877f3c..0cdbb82 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -17,6 +17,8 @@ #include "cmFileTimeComparison.h" #include "cmCryptoHash.h" +#include "cmTimestamp.h" + #if defined(CMAKE_BUILD_WITH_CMAKE) #include "cm_curl.h" #endif @@ -161,6 +163,10 @@ bool cmFileCommand { return this->HandleCMakePathCommand(args, true); } + else if ( subCommand == "TIMESTAMP" ) + { + return this->HandleTimestampCommand(args); + } std::string e = "does not recognize sub-command "+subCommand; this->SetError(e.c_str()); @@ -3241,3 +3247,54 @@ cmFileCommand::HandleUploadCommand(std::vector<std::string> const& args) return false; #endif } + +//---------------------------------------------------------------------------- +bool cmFileCommand::HandleTimestampCommand( + std::vector<std::string> const& args) +{ + if(args.size() < 3) + { + this->SetError("sub-command TIMESTAMP requires at least two arguments."); + return false; + } + else if(args.size() > 5) + { + this->SetError("sub-command TIMESTAMP takes at most four arguments."); + return false; + } + + unsigned int argsIndex = 1; + + const std::string& filename = args[argsIndex++]; + + const std::string& outputVariable = args[argsIndex++]; + + std::string formatString; + if(args.size() > argsIndex && args[argsIndex] != "UTC") + { + formatString = args[argsIndex++]; + } + + bool utcFlag = false; + if(args.size() > argsIndex) + { + if(args[argsIndex] == "UTC") + { + utcFlag = true; + } + else + { + std::string e = " TIMESTAMP sub-command does not recognize option " + + args[argsIndex] + "."; + this->SetError(e.c_str()); + return false; + } + } + + cmTimestamp timestamp; + std::string result = timestamp.FileModificationTime( + filename.c_str(), formatString, utcFlag); + this->Makefile->AddDefinition(outputVariable.c_str(), result.c_str()); + + return true; +} diff --git a/Source/cmFileCommand.h b/Source/cmFileCommand.h index a0862ec..5973fa7 100644 --- a/Source/cmFileCommand.h +++ b/Source/cmFileCommand.h @@ -87,6 +87,7 @@ public: " [TLS_VERIFY on|off] [TLS_CAINFO file])\n" " file(UPLOAD filename url [INACTIVITY_TIMEOUT timeout]\n" " [TIMEOUT timeout] [STATUS status] [LOG log] [SHOW_PROGRESS])\n" + " file(TIMESTAMP filename variable [<format string>] [UTC])\n" "WRITE will write a message into a file called 'filename'. It " "overwrites the file if it already exists, and creates the file " "if it does not exist. (If the file is a build input, use " @@ -200,6 +201,12 @@ public: "If SHOW_PROGRESS is specified, progress information will be printed " "as status messages until the operation is complete." "\n" + "TIMESTAMP will write a string representation of " + "the modification time of filename to variable.\n" + "Should the command be unable to obtain a timestamp " + "variable will be set to the empty string \"\".\n" + "See documentation of the string TIMESTAMP sub-command for more details." + "\n" "The file() command also provides COPY and INSTALL signatures:\n" " file(<COPY|INSTALL> files... DESTINATION <dir>\n" " [FILE_PERMISSIONS permissions...]\n" @@ -260,6 +267,8 @@ protected: bool HandleInstallCommand(std::vector<std::string> const& args); bool HandleDownloadCommand(std::vector<std::string> const& args); bool HandleUploadCommand(std::vector<std::string> const& args); + + bool HandleTimestampCommand(std::vector<std::string> const& args); }; diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index 32bf941..78ae8f2 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,12 +88,21 @@ 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) { - this->Output += (*it)->Evaluate(&context, dagChecker); + const std::string result = (*it)->Evaluate(&context, dagChecker); + this->Output += result; + + for(std::set<cmStdString>::const_iterator + p = context.SeenTargetProperties.begin(); + p != context.SeenTargetProperties.end(); ++p) + { + this->SeenTargetProperties[*p] += result + ";"; + } if (context.HadError) { this->Output = ""; @@ -108,12 +117,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 +147,41 @@ cmCompiledGeneratorExpression::~cmCompiledGeneratorExpression() } } -std::string cmGeneratorExpression::Preprocess(const std::string &input, - PreprocessContext context) +//---------------------------------------------------------------------------- +static std::string stripEmptyListElements(const std::string &input) { - if (context != StripAllGeneratorExpressions) - { - assert(!"cmGeneratorExpression::Preprocess called with invalid args"); - return std::string(); - } + std::string result; + + const char *c = input.c_str(); + bool skipSemiColons = true; + for ( ; *c; ++c) + { + if(c[0] == ';') + { + if(skipSemiColons) + { + continue; + } + skipSemiColons = true; + } + else + { + skipSemiColons = false; + } + result += *c; + } + + if (!result.empty() && *(result.end() - 1) == ';') + { + result.resize(result.size() - 1); + } + + return result; +} +//---------------------------------------------------------------------------- +static std::string stripAllGeneratorExpressions(const std::string &input) +{ std::string result; std::string::size_type pos = 0; std::string::size_type lastPos = pos; @@ -176,5 +218,144 @@ std::string cmGeneratorExpression::Preprocess(const std::string &input, lastPos = pos; } result += input.substr(lastPos); - return result; + return stripEmptyListElements(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 stripEmptyListElements(result); +} + +//---------------------------------------------------------------------------- +void cmGeneratorExpression::Split(const std::string &input, + std::vector<std::string> &output) +{ + std::string::size_type pos = 0; + std::string::size_type lastPos = pos; + while((pos = input.find("$<", lastPos)) != input.npos) + { + std::string part = input.substr(lastPos, pos - lastPos); + std::string preGenex; + if (!part.empty()) + { + std::string::size_type startPos = input.rfind(";", pos); + if (startPos != pos - 1 && startPos >= lastPos) + { + part = input.substr(lastPos, startPos - lastPos); + preGenex = input.substr(startPos + 1, pos - startPos - 1); + } + cmSystemTools::ExpandListArgument(part.c_str(), output); + } + pos += 2; + 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) + { + break; + } + } + } + for ( ; *c; ++c) + { + // Capture the part after the genex and before the next ';' + if(c[0] == ';') + { + --c; + break; + } + } + const std::string::size_type traversed = (c - cStart) + 1; + output.push_back(preGenex + "$<" + input.substr(pos, traversed)); + pos += traversed; + lastPos = pos; + } + if (lastPos < input.size()) + { + cmSystemTools::ExpandListArgument(input.substr(lastPos), output); + } +} + +//---------------------------------------------------------------------------- +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..8f1aef6 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,22 +46,27 @@ 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, PreprocessContext context); + static void Split(const std::string &input, + std::vector<std::string> &output); + private: cmGeneratorExpression(const cmGeneratorExpression &); void operator=(const cmGeneratorExpression &); cmListFileBacktrace const& Backtrace; - cmCompiledGeneratorExpression *CompiledExpression; }; class cmCompiledGeneratorExpression @@ -67,31 +74,49 @@ 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 { return this->Targets; } + std::map<cmStdString, cmStdString> const& GetSeenTargetProperties() const + { return this->SeenTargetProperties; } + ~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::map<cmStdString, cmStdString> SeenTargetProperties; 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..8e40815a 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,50 @@ 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 struct TargetDefinedNode : public cmGeneratorExpressionNode +{ + TargetDefinedNode() {} + + virtual int NumExpectedParameters() const { return 1; } + + std::string Evaluate(const std::vector<std::string> ¶meters, + cmGeneratorExpressionContext *context, + const GeneratorExpressionContent *, + cmGeneratorExpressionDAGChecker *) const + { + return context->Makefile->FindTargetToUse(parameters.front().c_str()) + ? "1" : "0"; + } +} targetDefinedNode; + +//---------------------------------------------------------------------------- +static const char* targetPropertyTransitiveWhitelist[] = { + "INTERFACE_INCLUDE_DIRECTORIES" + , "INTERFACE_COMPILE_DEFINITIONS" +}; + //---------------------------------------------------------------------------- static const struct TargetPropertyNode : public cmGeneratorExpressionNode { @@ -289,8 +338,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()) @@ -336,6 +396,14 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode } } + if (target == context->HeadTarget) + { + // Keep track of the properties seen while processing. + // The evaluation of the LINK_LIBRARIES generator expressions + // will check this to ensure that properties form a DAG. + context->SeenTargetProperties.insert(propertyName); + } + if (propertyName.empty()) { reportError(context, content->GetOriginalExpression(), @@ -351,24 +419,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 +672,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 +712,14 @@ 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; + else if (identifier == "TARGET_DEFINED") + return &targetDefinedNode; return 0; } @@ -682,6 +809,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 +825,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..fb6c7ee 100644 --- a/Source/cmGeneratorExpressionEvaluator.h +++ b/Source/cmGeneratorExpressionEvaluator.h @@ -24,9 +24,12 @@ struct cmGeneratorExpressionContext { cmListFileBacktrace Backtrace; std::set<cmTarget*> Targets; + std::set<cmStdString> SeenTargetProperties; 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/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 0f439e9..d2baf53 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -938,6 +938,11 @@ void cmGlobalGenerator::Generate() (*targets)[tit->first] = tit->second; (*targets)[tit->first].SetMakefile(mf); } + + for ( tit = targets->begin(); tit != targets->end(); ++ tit ) + { + tit->second.AppendBuildInterfaceIncludes(); + } } // Add generator specific helper commands diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 9bbeeaf..0681ce5 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1206,7 +1206,7 @@ void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmTarget& cmtarget) // If the language is compiled as a source trust Xcode to link with it. cmTarget::LinkImplementation const* impl = - cmtarget.GetLinkImplementation("NOCONFIG"); + cmtarget.GetLinkImplementation("NOCONFIG", &cmtarget); for(std::vector<std::string>::const_iterator li = impl->Languages.begin(); li != impl->Languages.end(); ++li) { @@ -1367,16 +1367,18 @@ void cmGlobalXCodeGenerator::CreateCustomCommands(cmXCodeObject* buildPhases, } //---------------------------------------------------------------------------- -// This function removes each occurence of the flag and returns the last one +// This function removes each occurrence of the flag and returns the last one // (i.e., the dominant flag in GCC) std::string cmGlobalXCodeGenerator::ExtractFlag(const char* flag, std::string& flags) { std::string retFlag; - std::string::size_type pos = flags.rfind(flag); + std::string::size_type lastOccurancePos = flags.rfind(flag); bool saved = false; - while(pos != flags.npos) + while(lastOccurancePos != flags.npos) { + //increment pos, we use lastOccurancePos to reduce search space on next inc + std::string::size_type pos = lastOccurancePos; if(pos == 0 || flags[pos-1]==' ') { while(pos < flags.size() && flags[pos] != ' ') @@ -1388,9 +1390,12 @@ std::string cmGlobalXCodeGenerator::ExtractFlag(const char* flag, flags[pos] = ' '; pos++; } - } saved = true; - pos = flags.rfind(flag); + } + //decrement lastOccurancePos while making sure we don't loop around + //and become a very large positive number since size_type is unsigned + lastOccurancePos = lastOccurancePos == 0 ? 0 : lastOccurancePos-1; + lastOccurancePos = flags.rfind(flag,lastOccurancePos); } return retFlag; } @@ -1639,14 +1644,16 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, if(strcmp(lang, "CXX") == 0) { this->CurrentLocalGenerator->AddLanguageFlags(cflags, "C", configName); - this->CurrentLocalGenerator->AddCMP0018Flags(cflags, &target, "C"); + this->CurrentLocalGenerator->AddCMP0018Flags(cflags, &target, + "C", configName); } // Add language-specific flags. this->CurrentLocalGenerator->AddLanguageFlags(flags, lang, configName); // Add shared-library flags if needed. - this->CurrentLocalGenerator->AddCMP0018Flags(flags, &target, lang); + this->CurrentLocalGenerator->AddCMP0018Flags(flags, &target, + lang, configName); } else if(binary) { @@ -1997,15 +2004,20 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, dirs.Add(incpath.c_str()); } } - std::vector<std::string>& frameworks = target.GetFrameworks(); - if(frameworks.size()) + if(target.GetType() != cmTarget::OBJECT_LIBRARY && + target.GetType() != cmTarget::STATIC_LIBRARY) { - for(std::vector<std::string>::iterator fmIt = frameworks.begin(); - fmIt != frameworks.end(); ++fmIt) + // Add framework search paths needed for linking. + if(cmComputeLinkInformation* cli = target.GetLinkInformation(configName)) { - if(emitted.insert(*fmIt).second) + std::vector<std::string> const& fwDirs = cli->GetFrameworkPaths(); + for(std::vector<std::string>::const_iterator fdi = fwDirs.begin(); + fdi != fwDirs.end(); ++fdi) { - fdirs.Add(this->XCodeEscapePath(fmIt->c_str()).c_str()); + if(emitted.insert(*fdi).second) + { + fdirs.Add(this->XCodeEscapePath(fdi->c_str()).c_str()); + } } } } @@ -2691,25 +2703,6 @@ void cmGlobalXCodeGenerator linkDirs.c_str(), configName); } - // add the framework search paths - { - const char* sep = ""; - std::string fdirs; - std::vector<std::string> const& fwDirs = cli.GetFrameworkPaths(); - for(std::vector<std::string>::const_iterator fdi = fwDirs.begin(); - fdi != fwDirs.end(); ++fdi) - { - fdirs += sep; - sep = " "; - fdirs += this->XCodeEscapePath(fdi->c_str()); - } - if(!fdirs.empty()) - { - this->AppendBuildSettingAttribute(target, "FRAMEWORK_SEARCH_PATHS", - fdirs.c_str(), configName); - } - } - // now add the link libraries { std::string linkLibs; diff --git a/Source/cmLoadCommandCommand.cxx b/Source/cmLoadCommandCommand.cxx index 181b922..b2acf06 100644 --- a/Source/cmLoadCommandCommand.cxx +++ b/Source/cmLoadCommandCommand.cxx @@ -224,10 +224,6 @@ cmLoadedCommand::~cmLoadedCommand() bool cmLoadCommandCommand ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &) { - this->Makefile->IssueMessage( - cmake::AUTHOR_WARNING, - "The \"load_command\" command will be removed in CMake 3.0. " - "See command documentation for details."); if(args.size() < 1 ) { return true; diff --git a/Source/cmLoadCommandCommand.h b/Source/cmLoadCommandCommand.h index bcd1831..f0b34ee 100644 --- a/Source/cmLoadCommandCommand.h +++ b/Source/cmLoadCommandCommand.h @@ -47,7 +47,7 @@ public: */ virtual const char* GetTerseDocumentation() const { - return "Deprecated. Use macro() or function() instead."; + return "Load a command into a running CMake."; } /** @@ -56,13 +56,6 @@ public: virtual const char* GetFullDocumentation() const { return - "This command will be removed in CMake 3.0. " - "It works only when the target architecture matches the " - "running CMake binary. " - "Use macro() or function() to add commands. " - "Use execute_process() to run advanced computations " - "in external processes." - "\n" " load_command(COMMAND_NAME <loc1> [loc2 ...])\n" "The given locations are searched for a library whose name is " "cmCOMMAND_NAME. If found, it is loaded as a module and the command " @@ -74,12 +67,6 @@ public: "Otherwise the variable will not be set."; } - /** This command is kept for compatibility with older CMake versions. */ - virtual bool IsDiscouraged() const - { - return true; - } - cmTypeMacro(cmLoadCommandCommand, cmCommand); }; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 6d396b3..ecf6b41 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1329,7 +1329,9 @@ std::string cmLocalGenerator::GetIncludeFlags( void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, cmGeneratorTarget* target, const char* lang, - const char *config) + const char *config, + bool stripImplicitInclDirs + ) { // Need to decide whether to automatically include the source and // binary directories at the beginning of the include path. @@ -1404,18 +1406,21 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, return; } - // Load implicit include directories for this language. - std::string impDirVar = "CMAKE_"; - impDirVar += lang; - impDirVar += "_IMPLICIT_INCLUDE_DIRECTORIES"; - if(const char* value = this->Makefile->GetDefinition(impDirVar.c_str())) + if (stripImplicitInclDirs) { - std::vector<std::string> impDirVec; - cmSystemTools::ExpandListArgument(value, impDirVec); - for(std::vector<std::string>::const_iterator i = impDirVec.begin(); - i != impDirVec.end(); ++i) + // Load implicit include directories for this language. + std::string impDirVar = "CMAKE_"; + impDirVar += lang; + impDirVar += "_IMPLICIT_INCLUDE_DIRECTORIES"; + if(const char* value = this->Makefile->GetDefinition(impDirVar.c_str())) { - emitted.insert(*i); + std::vector<std::string> impDirVec; + cmSystemTools::ExpandListArgument(value, impDirVec); + for(std::vector<std::string>::const_iterator i = impDirVec.begin(); + i != impDirVec.end(); ++i) + { + emitted.insert(*i); + } } } @@ -1703,7 +1708,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries, for(std::vector<std::string>::const_iterator fdi = fwDirs.begin(); fdi != fwDirs.end(); ++fdi) { - frameworkPath = " -F"; + frameworkPath += "-F"; frameworkPath += this->Convert(fdi->c_str(), NONE, SHELL, false); frameworkPath += " "; } @@ -1979,7 +1984,8 @@ void cmLocalGenerator::AddSharedFlags(std::string& flags, //---------------------------------------------------------------------------- void cmLocalGenerator::AddCMP0018Flags(std::string &flags, cmTarget* target, - std::string const& lang) + std::string const& lang, + const char *config) { int targetType = target->GetType(); @@ -1992,8 +1998,18 @@ void cmLocalGenerator::AddCMP0018Flags(std::string &flags, cmTarget* target, } else { - // Add position independendent flags, if needed. - if (target->GetPropertyAsBool("POSITION_INDEPENDENT_CODE")) + if (target->GetType() == cmTarget::OBJECT_LIBRARY) + { + if (target->GetPropertyAsBool("POSITION_INDEPENDENT_CODE")) + { + this->AddPositionIndependentFlags(flags, lang, targetType); + } + return; + } + + if (target->GetLinkInterfaceDependentBoolProperty( + "POSITION_INDEPENDENT_CODE", + config)) { this->AddPositionIndependentFlags(flags, lang, targetType); } diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index bd58218..b2ff0c4 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -142,7 +142,7 @@ public: void AddLanguageFlags(std::string& flags, const char* lang, const char* config); void AddCMP0018Flags(std::string &flags, cmTarget* target, - std::string const& lang); + std::string const& lang, const char *config); void AddConfigVariableFlags(std::string& flags, const char* var, const char* config); ///! Append flags to a string. @@ -212,7 +212,8 @@ public: /** Get the include flags for the current makefile and language. */ void GetIncludeDirectories(std::vector<std::string>& dirs, cmGeneratorTarget* target, - const char* lang = "C", const char *config = 0); + const char* lang = "C", const char *config = 0, + bool stripImplicitInclDirs = true); /** Compute the language used to compile the given source file. */ const char* GetSourceFileLanguage(const cmSourceFile& source); diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 8498d72..b432986 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -814,7 +814,7 @@ bool cmMakefile::NeedBackwardsCompatibility(unsigned int major, void cmMakefile::FinalPass() { // do all the variable expansions here - this->ExpandVariables(); + this->ExpandVariablesCMP0019(); // give all the commands a chance to do something // after the file has been parsed before generation @@ -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); } } @@ -2122,21 +2093,33 @@ void cmMakefile::AddExtraDirectory(const char* dir) this->AuxSourceDirectories.push_back(dir); } +static bool mightExpandVariablesCMP0019(const char* s) +{ + return s && *s && strstr(s,"${") && strchr(s,'}'); +} -// expand CMAKE_BINARY_DIR and CMAKE_SOURCE_DIR in the -// include and library directories. - -void cmMakefile::ExpandVariables() +void cmMakefile::ExpandVariablesCMP0019() { - // Now expand variables in the include and link strings + // Drop this ancient compatibility behavior with a policy. + cmPolicies::PolicyStatus pol = this->GetPolicyStatus(cmPolicies::CMP0019); + if(pol != cmPolicies::OLD && pol != cmPolicies::WARN) + { + return; + } + cmOStringStream w; - // May not be necessary anymore... But may need a policy for strict - // backwards compatibility const char *includeDirs = this->GetProperty("INCLUDE_DIRECTORIES"); - if (includeDirs) + if(mightExpandVariablesCMP0019(includeDirs)) { std::string dirs = includeDirs; this->ExpandVariablesInString(dirs, true, true); + if(pol == cmPolicies::WARN && dirs != includeDirs) + { + w << "Evaluated directory INCLUDE_DIRECTORIES\n" + << " " << includeDirs << "\n" + << "as\n" + << " " << dirs << "\n"; + } this->SetProperty("INCLUDE_DIRECTORIES", dirs.c_str()); } @@ -2146,10 +2129,17 @@ void cmMakefile::ExpandVariables() { cmTarget &t = l->second; includeDirs = t.GetProperty("INCLUDE_DIRECTORIES"); - if (includeDirs) + if(mightExpandVariablesCMP0019(includeDirs)) { std::string dirs = includeDirs; this->ExpandVariablesInString(dirs, true, true); + if(pol == cmPolicies::WARN && dirs != includeDirs) + { + w << "Evaluated target " << t.GetName() << " INCLUDE_DIRECTORIES\n" + << " " << includeDirs << "\n" + << "as\n" + << " " << dirs << "\n"; + } t.SetProperty("INCLUDE_DIRECTORIES", dirs.c_str()); } } @@ -2157,13 +2147,45 @@ void cmMakefile::ExpandVariables() for(std::vector<std::string>::iterator d = this->LinkDirectories.begin(); d != this->LinkDirectories.end(); ++d) { - this->ExpandVariablesInString(*d, true, true); + if(mightExpandVariablesCMP0019(d->c_str())) + { + std::string orig = *d; + this->ExpandVariablesInString(*d, true, true); + if(pol == cmPolicies::WARN && *d != orig) + { + w << "Evaluated link directory\n" + << " " << orig << "\n" + << "as\n" + << " " << *d << "\n"; + } + } } for(cmTarget::LinkLibraryVectorType::iterator l = this->LinkLibraries.begin(); l != this->LinkLibraries.end(); ++l) { - this->ExpandVariablesInString(l->first, true, true); + if(mightExpandVariablesCMP0019(l->first.c_str())) + { + std::string orig = l->first; + this->ExpandVariablesInString(l->first, true, true); + if(pol == cmPolicies::WARN && l->first != orig) + { + w << "Evaluated link library\n" + << " " << orig << "\n" + << "as\n" + << " " << l->first << "\n"; + } + } + } + + if(!w.str().empty()) + { + cmOStringStream m; + m << this->GetPolicies()->GetPolicyWarning(cmPolicies::CMP0019) + << "\n" + << "The following variable evaluations were encountered:\n" + << w.str(); + this->IssueMessage(cmake::AUTHOR_WARNING, m.str()); } } @@ -3400,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" ) { @@ -3431,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; @@ -3542,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 70cfe54..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" @@ -693,7 +694,7 @@ public: /** * Expand variables in the makefiles ivars such as link directories etc */ - void ExpandVariables(); + void ExpandVariablesCMP0019(); /** * Replace variables and #cmakedefine lines in the given string. @@ -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/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 2b89c79..64fcfce 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -268,7 +268,8 @@ std::string cmMakefileTargetGenerator::GetFlags(const std::string &l) this->AddFortranFlags(flags); } - this->LocalGenerator->AddCMP0018Flags(flags, this->Target, lang); + this->LocalGenerator->AddCMP0018Flags(flags, this->Target, + lang, this->ConfigName); // Add include directory flags. this->AddIncludeFlags(flags, lang); @@ -1550,10 +1551,10 @@ std::string cmMakefileTargetGenerator::GetFrameworkFlags() this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget, "C", config); - std::vector<std::string>::iterator i; // check all include directories for frameworks as this // will already have added a -F for the framework - for(i = includes.begin(); i != includes.end(); ++i) + for(std::vector<std::string>::iterator i = includes.begin(); + i != includes.end(); ++i) { if(this->Target->NameResolvesToFramework(i->c_str())) { @@ -1565,17 +1566,21 @@ std::string cmMakefileTargetGenerator::GetFrameworkFlags() } std::string flags; - std::vector<std::string>& frameworks = this->Target->GetFrameworks(); - for(i = frameworks.begin(); - i != frameworks.end(); ++i) + const char* cfg = this->LocalGenerator->ConfigurationName.c_str(); + if(cmComputeLinkInformation* cli = this->Target->GetLinkInformation(cfg)) { - if(emitted.insert(*i).second) + std::vector<std::string> const& frameworks = cli->GetFrameworkPaths(); + for(std::vector<std::string>::const_iterator i = frameworks.begin(); + i != frameworks.end(); ++i) { - flags += "-F"; - flags += this->Convert(i->c_str(), - cmLocalGenerator::START_OUTPUT, - cmLocalGenerator::SHELL, true); - flags += " "; + if(emitted.insert(*i).second) + { + flags += "-F"; + flags += this->Convert(i->c_str(), + cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::SHELL, true); + flags += " "; + } } } return flags; diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 15842e4..0f484da 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -147,7 +147,8 @@ cmNinjaTargetGenerator::ComputeFlagsForObject(cmSourceFile *source, // Add shared-library flags if needed. this->LocalGenerator->AddCMP0018Flags(flags, this->Target, - language.c_str()); + language.c_str(), + this->GetConfigName()); // Add include directory flags. { diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx index 6aef502..eb7d666 100644 --- a/Source/cmPolicies.cxx +++ b/Source/cmPolicies.cxx @@ -491,6 +491,23 @@ cmPolicies::cmPolicies() "CMAKE_SHARED_LIBRARY_<Lang>_FLAGS whether it is modified or not and " "honor the POSITION_INDEPENDENT_CODE target property.", 2,8,9,0, cmPolicies::WARN); + + this->DefinePolicy( + CMP0019, "CMP0019", + "Do not re-expand variables in include and link information.", + "CMake 2.8.10 and lower re-evaluated values given to the " + "include_directories, link_directories, and link_libraries " + "commands to expand any leftover variable references at the " + "end of the configuration step. " + "This was for strict compatibility with VERY early CMake versions " + "because all variable references are now normally evaluated during " + "CMake language processing. " + "CMake 2.8.11 and higher prefer to skip the extra evaluation." + "\n" + "The OLD behavior for this policy is to re-evaluate the values " + "for strict compatibility. " + "The NEW behavior for this policy is to leave the values untouched.", + 2,8,11,0, cmPolicies::WARN); } cmPolicies::~cmPolicies() diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 6932565..d7d945c 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -68,6 +68,7 @@ public: CMP0018, ///< Ignore language flags for shared libs, and adhere to /// POSITION_INDEPENDENT_CODE property and *_COMPILE_OPTIONS_PI{E,C} /// instead. + CMP0019, ///< No variable re-expansion in include and link info /** \brief Always the last entry. * diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 83688dd..bf034cf 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -212,36 +212,11 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target) } - const char* qtIncDir = 0; - const char* qtCoreIncDir = 0; - - // check whether ${QT_INCLUDE_DIR} is part of the implicit include dirs, - // see http://public.kitware.com/Bug/view.php?id=13667 - bool qtIncludeDirMayHaveBeenRemoved = false; - if (makefile->IsSet("QT_INCLUDE_DIR")) - { - qtIncDir = makefile->GetDefinition("QT_INCLUDE_DIR"); - std::string s = - makefile->GetSafeDefinition("CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES"); - std::vector<std::string> implIncDirs; - cmSystemTools::ExpandListArgument(s, implIncDirs); - if (std::find(implIncDirs.begin(), implIncDirs.end(),std::string(qtIncDir)) - != implIncDirs.end()) - { - qtIncludeDirMayHaveBeenRemoved = true; - if (makefile->IsSet("QT_QTCORE_INCLUDE_DIR")) - { - qtCoreIncDir = makefile->GetDefinition("QT_QTCORE_INCLUDE_DIR"); - } - } - } - - bool haveQtCoreIncDir = false; - bool haveQtIncDir = false; - std::vector<std::string> includeDirs; cmGeneratorTarget gtgt(target); - localGen->GetIncludeDirectories(includeDirs, >gt, "CXX"); + // Get the include dirs for this target, without stripping the implicit + // include dirs off, see http://public.kitware.com/Bug/view.php?id=13667 + localGen->GetIncludeDirectories(includeDirs, >gt, "CXX", 0, false); std::string _moc_incs = ""; const char* sep = ""; for(std::vector<std::string>::const_iterator incDirIt = includeDirs.begin(); @@ -251,37 +226,6 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target) _moc_incs += sep; sep = ";"; _moc_incs += *incDirIt; - - if (qtIncludeDirMayHaveBeenRemoved && qtCoreIncDir && qtIncDir) // #13667 - { - if (*incDirIt == qtIncDir) - { - haveQtIncDir = true; - qtIncludeDirMayHaveBeenRemoved = false; // it's here, i.e. not removed - } - if (*incDirIt == qtCoreIncDir) - { - haveQtCoreIncDir = true; - } - } - } - - // Some projects (kdelibs, phonon) query the compiler for its default - // include search dirs, and add those to - // CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES. - // These may include e.g./usr/lib/qt/include . This is typically also part - // of ${QT_INCLUDES}. If this directory is then contained in the implicit - // include dirs, it is removed from the include dirs returned from the - // target above. So we add ${QT_INCLUDE_DIR} manually for moc if we detected - // that ${QT_QTCORE_INCLUDE_DIR} is among the include dirs (there shouldn't - // be a way to use Qt4 without using ${QT_QTCORE_INCLUDE_DIR} I think. - // See #13646 and #13667. - if (qtIncludeDirMayHaveBeenRemoved && qtCoreIncDir && qtIncDir - && (haveQtCoreIncDir == true) && (haveQtIncDir == false)) - { - _moc_incs += sep; - sep = ";"; - _moc_incs += qtIncDir; } const char* tmp = target->GetProperty("COMPILE_DEFINITIONS"); diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index 0193dc9..e49edd8 100644 --- a/Source/cmStringCommand.cxx +++ b/Source/cmStringCommand.cxx @@ -19,6 +19,8 @@ #include <ctype.h> #include <time.h> +#include <cmTimestamp.h> + //---------------------------------------------------------------------------- bool cmStringCommand ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &) @@ -87,6 +89,10 @@ bool cmStringCommand { return this->HandleFindCommand(args); } + else if(subCommand == "TIMESTAMP") + { + return this->HandleTimestampCommand(args); + } std::string e = "does not recognize sub-command "+subCommand; this->SetError(e.c_str()); @@ -879,3 +885,51 @@ bool cmStringCommand this->Makefile->AddDefinition(variableName.c_str(), &*result.begin()); return true; } + +//---------------------------------------------------------------------------- +bool cmStringCommand +::HandleTimestampCommand(std::vector<std::string> const& args) +{ + if(args.size() < 2) + { + this->SetError("sub-command TIMESTAMP requires at least one argument."); + return false; + } + else if(args.size() > 4) + { + this->SetError("sub-command TIMESTAMP takes at most three arguments."); + return false; + } + + unsigned int argsIndex = 1; + + const std::string &outputVariable = args[argsIndex++]; + + std::string formatString; + if(args.size() > argsIndex && args[argsIndex] != "UTC") + { + formatString = args[argsIndex++]; + } + + bool utcFlag = false; + if(args.size() > argsIndex) + { + if(args[argsIndex] == "UTC") + { + utcFlag = true; + } + else + { + std::string e = " TIMESTAMP sub-command does not recognize option " + + args[argsIndex] + "."; + this->SetError(e.c_str()); + return false; + } + } + + cmTimestamp timestamp; + std::string result = timestamp.CurrentTime(formatString, utcFlag); + this->Makefile->AddDefinition(outputVariable.c_str(), result.c_str()); + + return true; +} diff --git a/Source/cmStringCommand.h b/Source/cmStringCommand.h index 728b1bc..4423a90 100644 --- a/Source/cmStringCommand.h +++ b/Source/cmStringCommand.h @@ -93,6 +93,7 @@ public: " string(RANDOM [LENGTH <length>] [ALPHABET <alphabet>]\n" " [RANDOM_SEED <seed>] <output variable>)\n" " string(FIND <string> <substring> <output variable> [REVERSE])\n" + " string(TIMESTAMP <output variable> [<format string>] [UTC])\n" "REGEX MATCH will match the regular expression once and store the " "match in the output variable.\n" "REGEX MATCHALL will match the regular expression as many times as " @@ -142,7 +143,33 @@ public: " () Saves a matched subexpression, which can be referenced \n" " in the REGEX REPLACE operation. Additionally it is saved\n" " by all regular expression-related commands, including \n" - " e.g. if( MATCHES ), in the variables CMAKE_MATCH_(0..9)."; + " e.g. if( MATCHES ), in the variables CMAKE_MATCH_(0..9).\n" + "TIMESTAMP will write a string representation of " + "the current date and/or time to the output variable.\n" + "Should the command be unable to obtain a timestamp " + "the output variable will be set to the empty string \"\".\n" + "The optional UTC flag requests the current date/time " + "representation to be in Coordinated Universal Time (UTC) " + "rather than local time.\n" + "The optional <format string> may contain the following " + "format specifiers: \n" + " %d The day of the current month (01-31).\n" + " %H The hour on a 24-hour clock (00-23).\n" + " %I The hour on a 12-hour clock (01-12).\n" + " %j The day of the current year (001-366).\n" + " %m The month of the current year (01-12).\n" + " %M The minute of the current hour (00-59).\n" + " %S The second of the current minute.\n" + " 60 represents a leap second. (00-60)\n" + " %U The week number of the current year (00-53).\n" + " %w The day of the current week. 0 is Sunday. (0-6)\n" + " %y The last two digits of the current year (00-99)\n" + " %Y The current year. \n" + "Unknown format specifiers will be ignored " + "and copied to the output as-is.\n" + "If no explicit <format string> is given it will default to:\n" + " %Y-%m-%dT%H:%M:%S for local time.\n" + " %Y-%m-%dT%H:%M:%SZ for UTC."; } cmTypeMacro(cmStringCommand, cmCommand); @@ -165,6 +192,7 @@ protected: bool HandleStripCommand(std::vector<std::string> const& args); bool HandleRandomCommand(std::vector<std::string> const& args); bool HandleFindCommand(std::vector<std::string> const& args); + bool HandleTimestampCommand(std::vector<std::string> const& args); class RegexReplacement { diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index be20464..815da40 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> @@ -71,6 +72,11 @@ struct cmTarget::ImportInfo cmTarget::LinkInterface LinkInterface; }; +struct TargetConfigPair : public std::pair<cmTarget*, std::string> { + TargetConfigPair(cmTarget* tgt, const std::string &config) + : std::pair<cmTarget*, std::string>(tgt, config) {} +}; + //---------------------------------------------------------------------------- class cmTargetInternals { @@ -99,25 +105,37 @@ public: OptionalLinkInterface(): Exists(false) {} bool Exists; }; - typedef std::map<cmStdString, OptionalLinkInterface> LinkInterfaceMapType; + typedef std::map<TargetConfigPair, OptionalLinkInterface> + LinkInterfaceMapType; LinkInterfaceMapType LinkInterfaceMap; typedef std::map<cmStdString, cmTarget::OutputInfo> OutputInfoMapType; OutputInfoMapType OutputInfoMap; - typedef std::map<cmStdString, cmTarget::ImportInfo> ImportInfoMapType; + typedef std::map<TargetConfigPair, cmTarget::ImportInfo> + ImportInfoMapType; ImportInfoMapType ImportInfoMap; // Cache link implementation computation from each configuration. - typedef std::map<cmStdString, cmTarget::LinkImplementation> LinkImplMapType; + typedef std::map<TargetConfigPair, + cmTarget::LinkImplementation> LinkImplMapType; LinkImplMapType LinkImplMap; - typedef std::map<cmStdString, cmTarget::LinkClosure> LinkClosureMapType; + typedef std::map<TargetConfigPair, cmTarget::LinkClosure> + LinkClosureMapType; LinkClosureMapType LinkClosureMap; 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; }; //---------------------------------------------------------------------------- @@ -132,6 +150,7 @@ cmTarget::cmTarget() this->DLLPlatform = false; this->IsApple = false; this->IsImportedTarget = false; + this->BuildInterfaceIncludesAppended = false; } //---------------------------------------------------------------------------- @@ -502,6 +521,22 @@ void cmTarget::DefineProperties(cmake *cm) "undefined behavior."); cm->DefineProperty + ("LINK_LIBRARIES", cmProperty::TARGET, + "List of direct link dependencies.", + "This property specifies the list of libraries or targets which will be " + "used for linking. " + "In addition to accepting values from the target_link_libraries " + "command, values may be set directly on any target using the " + "set_property command. " + "\n" + "The target property values are used by the generators to set " + "the link libraries for the compiler. " + "See also the target_link_libraries command.\n" + "Contents of LINK_LIBRARIES may use \"generator expressions\" with " + "the syntax \"$<...>\". " + CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS); + + cm->DefineProperty ("INCLUDE_DIRECTORIES", cmProperty::TARGET, "List of preprocessor include file search directories.", "This property specifies the list of directories given " @@ -711,6 +746,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 " @@ -822,6 +879,33 @@ void cmTarget::DefineProperties(cmake *cm) "created."); cm->DefineProperty + ("INTERFACE_POSITION_INDEPENDENT_CODE", cmProperty::TARGET, + "Whether consumers need to create a position-independent target", + "The INTERFACE_POSITION_INDEPENDENT_CODE property informs consumers of " + "this target whether they must set their POSITION_INDEPENDENT_CODE " + "property to ON. If this property is set to ON, then the " + "POSITION_INDEPENDENT_CODE property on all consumers will be set to " + "ON. Similarly, if this property is set to OFF, then the " + "POSITION_INDEPENDENT_CODE property on all consumers will be set to " + "OFF. If this property is undefined, then consumers will determine " + "their POSITION_INDEPENDENT_CODE property by other means. Consumers " + "must ensure that the targets that they link to have a consistent " + "requirement for their INTERFACE_POSITION_INDEPENDENT_CODE property."); + + cm->DefineProperty + ("COMPATIBLE_INTERFACE_BOOL", cmProperty::TARGET, + "Properties which must be compatible with their link interface", + "The COMPATIBLE_INTERFACE_BOOL property may contain a list of properties" + "for this target which must be consistent when evaluated as a boolean " + "in the INTERFACE of all linked dependencies. For example, if a " + "property \"FOO\" appears in the list, then the \"INTERFACE_FOO\" " + "property content in all dependencies must be consistent with each " + "other, and with the \"FOO\" property in this target. " + "Consistency in this sense has the meaning that if the property is set," + "then it must have the same boolean value as all others, and if the " + "property is not set, then it is ignored."); + + cm->DefineProperty ("POST_INSTALL_SCRIPT", cmProperty::TARGET, "Deprecated install support.", "The PRE_INSTALL_SCRIPT and POST_INSTALL_SCRIPT properties are the " @@ -1392,8 +1476,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 +1818,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) { @@ -2093,23 +2184,74 @@ bool cmTarget::NameResolvesToFramework(const std::string& libname) } //---------------------------------------------------------------------------- -bool cmTarget::AddFramework(const std::string& libname, LinkLibraryType) +void cmTarget::GetDirectLinkLibraries(const char *config, + std::vector<std::string> &libs, cmTarget *head) { - if(this->NameResolvesToFramework(libname.c_str())) + const char *prop = this->GetProperty("LINK_LIBRARIES"); + if (prop) + { + cmListFileBacktrace lfbt; + cmGeneratorExpression ge(lfbt); + const cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop); + + cmGeneratorExpressionDAGChecker dagChecker(lfbt, + this->GetName(), + "LINK_LIBRARIES", 0, 0); + cmSystemTools::ExpandListArgument(cge->Evaluate(this->Makefile, + config, + false, + head, + &dagChecker), + libs); + + this->AddLinkDependentTargetsForProperties(cge->GetSeenTargetProperties()); + } +} + +//---------------------------------------------------------------------------- +std::string cmTarget::GetDebugGeneratorExpressions(const std::string &value, + cmTarget::LinkLibraryType llt) +{ + if (llt == GENERAL) + { + return value; + } + + // Get the list of configurations considered to be DEBUG. + std::vector<std::string> const& debugConfigs = + this->Makefile->GetCMakeInstance()->GetDebugConfigs(); + + std::string configString = "$<CONFIG:" + debugConfigs[0] + ">"; + + if (debugConfigs.size() > 1) { - std::string frameworkDir = libname; - frameworkDir += "/../"; - frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir.c_str()); - std::vector<std::string>::iterator i = - std::find(this->Frameworks.begin(), - this->Frameworks.end(), frameworkDir); - if(i == this->Frameworks.end()) + for(std::vector<std::string>::const_iterator + li = debugConfigs.begin() + 1; li != debugConfigs.end(); ++li) { - this->Frameworks.push_back(frameworkDir); + configString += ",$<CONFIG:" + *li + ">"; } - return true; + configString = "$<OR:" + configString + ">"; } - return false; + + if (llt == OPTIMIZED) + { + configString = "$<NOT:" + configString + ">"; + } + return "$<" + configString + ":" + value + ">"; +} + +//---------------------------------------------------------------------------- +static std::string targetNameGenex(const char *lib) +{ + return std::string("$<TARGET_NAME:") + lib + ">"; +} + +//---------------------------------------------------------------------------- +static bool isGeneratorExpression(const std::string &lib) +{ + const std::string::size_type openpos = lib.find("$<"); + return (openpos != std::string::npos) + && (lib.find(">", openpos) != std::string::npos); } //---------------------------------------------------------------------------- @@ -2122,7 +2264,23 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, { return; } - this->AddFramework(lib, llt); + + { + cmTarget *tgt = this->Makefile->FindTargetToUse(lib); + const bool isNonImportedTarget = tgt && !tgt->IsImported(); + + std::string libName = isNonImportedTarget ? targetNameGenex(lib) + : std::string(lib); + this->AppendProperty("LINK_LIBRARIES", + this->GetDebugGeneratorExpressions(libName, + llt).c_str()); + } + + if (isGeneratorExpression(lib)) + { + return; + } + cmTarget::LibraryID tmp; tmp.first = lib; tmp.second = llt; @@ -2466,6 +2624,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) @@ -2473,6 +2645,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); } @@ -2485,11 +2668,124 @@ 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::AppendBuildInterfaceIncludes() +{ + if (this->BuildInterfaceIncludesAppended) + { + return; + } + this->BuildInterfaceIncludesAppended = true; + + if (this->Makefile->IsOn("CMAKE_BUILD_INTERFACE_INCLUDES")) + { + const char *binDir = this->Makefile->GetStartOutputDirectory(); + const char *srcDir = this->Makefile->GetStartDirectory(); + const std::string dirs = std::string(binDir ? binDir : "") + + std::string(binDir ? ";" : "") + + std::string(srcDir ? srcDir : ""); + if (!dirs.empty()) + { + this->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES", + ("$<BUILD_INTERFACE:" + dirs + ">").c_str()); + } + } +} + +//---------------------------------------------------------------------------- +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. @@ -2816,6 +3112,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) { @@ -2875,8 +3189,11 @@ class cmTargetCollectLinkLanguages { public: cmTargetCollectLinkLanguages(cmTarget* target, const char* config, - std::set<cmStdString>& languages): - Config(config), Languages(languages) { this->Visited.insert(target); } + std::set<cmStdString>& languages, + cmTarget* head): + Config(config), Languages(languages), HeadTarget(head) + { this->Visited.insert(target); } + void Visit(cmTarget* target) { if(!target || !this->Visited.insert(target).second) @@ -2885,7 +3202,7 @@ public: } cmTarget::LinkInterface const* iface = - target->GetLinkInterface(this->Config); + target->GetLinkInterface(this->Config, this->HeadTarget); if(!iface) { return; } for(std::vector<std::string>::const_iterator @@ -2904,26 +3221,30 @@ public: private: const char* Config; std::set<cmStdString>& Languages; + cmTarget* HeadTarget; std::set<cmTarget*> Visited; }; //---------------------------------------------------------------------------- -const char* cmTarget::GetLinkerLanguage(const char* config) +const char* cmTarget::GetLinkerLanguage(const char* config, cmTarget *head) { - const char* lang = this->GetLinkClosure(config)->LinkerLanguage.c_str(); + cmTarget *headTarget = head ? head : this; + const char* lang = this->GetLinkClosure(config, headTarget) + ->LinkerLanguage.c_str(); return *lang? lang : 0; } //---------------------------------------------------------------------------- -cmTarget::LinkClosure const* cmTarget::GetLinkClosure(const char* config) +cmTarget::LinkClosure const* cmTarget::GetLinkClosure(const char* config, + cmTarget *head) { - std::string key = cmSystemTools::UpperCase(config? config : ""); + TargetConfigPair key(head, cmSystemTools::UpperCase(config ? config : "")); cmTargetInternals::LinkClosureMapType::iterator i = this->Internal->LinkClosureMap.find(key); if(i == this->Internal->LinkClosureMap.end()) { LinkClosure lc; - this->ComputeLinkClosure(config, lc); + this->ComputeLinkClosure(config, lc, head); cmTargetInternals::LinkClosureMapType::value_type entry(key, lc); i = this->Internal->LinkClosureMap.insert(entry).first; } @@ -2984,11 +3305,12 @@ public: }; //---------------------------------------------------------------------------- -void cmTarget::ComputeLinkClosure(const char* config, LinkClosure& lc) +void cmTarget::ComputeLinkClosure(const char* config, LinkClosure& lc, + cmTarget *head) { // Get languages built in this target. std::set<cmStdString> languages; - LinkImplementation const* impl = this->GetLinkImplementation(config); + LinkImplementation const* impl = this->GetLinkImplementation(config, head); for(std::vector<std::string>::const_iterator li = impl->Languages.begin(); li != impl->Languages.end(); ++li) { @@ -2996,7 +3318,7 @@ void cmTarget::ComputeLinkClosure(const char* config, LinkClosure& lc) } // Add interface languages from linked targets. - cmTargetCollectLinkLanguages cll(this, config, languages); + cmTargetCollectLinkLanguages cll(this, config, languages, head); for(std::vector<std::string>::const_iterator li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li) { @@ -3135,7 +3457,8 @@ bool cmTarget::HasSOName(const char* config) return ((this->GetType() == cmTarget::SHARED_LIBRARY || this->GetType() == cmTarget::MODULE_LIBRARY) && !this->GetPropertyAsBool("NO_SONAME") && - this->Makefile->GetSONameFlag(this->GetLinkerLanguage(config))); + this->Makefile->GetSONameFlag(this->GetLinkerLanguage(config, + this))); } //---------------------------------------------------------------------------- @@ -3144,7 +3467,7 @@ std::string cmTarget::GetSOName(const char* config) if(this->IsImported()) { // Lookup the imported soname. - if(cmTarget::ImportInfo const* info = this->GetImportInfo(config)) + if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, this)) { if(info->NoSOName) { @@ -3181,7 +3504,7 @@ bool cmTarget::IsImportedSharedLibWithoutSOName(const char* config) { if(this->IsImported() && this->GetType() == cmTarget::SHARED_LIBRARY) { - if(cmTarget::ImportInfo const* info = this->GetImportInfo(config)) + if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, this)) { return info->NoSOName; } @@ -3295,7 +3618,7 @@ std::string cmTarget::NormalGetFullPath(const char* config, bool implib, std::string cmTarget::ImportedGetFullPath(const char* config, bool implib) { std::string result; - if(cmTarget::ImportInfo const* info = this->GetImportInfo(config)) + if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, this)) { result = implib? info->ImportLibrary : info->Location; } @@ -3380,7 +3703,7 @@ void cmTarget::GetFullNameInternal(const char* config, const char* suffixVar = this->GetSuffixVariableInternal(implib); // Check for language-specific default prefix and suffix. - if(const char* ll = this->GetLinkerLanguage(config)) + if(const char* ll = this->GetLinkerLanguage(config, this)) { if(!targetSuffix && suffixVar && *suffixVar) { @@ -3751,7 +4074,7 @@ bool cmTarget::NeedRelinkBeforeInstall(const char* config) } // Check for rpath support on this platform. - if(const char* ll = this->GetLinkerLanguage(config)) + if(const char* ll = this->GetLinkerLanguage(config, this)) { std::string flagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_"; flagVar += ll; @@ -4122,6 +4445,171 @@ const char* cmTarget::GetExportMacro() } //---------------------------------------------------------------------------- +void cmTarget::GetLinkDependentTargetsForProperty(const std::string &p, + std::set<std::string> &targets) +{ + const std::map<cmStdString, std::set<std::string> >::const_iterator findIt + = this->LinkDependentProperties.find(p); + if (findIt != this->LinkDependentProperties.end()) + { + targets = findIt->second; + } +} + +//---------------------------------------------------------------------------- +bool cmTarget::IsNullImpliedByLinkLibraries(const std::string &p) +{ + return this->LinkImplicitNullProperties.find(p) + != this->LinkImplicitNullProperties.end(); +} + +//---------------------------------------------------------------------------- +void cmTarget::AddLinkDependentTargetsForProperties( + const std::map<cmStdString, cmStdString> &map) +{ + for (std::map<cmStdString, cmStdString>::const_iterator it = map.begin(); + it != map.end(); ++it) + { + std::vector<std::string> targets; + cmSystemTools::ExpandListArgument(it->second.c_str(), targets); + this->LinkDependentProperties[it->first].insert(targets.begin(), + targets.end()); + if (!this->GetProperty(it->first.c_str())) + { + this->LinkImplicitNullProperties.insert(it->first); + } + } +} + +//---------------------------------------------------------------------------- +bool cmTarget::GetLinkInterfaceDependentBoolProperty(const std::string &p, + const char *config) +{ + bool propContent = this->GetPropertyAsBool(p.c_str()); + const bool explicitlySet = this->GetProperties() + .find(p.c_str()) + != this->GetProperties().end(); + std::set<std::string> dependentTargets; + this->GetLinkDependentTargetsForProperty(p, + dependentTargets); + const bool impliedByUse = + this->IsNullImpliedByLinkLibraries(p); + assert((impliedByUse ^ explicitlySet) + || (!impliedByUse && !explicitlySet)); + + cmComputeLinkInformation *info = this->GetLinkInformation(config); + const cmComputeLinkInformation::ItemVector &deps = info->GetItems(); + bool propInitialized = explicitlySet; + + for(cmComputeLinkInformation::ItemVector::const_iterator li = + deps.begin(); + li != deps.end(); ++li) + { + // An error should be reported if one dependency + // has INTERFACE_POSITION_INDEPENDENT_CODE ON and the other + // has INTERFACE_POSITION_INDEPENDENT_CODE OFF, or if the + // target itself has a POSITION_INDEPENDENT_CODE which disagrees + // with a dependency. + + if (!li->Target) + { + continue; + } + + const bool ifaceIsSet = li->Target->GetProperties() + .find("INTERFACE_" + p) + != li->Target->GetProperties().end(); + const bool ifacePropContent = li->Target->GetPropertyAsBool( + ("INTERFACE_" + p).c_str()); + if (explicitlySet) + { + if (ifaceIsSet) + { + if (propContent != ifacePropContent) + { + cmOStringStream e; + e << "Property " << p << " on target \"" + << this->GetName() << "\" does\nnot match the " + "INTERFACE_" << p << " property requirement\nof " + "dependency \"" << li->Target->GetName() << "\".\n"; + cmSystemTools::Error(e.str().c_str()); + } + else + { + // Agree + continue; + } + } + else + { + // Explicitly set on target and not set in iface. Can't disagree. + continue; + } + } + else if (impliedByUse) + { + if (ifaceIsSet) + { + if (propContent != ifacePropContent) + { + cmOStringStream e; + e << "Property " << p << " on target \"" + << this->GetName() << "\" is\nimplied to be FALSE because it " + "was used to determine the link libraries\nalready. The " + "INTERFACE_" << p << " property on\ndependency \"" + << li->Target->GetName() << "\" is in conflict.\n"; + cmSystemTools::Error(e.str().c_str()); + } + else + { + // Agree + continue; + } + } + else + { + // Implicitly set on target and not set in iface. Can't disagree. + continue; + } + } + else + { + if (ifaceIsSet) + { + if (propInitialized) + { + if (propContent != ifacePropContent) + { + cmOStringStream e; + e << "The INTERFACE_" << p << " property of \"" + << li->Target->GetName() << "\" does\nnot agree with the value " + "of " << p << " already determined\nfor \"" + << this->GetName() << "\".\n"; + cmSystemTools::Error(e.str().c_str()); + } + else + { + // Agree. + continue; + } + } + else + { + propContent = ifacePropContent; + propInitialized = true; + } + } + else + { + // Not set. Nothing to agree on. + continue; + } + } + } + return propContent; +} + +//---------------------------------------------------------------------------- void cmTarget::GetLanguages(std::set<cmStdString>& languages) const { for(std::vector<cmSourceFile*>::const_iterator @@ -4173,7 +4661,7 @@ bool cmTarget::IsChrpathUsed(const char* config) // Enable if the rpath flag uses a separator and the target uses ELF // binaries. - if(const char* ll = this->GetLinkerLanguage(config)) + if(const char* ll = this->GetLinkerLanguage(config, this)) { std::string sepVar = "CMAKE_SHARED_LIBRARY_RUNTIME_"; sepVar += ll; @@ -4197,7 +4685,7 @@ bool cmTarget::IsChrpathUsed(const char* config) //---------------------------------------------------------------------------- cmTarget::ImportInfo const* -cmTarget::GetImportInfo(const char* config) +cmTarget::GetImportInfo(const char* config, cmTarget *headTarget) { // There is no imported information for non-imported targets. if(!this->IsImported()) @@ -4216,14 +4704,16 @@ cmTarget::GetImportInfo(const char* config) { config_upper = "NOCONFIG"; } + TargetConfigPair key(headTarget, config_upper); typedef cmTargetInternals::ImportInfoMapType ImportInfoMapType; + ImportInfoMapType::const_iterator i = - this->Internal->ImportInfoMap.find(config_upper); + this->Internal->ImportInfoMap.find(key); if(i == this->Internal->ImportInfoMap.end()) { ImportInfo info; - this->ComputeImportInfo(config_upper, info); - ImportInfoMapType::value_type entry(config_upper, info); + this->ComputeImportInfo(config_upper, info, headTarget); + ImportInfoMapType::value_type entry(key, info); i = this->Internal->ImportInfoMap.insert(entry).first; } @@ -4238,27 +4728,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_"; @@ -4269,26 +4747,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; @@ -4298,45 +4779,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")) @@ -4345,24 +4826,47 @@ 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, + cmTarget *headTarget) +{ + (void)headTarget; + // 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; } @@ -4443,16 +4947,30 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config, { std::string linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES"; linkProp += suffix; - if(const char* config_libs = this->GetProperty(linkProp.c_str())) + + const char *propertyLibs = this->GetProperty(linkProp.c_str()); + + if(!propertyLibs) { - cmSystemTools::ExpandListArgument(config_libs, - info.LinkInterface.Libraries); + linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES"; + propertyLibs = this->GetProperty(linkProp.c_str()); } - else if(const char* libs = - this->GetProperty("IMPORTED_LINK_INTERFACE_LIBRARIES")) + if(propertyLibs) { - cmSystemTools::ExpandListArgument(libs, - info.LinkInterface.Libraries); + cmListFileBacktrace lfbt; + cmGeneratorExpression ge(lfbt); + + cmGeneratorExpressionDAGChecker dagChecker(lfbt, + this->GetName(), + linkProp, 0, 0); + cmSystemTools::ExpandListArgument(ge.Parse(propertyLibs) + ->Evaluate(this->Makefile, + desired_config.c_str(), + false, + headTarget, + this, + &dagChecker), + info.LinkInterface.Libraries); } } @@ -4508,12 +5026,13 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config, } //---------------------------------------------------------------------------- -cmTarget::LinkInterface const* cmTarget::GetLinkInterface(const char* config) +cmTarget::LinkInterface const* cmTarget::GetLinkInterface(const char* config, + cmTarget *head) { // Imported targets have their own link interface. if(this->IsImported()) { - if(cmTarget::ImportInfo const* info = this->GetImportInfo(config)) + if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, head)) { return &info->LinkInterface; } @@ -4529,14 +5048,15 @@ cmTarget::LinkInterface const* cmTarget::GetLinkInterface(const char* config) } // Lookup any existing link interface for this configuration. - std::string key = cmSystemTools::UpperCase(config? config : ""); + TargetConfigPair key(head, cmSystemTools::UpperCase(config? config : "")); + cmTargetInternals::LinkInterfaceMapType::iterator i = this->Internal->LinkInterfaceMap.find(key); if(i == this->Internal->LinkInterfaceMap.end()) { // Compute the link interface for this configuration. cmTargetInternals::OptionalLinkInterface iface; - iface.Exists = this->ComputeLinkInterface(config, iface); + iface.Exists = this->ComputeLinkInterface(config, iface, head); // Store the information for this configuration. cmTargetInternals::LinkInterfaceMapType::value_type entry(key, iface); @@ -4547,7 +5067,8 @@ cmTarget::LinkInterface const* cmTarget::GetLinkInterface(const char* config) } //---------------------------------------------------------------------------- -bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface) +bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, + cmTarget *headTarget) { // Construct the property name suffix for this configuration. std::string suffix = "_"; @@ -4563,18 +5084,20 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface) // An explicit list of interface libraries may be set for shared // libraries and executables that export symbols. const char* explicitLibraries = 0; + std::string linkIfaceProp; if(this->GetType() == cmTarget::SHARED_LIBRARY || this->IsExecutableWithExports()) { // Lookup the per-configuration property. - std::string propName = "LINK_INTERFACE_LIBRARIES"; - propName += suffix; - explicitLibraries = this->GetProperty(propName.c_str()); + linkIfaceProp = "LINK_INTERFACE_LIBRARIES"; + linkIfaceProp += suffix; + explicitLibraries = this->GetProperty(linkIfaceProp.c_str()); // If not set, try the generic property. if(!explicitLibraries) { - explicitLibraries = this->GetProperty("LINK_INTERFACE_LIBRARIES"); + linkIfaceProp = "LINK_INTERFACE_LIBRARIES"; + explicitLibraries = this->GetProperty(linkIfaceProp.c_str()); } } @@ -4592,7 +5115,16 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface) if(explicitLibraries) { // The interface libraries have been explicitly set. - cmSystemTools::ExpandListArgument(explicitLibraries, iface.Libraries); + cmListFileBacktrace lfbt; + cmGeneratorExpression ge(lfbt); + cmGeneratorExpressionDAGChecker dagChecker(lfbt, this->GetName(), + linkIfaceProp, 0, 0); + cmSystemTools::ExpandListArgument(ge.Parse(explicitLibraries)->Evaluate( + this->Makefile, + config, + false, + headTarget, + this, &dagChecker), iface.Libraries); if(this->GetType() == cmTarget::SHARED_LIBRARY) { @@ -4604,7 +5136,8 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface) { emitted.insert(*li); } - LinkImplementation const* impl = this->GetLinkImplementation(config); + LinkImplementation const* impl = this->GetLinkImplementation(config, + headTarget); for(std::vector<std::string>::const_iterator li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li) { @@ -4632,7 +5165,9 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface) else { // The link implementation is the default link interface. - LinkImplementation const* impl = this->GetLinkImplementation(config); + LinkImplementation const* impl = this->GetLinkImplementation(config, + headTarget); + iface.ImplementationIsInterface = true; iface.Libraries = impl->Libraries; iface.WrongConfigLibraries = impl->WrongConfigLibraries; if(this->GetType() == cmTarget::STATIC_LIBRARY) @@ -4664,7 +5199,7 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface) //---------------------------------------------------------------------------- cmTarget::LinkImplementation const* -cmTarget::GetLinkImplementation(const char* config) +cmTarget::GetLinkImplementation(const char* config, cmTarget *head) { // There is no link implementation for imported targets. if(this->IsImported()) @@ -4673,14 +5208,15 @@ cmTarget::GetLinkImplementation(const char* config) } // Lookup any existing link implementation for this configuration. - std::string key = cmSystemTools::UpperCase(config? config : ""); + TargetConfigPair key(head, cmSystemTools::UpperCase(config? config : "")); + cmTargetInternals::LinkImplMapType::iterator i = this->Internal->LinkImplMap.find(key); if(i == this->Internal->LinkImplMap.end()) { // Compute the link implementation for this configuration. LinkImplementation impl; - this->ComputeLinkImplementation(config, impl); + this->ComputeLinkImplementation(config, impl, head); // Store the information for this configuration. cmTargetInternals::LinkImplMapType::value_type entry(key, impl); @@ -4692,27 +5228,26 @@ cmTarget::GetLinkImplementation(const char* config) //---------------------------------------------------------------------------- void cmTarget::ComputeLinkImplementation(const char* config, - LinkImplementation& impl) + LinkImplementation& impl, + cmTarget *head) { // Compute which library configuration to link. cmTarget::LinkLibraryType linkType = this->ComputeLinkType(config); // Collect libraries directly linked in this configuration. - LinkLibraryVectorType const& llibs = this->GetOriginalLinkLibraries(); - for(cmTarget::LinkLibraryVectorType::const_iterator li = llibs.begin(); + std::vector<std::string> llibs; + this->GetDirectLinkLibraries(config, llibs, head); + for(std::vector<std::string>::const_iterator li = llibs.begin(); li != llibs.end(); ++li) { // Skip entries that resolve to the target itself or are empty. - std::string item = this->CheckCMP0004(li->first); + std::string item = this->CheckCMP0004(*li); if(item == this->GetName() || item.empty()) { continue; } - if(li->second == cmTarget::GENERAL || li->second == linkType) - { - // The entry is meant for this configuration. - impl.Libraries.push_back(item); - } + // The entry is meant for this configuration. + impl.Libraries.push_back(item); } LinkLibraryVectorType const& oldllibs = this->GetOriginalLinkLibraries(); @@ -4815,26 +5350,85 @@ std::string cmTarget::CheckCMP0004(std::string const& item) } //---------------------------------------------------------------------------- +void cmTarget::CheckPropertyCompatibility(cmComputeLinkInformation *info, + const char* config) +{ + const cmComputeLinkInformation::ItemVector &deps = info->GetItems(); + + std::set<cmStdString> emitted; + + for(cmComputeLinkInformation::ItemVector::const_iterator li = + deps.begin(); + li != deps.end(); ++li) + { + if (!li->Target) + { + continue; + } + const char *prop = li->Target->GetProperty("COMPATIBLE_INTERFACE_BOOL"); + if (!prop) + { + continue; + } + + std::vector<std::string> props; + cmSystemTools::ExpandListArgument(prop, props); + + for(std::vector<std::string>::iterator pi = props.begin(); + pi != props.end(); ++pi) + { + if (this->Makefile->GetCMakeInstance() + ->GetIsPropertyDefined(pi->c_str(), + cmProperty::TARGET)) + { + cmOStringStream e; + e << "Target \"" << li->Target->GetName() << "\" has property \"" + << *pi << "\" listed in its COMPATIBLE_INTERFACE_BOOL property. " + "This is not allowed. Only user-defined properties may appear " + "listed in the COMPATIBLE_INTERFACE_BOOL property."; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); + return; + } + if(emitted.insert(*pi).second) + { + this->GetLinkInterfaceDependentBoolProperty(*pi, config); + if (cmSystemTools::GetErrorOccuredFlag()) + { + return; + } + } + } + } +} + +//---------------------------------------------------------------------------- cmComputeLinkInformation* -cmTarget::GetLinkInformation(const char* config) +cmTarget::GetLinkInformation(const char* config, cmTarget *head) { + cmTarget *headTarget = head ? head : this; // Lookup any existing information for this configuration. - std::map<cmStdString, cmComputeLinkInformation*>::iterator - i = this->LinkInformation.find(config?config:""); + TargetConfigPair key(headTarget, + cmSystemTools::UpperCase(config?config:"")); + cmTargetLinkInformationMap::iterator + i = this->LinkInformation.find(key); if(i == this->LinkInformation.end()) { // Compute information for this configuration. cmComputeLinkInformation* info = - new cmComputeLinkInformation(this, config); + new cmComputeLinkInformation(this, config, headTarget); if(!info || !info->Compute()) { delete info; info = 0; } + if (info) + { + this->CheckPropertyCompatibility(info, config); + } + // Store the information for this configuration. - std::map<cmStdString, cmComputeLinkInformation*>::value_type - entry(config?config:"", info); + cmTargetLinkInformationMap::value_type entry(key, info); i = this->LinkInformation.insert(entry).first; } return i->second; @@ -4939,6 +5533,7 @@ cmTargetInternalPointer //---------------------------------------------------------------------------- cmTargetInternalPointer::~cmTargetInternalPointer() { + deleteAndClear(this->Pointer->IncludeDirectoriesEntries); delete this->Pointer; } diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 9efd638..69a00c1 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> @@ -24,11 +25,13 @@ class cmSourceFile; class cmGlobalGenerator; class cmComputeLinkInformation; class cmListFileBacktrace; +class cmTarget; struct cmTargetLinkInformationMap: - public std::map<cmStdString, cmComputeLinkInformation*> + public std::map<std::pair<cmTarget*, std::string>, cmComputeLinkInformation*> { - typedef std::map<cmStdString, cmComputeLinkInformation*> derived; + typedef std::map<std::pair<cmTarget*, std::string>, + cmComputeLinkInformation*> derived; cmTargetLinkInformationMap() {} cmTargetLinkInformationMap(cmTargetLinkInformationMap const& r); ~cmTargetLinkInformationMap(); @@ -109,9 +112,6 @@ public: std::vector<cmCustomCommand> &GetPostBuildCommands() {return this->PostBuildCommands;} - ///! Return the list of frameworks being linked to this target - std::vector<std::string> &GetFrameworks() {return this->Frameworks;} - /** * Get the list of the source files used by this target */ @@ -168,6 +168,9 @@ public: return this->LinkLibraries;} const LinkLibraryVectorType &GetOriginalLinkLibraries() const {return this->OriginalLinkLibraries;} + void GetDirectLinkLibraries(const char *config, + std::vector<std::string> &, + cmTarget *head); /** Compute the link type to use for the given configuration. */ LinkLibraryType ComputeLinkType(const char* config); @@ -179,7 +182,6 @@ public: // Check to see if a library is a framework and treat it different on Mac bool NameResolvesToFramework(const std::string& libname); - bool AddFramework(const std::string& lib, LinkLibraryType llt); void AddLinkLibrary(cmMakefile& mf, const char *target, const char* lib, LinkLibraryType llt); @@ -256,12 +258,15 @@ public: // Needed only for OLD behavior of CMP0003. std::vector<std::string> WrongConfigLibraries; - LinkInterface(): Multiplicity(0) {} + bool ImplementationIsInterface; + + LinkInterface(): Multiplicity(0), ImplementationIsInterface(false) {} }; /** Get the link interface for the given configuration. Returns 0 if the target cannot be linked. */ - LinkInterface const* GetLinkInterface(const char* config); + LinkInterface const* GetLinkInterface(const char* config, + cmTarget *headTarget); /** The link implementation specifies the direct library dependencies needed by the object files of the target. */ @@ -277,7 +282,8 @@ public: // Needed only for OLD behavior of CMP0003. std::vector<std::string> WrongConfigLibraries; }; - LinkImplementation const* GetLinkImplementation(const char* config); + LinkImplementation const* GetLinkImplementation(const char* config, + cmTarget *head); /** Link information from the transitive closure of the link implementation and the interfaces of its dependencies. */ @@ -289,7 +295,7 @@ public: // Languages whose runtime libraries must be linked. std::vector<std::string> Languages; }; - LinkClosure const* GetLinkClosure(const char* config); + LinkClosure const* GetLinkClosure(const char* config, cmTarget *head); /** Strip off leading and trailing whitespace from an item named in the link dependencies of this target. */ @@ -334,7 +340,7 @@ public: bool FindSourceFiles(); ///! Return the preferred linker language for this target - const char* GetLinkerLanguage(const char* config = 0); + const char* GetLinkerLanguage(const char* config = 0, cmTarget *head = 0); /** Get the full name of the target according to the settings in its makefile. */ @@ -402,11 +408,17 @@ public: std::string GetInstallNameDirForInstallTree(const char* config, bool for_xcode = false); - cmComputeLinkInformation* GetLinkInformation(const char* config); + cmComputeLinkInformation* GetLinkInformation(const char* config, + cmTarget *head = 0); // 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); @@ -474,6 +486,21 @@ 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); + + void AppendBuildInterfaceIncludes(); + + void GetLinkDependentTargetsForProperty(const std::string &p, + std::set<std::string> &targets); + bool IsNullImpliedByLinkLibraries(const std::string &p); + + void AddLinkDependentTargetsForProperties( + const std::map<cmStdString, cmStdString> &map); + + bool GetLinkInterfaceDependentBoolProperty(const std::string &p, + const char *config); private: /** * A list of direct dependencies. Use in conjunction with DependencyMap. @@ -569,7 +596,6 @@ private: LinkLibraryVectorType LinkLibraries; LinkLibraryVectorType PrevLinkedLibraries; bool LinkLibrariesAnalyzed; - std::vector<std::string> Frameworks; std::vector<std::string> LinkDirectories; std::set<cmStdString> LinkDirectoriesEmmitted; bool HaveInstallRule; @@ -584,6 +610,10 @@ private: bool DLLPlatform; bool IsApple; bool IsImportedTarget; + mutable std::map<cmStdString, std::set<std::string> > + LinkDependentProperties; + mutable std::set<std::string> LinkImplicitNullProperties; + bool BuildInterfaceIncludesAppended; // Cache target output paths for each configuration. struct OutputInfo; @@ -593,16 +623,21 @@ private: // Cache import information from properties for each configuration. struct ImportInfo; - ImportInfo const* GetImportInfo(const char* config); - void ComputeImportInfo(std::string const& desired_config, ImportInfo& info); + ImportInfo const* GetImportInfo(const char* config, + cmTarget *workingTarget); + void ComputeImportInfo(std::string const& desired_config, ImportInfo& info, + cmTarget *head); cmTargetLinkInformationMap LinkInformation; + void CheckPropertyCompatibility(cmComputeLinkInformation *info, + const char* config); - bool ComputeLinkInterface(const char* config, LinkInterface& iface); + bool ComputeLinkInterface(const char* config, LinkInterface& iface, + cmTarget *head); void ComputeLinkImplementation(const char* config, - LinkImplementation& impl); - void ComputeLinkClosure(const char* config, LinkClosure& lc); + LinkImplementation& impl, cmTarget *head); + void ComputeLinkClosure(const char* config, LinkClosure& lc, cmTarget *head); void ClearLinkMaps(); @@ -610,6 +645,9 @@ private: void ProcessSourceExpression(std::string const& expr); + std::string GetDebugGeneratorExpressions(const std::string &value, + cmTarget::LinkLibraryType llt); + // The cmMakefile instance that owns this target. This should // always be set. cmMakefile* Makefile; diff --git a/Source/cmTargetCompileDefinitionsCommand.cxx b/Source/cmTargetCompileDefinitionsCommand.cxx new file mode 100644 index 0000000..492a1b7 --- /dev/null +++ b/Source/cmTargetCompileDefinitionsCommand.cxx @@ -0,0 +1,57 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2013 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. +============================================================================*/ +#include "cmTargetCompileDefinitionsCommand.h" + +#include "cmMakefileIncludeDirectoriesEntry.h" + +bool cmTargetCompileDefinitionsCommand +::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &) +{ + return this->HandleArguments(args, "COMPILE_DEFINITIONS"); +} + +void cmTargetCompileDefinitionsCommand +::HandleImportedTargetInvalidScope(const std::string &scope, + const std::string &tgt) +{ + cmOStringStream e; + e << "Cannot specify " << scope << " compile definitions for imported " + "target \"" << tgt << "\". Compile definitions can only be " + "specified for an imported target in the INTERFACE mode."; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); +} + +void cmTargetCompileDefinitionsCommand +::HandleMissingTarget(const std::string &name) +{ + cmOStringStream e; + e << "Cannot specify compile definitions for target \"" << name << "\" " + "which is not built by this project."; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); +} + +bool cmTargetCompileDefinitionsCommand +::HandleNonTargetArg(std::string &content, + const std::string &sep, + const std::string &entry, + const std::string &) +{ + content += sep + entry; + return true; +} + +void cmTargetCompileDefinitionsCommand +::HandleDirectContent(cmTarget *tgt, const std::string &content, + bool) +{ + tgt->AppendProperty("COMPILE_DEFINITIONS", content.c_str()); +} diff --git a/Source/cmTargetCompileDefinitionsCommand.h b/Source/cmTargetCompileDefinitionsCommand.h new file mode 100644 index 0000000..4b066b7a --- /dev/null +++ b/Source/cmTargetCompileDefinitionsCommand.h @@ -0,0 +1,94 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2013 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 cmTargetCompileDefinitionsCommand_h +#define cmTargetCompileDefinitionsCommand_h + +#include "cmTargetPropCommandBase.h" + +class cmTargetCompileDefinitionsCommand : public cmTargetPropCommandBase +{ +public: + /** + * This is a virtual constructor for the command. + */ + virtual cmCommand* Clone() + { + return new cmTargetCompileDefinitionsCommand; + } + + /** + * This is called when the command is first encountered in + * the CMakeLists.txt file. + */ + virtual bool InitialPass(std::vector<std::string> const& args, + cmExecutionStatus &status); + + /** + * The name of the command as specified in CMakeList.txt. + */ + virtual const char* GetName() const { return "target_compile_definitions";} + + /** + * Succinct documentation. + */ + virtual const char* GetTerseDocumentation() const + { + return + "Add compile definitions to a target."; + } + + /** + * More documentation. + */ + virtual const char* GetFullDocumentation() const + { + return + " target_compile_definitions(<target> " + "<INTERFACE|PUBLIC|PRIVATE> [items1...]\n" + " [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])\n" + "Specify compile definitions or targets to use when compiling a given " + "target. " + "The named <target> must have been created by a command such as " + "add_executable or add_library. " + "The INTERFACE, PUBLIC and PRIVATE keywords are required to specify " + "the scope of the following arguments. PRIVATE and PUBLIC items will " + "populate the COMPILE_DEFINITIONS property of <target>. PUBLIC and " + "INTERFACE items will populate the INTERFACE_COMPILE_DEFINITIONS " + "property of <target>. " + "The non-scope arguments specify compile definitions or targets to use " + "INTERFACE_COMPILE_DEFINITIONS from. " + "Repeated calls for the same <target> append items in the order called." + "\n" + "Arguments to target_compile_definitions may use \"generator " + "expressions\" with the syntax \"$<...>\". " + CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS + ; + } + + cmTypeMacro(cmTargetCompileDefinitionsCommand, cmCommand); + +private: + virtual void HandleImportedTargetInvalidScope(const std::string &scope, + const std::string &tgt); + virtual void HandleMissingTarget(const std::string &name); + + virtual bool HandleNonTargetArg(std::string &content, + const std::string &sep, + const std::string &entry, + const std::string &tgt); + + virtual void HandleDirectContent(cmTarget *tgt, const std::string &content, + bool prepend); +}; + +#endif diff --git a/Source/cmTargetIncludeDirectoriesCommand.cxx b/Source/cmTargetIncludeDirectoriesCommand.cxx new file mode 100644 index 0000000..18e2cba --- /dev/null +++ b/Source/cmTargetIncludeDirectoriesCommand.cxx @@ -0,0 +1,74 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2013 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. +============================================================================*/ +#include "cmTargetIncludeDirectoriesCommand.h" + +#include "cmMakefileIncludeDirectoriesEntry.h" + +//---------------------------------------------------------------------------- +bool cmTargetIncludeDirectoriesCommand +::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &) +{ + return this->HandleArguments(args, "INCLUDE_DIRECTORIES", PROCESS_BEFORE); +} + +//---------------------------------------------------------------------------- +void cmTargetIncludeDirectoriesCommand +::HandleImportedTargetInvalidScope(const std::string &tgt, + const std::string &scope) +{ + cmOStringStream e; + e << "Cannot specify " << scope << " include directories for imported " + "target \"" << tgt << "\". Include directories can only be " + "specified for an imported target in the INTERFACE mode."; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); +} + +//---------------------------------------------------------------------------- +void cmTargetIncludeDirectoriesCommand +::HandleMissingTarget(const std::string &name) +{ + cmOStringStream e; + e << "Cannot specify include directories for target \"" << name << "\" " + "which is not built by this project."; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); +} + +//---------------------------------------------------------------------------- +bool cmTargetIncludeDirectoriesCommand +::HandleNonTargetArg(std::string &content, + const std::string &sep, + const std::string &entry, + const std::string &tgt) +{ + if (!cmSystemTools::FileIsFullPath(entry.c_str())) + { + cmOStringStream e; + e << "Cannot specify relative include directory \"" << entry << "\" for " + "target \"" << tgt << "\". Only absolute paths are permitted"; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); + return false; + } + + content += sep + entry; + return true; +} + +//---------------------------------------------------------------------------- +void cmTargetIncludeDirectoriesCommand +::HandleDirectContent(cmTarget *tgt, const std::string &content, + bool prepend) +{ + cmListFileBacktrace lfbt; + this->Makefile->GetBacktrace(lfbt); + cmMakefileIncludeDirectoriesEntry entry(content, lfbt); + tgt->InsertInclude(entry, prepend); +} diff --git a/Source/cmTargetIncludeDirectoriesCommand.h b/Source/cmTargetIncludeDirectoriesCommand.h new file mode 100644 index 0000000..90e039c --- /dev/null +++ b/Source/cmTargetIncludeDirectoriesCommand.h @@ -0,0 +1,98 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2013 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 cmTargetIncludeDirectoriesCommand_h +#define cmTargetIncludeDirectoriesCommand_h + +#include "cmTargetPropCommandBase.h" + +//---------------------------------------------------------------------------- +class cmTargetIncludeDirectoriesCommand : public cmTargetPropCommandBase +{ +public: + /** + * This is a virtual constructor for the command. + */ + virtual cmCommand* Clone() + { + return new cmTargetIncludeDirectoriesCommand; + } + + /** + * This is called when the command is first encountered in + * the CMakeLists.txt file. + */ + virtual bool InitialPass(std::vector<std::string> const& args, + cmExecutionStatus &status); + + /** + * The name of the command as specified in CMakeList.txt. + */ + virtual const char* GetName() const { return "target_include_directories";} + + /** + * Succinct documentation. + */ + virtual const char* GetTerseDocumentation() const + { + return + "Add include directories to a target."; + } + + /** + * More documentation. + */ + virtual const char* GetFullDocumentation() const + { + return + " target_include_directories(<target> [BEFORE] " + "<INTERFACE|PUBLIC|PRIVATE> [items1...]\n" + " [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])\n" + "Specify include directories or targets to use when compiling a given " + "target. " + "The named <target> must have been created by a command such as " + "add_executable or add_library.\n" + "If BEFORE is specified, the content will be prepended to the property " + "instead of being appended.\n" + "The INTERFACE, PUBLIC and PRIVATE keywords are required to specify " + "the scope of the following arguments. PRIVATE and PUBLIC items will " + "populate the INCLUDE_DIRECTORIES property of <target>. PUBLIC and " + "INTERFACE items will populate the INTERFACE_INCLUDE_DIRECTORIES " + "property of <target>. " + "The non-scope arguments specify either include directories or targets " + "to use INTERFACE_INCLUDE_DIRECTORIES from. Any specified include " + "directories must be absolute paths, not relative paths. " + "Repeated calls for the same <target> append items in the order called." + "\n" + "Arguments to target_include_directories may use \"generator " + "expressions\" with the syntax \"$<...>\". " + CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS + ; + } + + cmTypeMacro(cmTargetIncludeDirectoriesCommand, cmCommand); + +private: + virtual void HandleImportedTargetInvalidScope(const std::string &tgt, + const std::string &scope); + virtual void HandleMissingTarget(const std::string &name); + + virtual bool HandleNonTargetArg(std::string &content, + const std::string &sep, + const std::string &entry, + const std::string &tgt); + + virtual void HandleDirectContent(cmTarget *tgt, const std::string &content, + bool prepend); +}; + +#endif diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx index f42b0f6..0705fb4 100644 --- a/Source/cmTargetLinkLibrariesCommand.cxx +++ b/Source/cmTargetLinkLibrariesCommand.cxx @@ -35,6 +35,10 @@ bool cmTargetLinkLibrariesCommand ->GetGlobalGenerator()->FindTarget(0, args[0].c_str()); if(!this->Target) { + this->Target = this->Makefile->FindTargetToUse(args[0].c_str()); + } + if(!this->Target) + { cmake::MessageType t = cmake::FATAL_ERROR; // fail by default cmOStringStream e; e << "Cannot specify link libraries for target \"" << args[0] << "\" " @@ -257,6 +261,16 @@ cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib, // Handle normal case first. if(this->CurrentProcessingState != ProcessingLinkInterface) { + if (this->Target->IsImported()) + { + cmOStringStream e; + e << "Imported targets may only be used with the " + "LINK_INTERFACE_LIBRARIES specifier to target_link_libraries."; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); + return; + } + + this->Makefile ->AddLinkLibraryForTarget(this->Target->GetName(), lib, llt); if (this->CurrentProcessingState != ProcessingPublicInterface) diff --git a/Source/cmTargetLinkLibrariesCommand.h b/Source/cmTargetLinkLibrariesCommand.h index 8e5823c..34fe54c 100644 --- a/Source/cmTargetLinkLibrariesCommand.h +++ b/Source/cmTargetLinkLibrariesCommand.h @@ -13,6 +13,7 @@ #define cmTargetLinkLibrariesCommand_h #include "cmCommand.h" +#include "cmDocumentGeneratorExpressions.h" /** \class cmTargetLinkLibrariesCommand * \brief Specify a list of libraries to link into executables. @@ -141,6 +142,12 @@ public: "However, if two archives are really so interdependent they should " "probably be combined into a single archive." ")" + "\n" + "Arguments to target_link_libraries may use \"generator expressions\" " + "with the syntax \"$<...>\". Note however, that generator expressions " + "will not be used in OLD handling of CMP0003 or CMP0004." + "\n" + CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS ; } diff --git a/Source/cmTargetPropCommandBase.cxx b/Source/cmTargetPropCommandBase.cxx new file mode 100644 index 0000000..69aaf17 --- /dev/null +++ b/Source/cmTargetPropCommandBase.cxx @@ -0,0 +1,144 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2013 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. +============================================================================*/ + +#include "cmTargetPropCommandBase.h" + +#include "cmGlobalGenerator.h" + +//---------------------------------------------------------------------------- +bool cmTargetPropCommandBase +::HandleArguments(std::vector<std::string> const& args, const char *prop, + ArgumentFlags flags) +{ + if(args.size() < 3) + { + this->SetError("called with incorrect number of arguments"); + return false; + } + + // Lookup the target for which libraries are specified. + this->Target = + this->Makefile->GetCMakeInstance() + ->GetGlobalGenerator()->FindTarget(0, args[0].c_str()); + if(!this->Target) + { + this->Target = this->Makefile->FindTargetToUse(args[0].c_str()); + } + if(!this->Target) + { + this->HandleMissingTarget(args[0]); + return false; + } + + unsigned int argIndex = 1; + + bool prepend = false; + if ((flags & PROCESS_BEFORE) && args[argIndex] == "BEFORE") + { + if (args.size() < 4) + { + this->SetError("called with incorrect number of arguments"); + return false; + } + prepend = true; + ++argIndex; + } + + this->Property = prop; + + while (argIndex < args.size()) + { + if (!this->ProcessContentArgs(args, argIndex, prepend)) + { + return false; + } + } + return true; +} + +//---------------------------------------------------------------------------- +bool cmTargetPropCommandBase +::ProcessContentArgs(std::vector<std::string> const& args, + unsigned int &argIndex, bool prepend) +{ + const std::string scope = args[argIndex]; + + if(scope != "PUBLIC" + && scope != "PRIVATE" + && scope != "INTERFACE" ) + { + this->SetError("called with invalid arguments"); + return false; + } + + if(this->Target->IsImported() && scope != "INTERFACE") + { + this->HandleImportedTargetInvalidScope(args[0], scope); + return false; + } + + ++argIndex; + + std::string content; + + std::string sep; + for(unsigned int i=argIndex; i < args.size(); ++i, ++argIndex) + { + if(args[i] == "PUBLIC" + || args[i] == "PRIVATE" + || args[i] == "INTERFACE" ) + { + this->PopulateTargetProperies(scope, content, prepend); + return true; + } + if (this->Makefile->FindTargetToUse(args[i].c_str())) + { + content += sep + "$<TARGET_PROPERTY:" + args[i] + + ",INTERFACE_" + this->Property + ">"; + } + else if (!this->HandleNonTargetArg(content, sep, args[i], args[0])) + { + return false; + } + sep = ";"; + } + this->PopulateTargetProperies(scope, content, prepend); + return true; +} + +//---------------------------------------------------------------------------- +void cmTargetPropCommandBase +::PopulateTargetProperies(const std::string &scope, + const std::string &content, bool prepend) +{ + if (scope == "PRIVATE" || scope == "PUBLIC") + { + this->HandleDirectContent(this->Target, content, prepend); + } + if (scope == "INTERFACE" || scope == "PUBLIC") + { + if (prepend) + { + const std::string propName = std::string("INTERFACE_") + this->Property; + const char *propValue = this->Target->GetProperty(propName.c_str()); + const std::string totalContent = content + (propValue + ? std::string(";") + propValue + : std::string()); + this->Target->SetProperty(propName.c_str(), totalContent.c_str()); + } + else + { + this->Target->AppendProperty(("INTERFACE_" + this->Property).c_str(), + content.c_str()); + } + } +} diff --git a/Source/cmTargetPropCommandBase.h b/Source/cmTargetPropCommandBase.h new file mode 100644 index 0000000..e757f9d --- /dev/null +++ b/Source/cmTargetPropCommandBase.h @@ -0,0 +1,58 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2013 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 cmTargetPropCommandBase_h +#define cmTargetPropCommandBase_h + +#include "cmCommand.h" +#include "cmDocumentGeneratorExpressions.h" + +class cmTarget; + +//---------------------------------------------------------------------------- +class cmTargetPropCommandBase : public cmCommand +{ +public: + + enum ArgumentFlags { + NO_FLAGS = 0, + PROCESS_BEFORE = 1 + }; + + bool HandleArguments(std::vector<std::string> const& args, + const char *prop, ArgumentFlags flags = NO_FLAGS); + +private: + virtual void HandleImportedTargetInvalidScope(const std::string &tgt, + const std::string &scope) = 0; + virtual void HandleMissingTarget(const std::string &name) = 0; + + virtual bool HandleNonTargetArg(std::string &content, + const std::string &sep, + const std::string &entry, + const std::string &tgt) = 0; + + virtual void HandleDirectContent(cmTarget *tgt, + const std::string &content, + bool prepend) = 0; + + bool ProcessContentArgs(std::vector<std::string> const& args, + unsigned int &argIndex, bool prepend); + void PopulateTargetProperies(const std::string &scope, + const std::string &content, bool prepend); + +private: + cmTarget *Target; + std::string Property; +}; + +#endif 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/cmTimestamp.cxx b/Source/cmTimestamp.cxx new file mode 100644 index 0000000..ac26503 --- /dev/null +++ b/Source/cmTimestamp.cxx @@ -0,0 +1,134 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2012 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 "cmTimestamp.h" + +#include <cstring> + +#include <sys/types.h> +#include <sys/stat.h> + +//---------------------------------------------------------------------------- +std::string cmTimestamp::CurrentTime( + const std::string& formatString, bool utcFlag) +{ + time_t currentTimeT = time(0); + if(currentTimeT == time_t(-1)) + { + return std::string(); + } + + return CreateTimestampFromTimeT(currentTimeT, formatString, utcFlag); +} + +//---------------------------------------------------------------------------- +std::string cmTimestamp::FileModificationTime(const char* path, + const std::string& formatString, bool utcFlag) +{ + struct stat info; + memset(&info, 0, sizeof(info)); + + if(stat(path, &info) != 0) + { + return std::string(); + } + + return CreateTimestampFromTimeT(info.st_mtime, formatString, utcFlag); +} + +//---------------------------------------------------------------------------- +std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT, + std::string formatString, bool utcFlag) +{ + if(formatString.empty()) + { + formatString = "%Y-%m-%dT%H:%M:%S"; + if(utcFlag) + { + formatString += "Z"; + } + } + + struct tm timeStruct; + memset(&timeStruct, 0, sizeof(timeStruct)); + + struct tm* ptr = (struct tm*) 0; + if(utcFlag) + { + ptr = gmtime(&timeT); + } + else + { + ptr = localtime(&timeT); + } + + if(ptr == 0) + { + return std::string(); + } + + timeStruct = *ptr; + + std::string result; + for(std::string::size_type i = 0; i < formatString.size(); ++i) + { + char c1 = formatString[i]; + char c2 = (i+1 < formatString.size()) ? + formatString[i+1] : static_cast<char>(0); + + if(c1 == '%' && c2 != 0) + { + result += AddTimestampComponent(c2, timeStruct); + ++i; + } + else + { + result += c1; + } + } + + return result; +} + +//---------------------------------------------------------------------------- +std::string cmTimestamp::AddTimestampComponent( + char flag, struct tm& timeStruct) +{ + std::string formatString = "%"; + formatString += flag; + + switch(flag) + { + case 'd': + case 'H': + case 'I': + case 'j': + case 'm': + case 'M': + case 'S': + case 'U': + case 'w': + case 'y': + case 'Y': + break; + default: + { + return formatString; + } + } + + char buffer[16]; + + size_t size = strftime(buffer, sizeof(buffer), + formatString.c_str(), &timeStruct); + + return std::string(buffer, size); +} diff --git a/Source/cmTimestamp.h b/Source/cmTimestamp.h new file mode 100644 index 0000000..24c1869 --- /dev/null +++ b/Source/cmTimestamp.h @@ -0,0 +1,40 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2012 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 cmTimestamp_h +#define cmTimestamp_h + +#include <string> +#include <time.h> + +/** \class cmTimestamp + * \brief Utility class to generate sting representation of a timestamp + * + */ +class cmTimestamp +{ +public: + cmTimestamp() {} + + std::string CurrentTime(const std::string& formatString, bool utcFlag); + + std::string FileModificationTime(const char* path, + const std::string& formatString, bool utcFlag); + +private: + std::string CreateTimestampFromTimeT(time_t timeT, + std::string formatString, bool utcFlag); + + std::string AddTimestampComponent(char flag, struct tm& timeStruct); +}; + + +#endif diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index ec9c125..2596d73 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -572,6 +572,12 @@ cmVisualStudio10TargetGenerator::WriteCustomRule(cmSourceFile* source, sep = ";"; } (*this->BuildFileStream ) << "</Outputs>\n"; + if(this->LocalGenerator->GetVersion() > cmLocalVisualStudioGenerator::VS10) + { + // VS >= 11 let us turn off linking of custom command outputs. + this->WritePlatformConfigTag("LinkObjects", i->c_str(), 3); + (*this->BuildFileStream ) << "false</LinkObjects>\n"; + } } this->WriteString("</CustomBuild>\n", 2); } @@ -879,14 +885,23 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() } } - for(std::vector<cmSourceFile*>::const_iterator - si = this->GeneratorTarget->ExternalObjects.begin(); - si != this->GeneratorTarget->ExternalObjects.end(); ++si) + if(this->LocalGenerator->GetVersion() > cmLocalVisualStudioGenerator::VS10) + { + // For VS >= 11 we use LinkObjects to avoid linking custom command + // outputs. Use Object for all external objects, generated or not. + this->WriteSources("Object", this->GeneratorTarget->ExternalObjects); + } + else { // If an object file is generated in this target, then vs10 will use // it in the build, and we have to list it as None instead of Object. - std::vector<cmSourceFile*> const* d = this->Target->GetSourceDepends(*si); - this->WriteSource((d && !d->empty())? "None":"Object", *si); + for(std::vector<cmSourceFile*>::const_iterator + si = this->GeneratorTarget->ExternalObjects.begin(); + si != this->GeneratorTarget->ExternalObjects.end(); ++si) + { + std::vector<cmSourceFile*> const* d=this->Target->GetSourceDepends(*si); + this->WriteSource((d && !d->empty())? "None":"Object", *si); + } } this->WriteSources("None", this->GeneratorTarget->ExtraSources); diff --git a/Source/cmake.cxx b/Source/cmake.cxx index fba4860..2eecfba 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())) { @@ -3299,6 +3299,12 @@ int cmake::ExecuteLinkScript(std::vector<std::string>& args) int result = 0; while(result == 0 && cmSystemTools::GetLineFromStream(fin, command)) { + // Skip empty command lines. + if(command.find_first_not_of(" \t") == command.npos) + { + continue; + } + // Setup this command line. const char* cmd[2] = {command.c_str(), 0}; cmsysProcess_SetCommand(cp, cmd); @@ -3552,6 +3558,13 @@ void cmake::DefineProperty(const char *name, cmProperty::ScopeType scope, chained); } +bool cmake::GetIsPropertyDefined(const char *name, + cmProperty::ScopeType scope) +{ + return this->PropertyDefinitions[scope].find(name) != + this->PropertyDefinitions[scope].end(); +} + cmPropertyDefinition *cmake ::GetPropertyDefinition(const char *name, cmProperty::ScopeType scope) diff --git a/Source/cmake.h b/Source/cmake.h index e5aa076..f6fe0d6 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -341,6 +341,8 @@ class cmake bool chain = false, const char *variableGroup = 0); + bool GetIsPropertyDefined(const char *name, cmProperty::ScopeType scope); + // get property definition cmPropertyDefinition *GetPropertyDefinition (const char *name, cmProperty::ScopeType scope); diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index 777d76f..124b8ac 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) @@ -575,6 +574,8 @@ IF(KWSYS_USE_SystemTools) ENDIF() IF(KWSYS_USE_SystemInformation) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS SIZEOF_VOID_P=${CMAKE_SIZEOF_VOID_P}) IF(NOT CYGWIN) INCLUDE(CheckIncludeFiles) CHECK_INCLUDE_FILES("sys/types.h;ifaddrs.h" KWSYS_SYS_HAS_IFADDRS_H) @@ -597,6 +598,20 @@ IF(KWSYS_USE_SystemInformation) ENDIF() ENDIF() ENDIF() + IF(CMAKE_SYSTEM MATCHES "HP-UX") + CHECK_INCLUDE_FILES("sys/mpctl.h" KWSYS_SYS_HAS_MPCTL_H) + IF(KWSYS_SYS_HAS_MPCTL_H) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_SYS_HAS_MPCTL_H=1) + ENDIF() + ENDIF() + IF(CMAKE_SYSTEM MATCHES "BSD") + CHECK_INCLUDE_FILES("machine/cpu.h" KWSYS_SYS_HAS_MACHINE_CPU_H) + IF(KWSYS_SYS_HAS_MACHINE_CPU_H) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_SYS_HAS_MACHINE_CPU_H=1) + ENDIF() + ENDIF() IF(KWSYS_LFS_AVAILABLE AND NOT KWSYS_LFS_DISABLE) SET(KWSYS_PLATFORM_CXX_TEST_DEFINES -DKWSYS_HAS_LFS=1) ENDIF() @@ -625,6 +640,20 @@ IF(KWSYS_USE_SystemInformation) SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_CXX_HAS__ATOI64=1) ENDIF() + IF(BORLAND) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BORLAND_ASM + "Checking whether Borland CXX compiler supports assembler instructions" DIRECT) + IF(KWSYS_CXX_HAS_BORLAND_ASM) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_CXX_HAS_BORLAND_ASM=1) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BORLAND_ASM_CPUID + "Checking whether Borland CXX compiler supports CPUID assembler instruction" DIRECT) + IF(KWSYS_CXX_HAS_BORLAND_ASM_CPUID) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_CXX_HAS_BORLAND_ASM_CPUID=1) + ENDIF() + ENDIF() + ENDIF() IF(KWSYS_USE___INT64) SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_USE___INT64=1) @@ -762,7 +791,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 +829,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 +963,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 +1000,6 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) ) ENDIF(NOT WATCOM) SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} - testRegistry testIOS testSystemTools testCommandLineArguments @@ -1116,8 +1103,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/IOStream.hxx.in b/Source/kwsys/IOStream.hxx.in index 9eb99e0..2eeedf2 100644 --- a/Source/kwsys/IOStream.hxx.in +++ b/Source/kwsys/IOStream.hxx.in @@ -26,12 +26,9 @@ /* Whether ostream supports long long. */ #define @KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG @KWSYS_IOS_HAS_OSTREAM_LONG_LONG@ -/* Size of type long long and 0 if not available. */ -#define @KWSYS_NAMESPACE@_IOS_SIZEOF_LONG_LONG @KWSYS_SIZEOF_LONG_LONG@ - /* Determine whether we need to define the streaming operators for long long or __int64. */ -#if @KWSYS_NAMESPACE@_IOS_SIZEOF_LONG_LONG +#if @KWSYS_USE_LONG_LONG@ # if !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG || \ !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG # define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 1 @@ -136,7 +133,6 @@ operator<<(kwsys_ios::ostream& os, @KWSYS_NAMESPACE@::IOStreamULL value) /* If building a C++ file in kwsys itself, give the source file access to the macros without a configured namespace. */ #if defined(KWSYS_NAMESPACE) -# define KWSYS_IOS_SIZEOF_LONG_LONG @KWSYS_NAMESPACE@_IOS_SIZEOF_LONG_LONG # define KWSYS_IOS_HAS_ISTREAM_LONG_LONG @KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG # define KWSYS_IOS_HAS_OSTREAM_LONG_LONG @KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG # define KWSYS_IOS_NEED_OPERATORS_LL @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 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/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c index 1992211..2db1254 100644 --- a/Source/kwsys/ProcessUNIX.c +++ b/Source/kwsys/ProcessUNIX.c @@ -63,10 +63,6 @@ do. #include <dirent.h> /* DIR, dirent */ #include <ctype.h> /* isspace */ -#ifdef __HAIKU__ -#undef __BEOS__ -#endif - #if defined(__VMS) # define KWSYSPE_VMS_NONBLOCK , O_NONBLOCK #else @@ -422,9 +418,10 @@ int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command) parse it. */ newCommands[cp->NumberOfCommands] = kwsysSystem_Parse_CommandForUnix(*command, 0); - if(!newCommands[cp->NumberOfCommands]) + if(!newCommands[cp->NumberOfCommands] || + !newCommands[cp->NumberOfCommands][0]) { - /* Out of memory. */ + /* Out of memory or no command parsed. */ free(newCommands); return 0; } 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..b20d724 100644 --- a/Source/kwsys/SystemInformation.cxx +++ b/Source/kwsys/SystemInformation.cxx @@ -86,6 +86,19 @@ typedef int siginfo_t; # endif #endif +#if defined(__OpenBSD__) || defined(__NetBSD__) +# include <sys/param.h> +# include <sys/sysctl.h> +#endif + +#if defined(KWSYS_SYS_HAS_MACHINE_CPU_H) +# include <machine/cpu.h> +#endif + +#if defined(__DragonFly__) +# include <sys/sysctl.h> +#endif + #ifdef __APPLE__ # include <sys/sysctl.h> # include <mach/vm_statistics.h> @@ -133,6 +146,9 @@ typedef struct rlimit ResourceLimitType; #elif defined( __hpux ) # include <sys/param.h> # include <sys/pstat.h> +# if defined(KWSYS_SYS_HAS_MPCTL_H) +# include <sys/mpctl.h> +# endif #endif #ifdef __HAIKU__ @@ -173,6 +189,105 @@ typedef struct rlimit ResourceLimitType; # endif #endif +#if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(_WIN64) +#define USE_ASM_INSTRUCTIONS 1 +#else +#define USE_ASM_INSTRUCTIONS 0 +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#include <intrin.h> +#define USE_CPUID_INTRINSICS 1 +#else +#define USE_CPUID_INTRINSICS 0 +#endif + +#if USE_ASM_INSTRUCTIONS || USE_CPUID_INTRINSICS || defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID) +# define USE_CPUID 1 +#else +# define USE_CPUID 0 +#endif + +#if USE_CPUID + +#define CPUID_AWARE_COMPILER + +/** + * call CPUID instruction + * + * Will return false if the instruction failed. + */ +static bool call_cpuid(int select, int result[4]) +{ +#if USE_CPUID_INTRINSICS + __cpuid(result, select); + return true; +#else + int tmp[4]; +#if defined(_MSC_VER) + // Use SEH to determine CPUID presence + __try { + _asm { +#ifdef CPUID_AWARE_COMPILER + ; we must push/pop the registers <<CPUID>> writes to, as the + ; optimiser doesn't know about <<CPUID>>, and so doesn't expect + ; these registers to change. + push eax + push ebx + push ecx + push edx +#endif + ; <<CPUID>> + mov eax, select +#ifdef CPUID_AWARE_COMPILER + cpuid +#else + _asm _emit 0x0f + _asm _emit 0xa2 +#endif + mov tmp[0 * TYPE int], eax + mov tmp[1 * TYPE int], ebx + mov tmp[2 * TYPE int], ecx + mov tmp[3 * TYPE int], edx + +#ifdef CPUID_AWARE_COMPILER + pop edx + pop ecx + pop ebx + pop eax +#endif + } + } + __except(1) + { + return false; + } + + memcpy(result, tmp, sizeof(tmp)); +#elif defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID) + unsigned int a, b, c, d; + __asm { + mov EAX, select; + cpuid + mov a, EAX; + mov b, EBX; + mov c, ECX; + mov d, EDX; + } + + result[0] = a; + result[1] = b; + result[2] = c; + result[3] = d; +#endif + + // The cpuid instruction succeeded. + return true; +#endif +} +#endif + + namespace KWSYS_NAMESPACE { template<typename T> @@ -307,7 +422,7 @@ public: enum Manufacturer { AMD, Intel, NSC, UMC, Cyrix, NexGen, IDT, Rise, Transmeta, Sun, IBM, - Motorola, UnknownManufacturer + Motorola, HP, UnknownManufacturer }; protected: @@ -335,18 +450,21 @@ protected: int CPUCount(); unsigned char LogicalCPUPerPhysicalCPU(); unsigned char GetAPICId(); - unsigned int IsHyperThreadingSupported(); - LongLong GetCyclesDifference(DELAY_FUNC, unsigned int); + bool IsHyperThreadingSupported(); + static LongLong GetCyclesDifference(DELAY_FUNC, unsigned int); // For Linux and Cygwin, /proc/cpuinfo formats are slightly different - int RetreiveInformationFromCpuInfoFile(); + bool RetreiveInformationFromCpuInfoFile(); kwsys_stl::string ExtractValueFromCpuInfoFile(kwsys_stl::string buffer, const char* word, size_t init=0); + bool QueryLinuxMemory(); + bool QueryCygwinMemory(); + static void Delay (unsigned int); static void DelayOverhead (unsigned int); - void FindManufacturer(); + void FindManufacturer(const kwsys_stl::string &family = ""); // For Mac bool ParseSysCtl(); @@ -356,7 +474,8 @@ protected: kwsys_stl::string SysCtlBuffer; // For Solaris - bool QuerySolarisInfo(); + bool QuerySolarisMemory(); + bool QuerySolarisProcessor(); kwsys_stl::string ParseValueFromKStat(const char* arguments); kwsys_stl::string RunProcess(kwsys_stl::vector<const char*> args); @@ -367,8 +486,26 @@ protected: bool QueryQNXMemory(); bool QueryQNXProcessor(); + //For OpenBSD, FreeBSD, NetBSD, DragonFly + bool QueryBSDMemory(); + bool QueryBSDProcessor(); + + //For HP-UX + bool QueryHPUXMemory(); + bool QueryHPUXProcessor(); + + //For Microsoft Windows + bool QueryWindowsMemory(); + + //For AIX + bool QueryAIXMemory(); + + bool QueryProcessorBySysconf(); + bool QueryProcessor(); + // Evaluate the memory information. - int QueryMemory(); + bool QueryMemoryBySysconf(); + bool QueryMemory(); size_t TotalVirtualMemory; size_t AvailableVirtualMemory; size_t TotalPhysicalMemory; @@ -695,24 +832,11 @@ void SystemInformation::RunMemoryCheck() // -------------------------------------------------------------- // SystemInformationImplementation starts here -#if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(_WIN64) -#define USE_ASM_INSTRUCTIONS 1 -#else -#define USE_ASM_INSTRUCTIONS 0 -#endif - #define STORE_TLBCACHE_INFO(x,y) x = (x < y) ? y : x #define TLBCACHE_INFO_UNITS (15) #define CLASSICAL_CPU_FREQ_LOOP 10000000 #define RDTSC_INSTRUCTION _asm _emit 0x0f _asm _emit 0x31 -#define CPUID_AWARE_COMPILER -#ifdef CPUID_AWARE_COMPILER - #define CPUID_INSTRUCTION cpuid -#else - #define CPUID_INSTRUCTION _asm _emit 0x0f _asm _emit 0xa2 -#endif - #define MMX_FEATURE 0x00000001 #define MMX_PLUS_FEATURE 0x00000002 #define SSE_FEATURE 0x00000004 @@ -1144,6 +1268,7 @@ void SystemInformationImplementation::RunCPUCheck() { // Retrieve the CPU details. RetrieveCPUIdentity(); + this->FindManufacturer(); RetrieveCPUFeatures(); } @@ -1183,13 +1308,19 @@ void SystemInformationImplementation::RunCPUCheck() #elif defined(__APPLE__) this->ParseSysCtl(); #elif defined (__SVR4) && defined (__sun) - this->QuerySolarisInfo(); + this->QuerySolarisProcessor(); #elif defined(__HAIKU__) this->QueryHaikuInfo(); #elif defined(__QNX__) this->QueryQNXProcessor(); -#else +#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) + this->QueryBSDProcessor(); +#elif defined(__hpux) + this->QueryHPUXProcessor(); +#elif defined(__linux) || defined(__CYGWIN__) this->RetreiveInformationFromCpuInfoFile(); +#else + this->QueryProcessor(); #endif } @@ -1203,11 +1334,23 @@ void SystemInformationImplementation::RunMemoryCheck() #if defined(__APPLE__) this->ParseSysCtl(); #elif defined (__SVR4) && defined (__sun) - this->QuerySolarisInfo(); + this->QuerySolarisMemory(); #elif defined(__HAIKU__) this->QueryHaikuInfo(); #elif defined(__QNX__) this->QueryQNXMemory(); +#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) + this->QueryBSDMemory(); +#elif defined(__CYGWIN__) + this->QueryCygwinMemory(); +#elif defined(_WIN32) + this->QueryWindowsMemory(); +#elif defined(__hpux) + this->QueryHPUXMemory(); +#elif defined(__linux) + this->QueryLinuxMemory(); +#elif defined(_AIX) + this->QueryAIXMemory(); #else this->QueryMemory(); #endif @@ -1415,6 +1558,8 @@ const char * SystemInformationImplementation::GetVendorID() return "IBM"; case Motorola: return "Motorola"; + case HP: + return "Hewlett-Packard"; default: return "Unknown Manufacturer"; } @@ -1609,40 +1754,15 @@ void SystemInformationImplementation::Delay(unsigned int uiMS) bool SystemInformationImplementation::DoesCPUSupportCPUID() { -#if USE_ASM_INSTRUCTIONS - // Use SEH to determine CPUID presence - __try { - _asm { -#ifdef CPUID_AWARE_COMPILER - ; we must push/pop the registers <<CPUID>> writes to, as the - ; optimiser doesn't know about <<CPUID>>, and so doesn't expect - ; these registers to change. - push eax - push ebx - push ecx - push edx -#endif - ; <<CPUID>> - mov eax, 0 - CPUID_INSTRUCTION +#if USE_CPUID + int dummy[4] = { 0, 0, 0, 0 }; -#ifdef CPUID_AWARE_COMPILER - pop edx - pop ecx - pop ebx - pop eax +#if USE_ASM_INSTRUCTIONS + return call_cpuid(0, dummy); +#else + call_cpuid(0, dummy); + return dummy[0] || dummy[1] || dummy[2] || dummy[3]; #endif - } - } - __except(1) - { - // Stop the class from trying to use CPUID again! - return false; - } - - // The cpuid instruction succeeded. - return true; - #else // Assume no cpuid instruction. return false; @@ -1652,58 +1772,29 @@ bool SystemInformationImplementation::DoesCPUSupportCPUID() bool SystemInformationImplementation::RetrieveCPUFeatures() { -#if USE_ASM_INSTRUCTIONS - int localCPUFeatures = 0; - int localCPUAdvanced = 0; - - // Use assembly to detect CPUID information... - __try { - _asm { -#ifdef CPUID_AWARE_COMPILER - ; we must push/pop the registers <<CPUID>> writes to, as the - ; optimiser doesn't know about <<CPUID>>, and so doesn't expect - ; these registers to change. - push eax - push ebx - push ecx - push edx -#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 - ; edx: CPU feature flags - mov eax,1 - CPUID_INSTRUCTION - mov localCPUFeatures, edx - mov localCPUAdvanced, ebx +#if USE_CPUID + int cpuinfo[4] = { 0, 0, 0, 0 }; -#ifdef CPUID_AWARE_COMPILER - pop edx - pop ecx - pop ebx - pop eax -#endif - } - } - __except(1) + if (!call_cpuid(1, cpuinfo)) { return false; } // Retrieve the features of CPU present. - this->Features.HasFPU = ((localCPUFeatures & 0x00000001) != 0); // FPU Present --> Bit 0 - this->Features.HasTSC = ((localCPUFeatures & 0x00000010) != 0); // TSC Present --> Bit 4 - this->Features.HasAPIC = ((localCPUFeatures & 0x00000200) != 0); // APIC Present --> Bit 9 - this->Features.HasMTRR = ((localCPUFeatures & 0x00001000) != 0); // MTRR Present --> Bit 12 - this->Features.HasCMOV = ((localCPUFeatures & 0x00008000) != 0); // CMOV Present --> Bit 15 - this->Features.HasSerial = ((localCPUFeatures & 0x00040000) != 0); // Serial Present --> Bit 18 - this->Features.HasACPI = ((localCPUFeatures & 0x00400000) != 0); // ACPI Capable --> Bit 22 - this->Features.HasMMX = ((localCPUFeatures & 0x00800000) != 0); // MMX Present --> Bit 23 - this->Features.HasSSE = ((localCPUFeatures & 0x02000000) != 0); // SSE Present --> Bit 25 - this->Features.HasSSE2 = ((localCPUFeatures & 0x04000000) != 0); // SSE2 Present --> Bit 26 - this->Features.HasThermal = ((localCPUFeatures & 0x20000000) != 0); // Thermal Monitor Present --> Bit 29 - this->Features.HasIA64 = ((localCPUFeatures & 0x40000000) != 0); // IA64 Present --> Bit 30 + this->Features.HasFPU = ((cpuinfo[3] & 0x00000001) != 0); // FPU Present --> Bit 0 + this->Features.HasTSC = ((cpuinfo[3] & 0x00000010) != 0); // TSC Present --> Bit 4 + this->Features.HasAPIC = ((cpuinfo[3] & 0x00000200) != 0); // APIC Present --> Bit 9 + this->Features.HasMTRR = ((cpuinfo[3] & 0x00001000) != 0); // MTRR Present --> Bit 12 + this->Features.HasCMOV = ((cpuinfo[3] & 0x00008000) != 0); // CMOV Present --> Bit 15 + this->Features.HasSerial = ((cpuinfo[3] & 0x00040000) != 0); // Serial Present --> Bit 18 + this->Features.HasACPI = ((cpuinfo[3] & 0x00400000) != 0); // ACPI Capable --> Bit 22 + this->Features.HasMMX = ((cpuinfo[3] & 0x00800000) != 0); // MMX Present --> Bit 23 + this->Features.HasSSE = ((cpuinfo[3] & 0x02000000) != 0); // SSE Present --> Bit 25 + this->Features.HasSSE2 = ((cpuinfo[3] & 0x04000000) != 0); // SSE2 Present --> Bit 26 + this->Features.HasThermal = ((cpuinfo[3] & 0x20000000) != 0); // Thermal Monitor Present --> Bit 29 + this->Features.HasIA64 = ((cpuinfo[3] & 0x40000000) != 0); // IA64 Present --> Bit 30 +#if USE_ASM_INSTRUCTIONS // Retrieve extended SSE capabilities if SSE is available. if (this->Features.HasSSE) { @@ -1732,17 +1823,20 @@ bool SystemInformationImplementation::RetrieveCPUFeatures() // Set the advanced SSE capabilities to not available. this->Features.HasSSEFP = false; } +#else + this->Features.HasSSEFP = false; +#endif // Retrieve Intel specific extended features. if (this->ChipManufacturer == Intel) { - this->Features.ExtendedFeatures.SupportsHyperthreading = ((localCPUFeatures & 0x10000000) != 0); // Intel specific: Hyperthreading --> Bit 28 - this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = (this->Features.ExtendedFeatures.SupportsHyperthreading) ? ((localCPUAdvanced & 0x00FF0000) >> 16) : 1; + this->Features.ExtendedFeatures.SupportsHyperthreading = ((cpuinfo[3] & 0x10000000) != 0); // Intel specific: Hyperthreading --> Bit 28 + this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = (this->Features.ExtendedFeatures.SupportsHyperthreading) ? ((cpuinfo[1] & 0x00FF0000) >> 16) : 1; if ((this->Features.ExtendedFeatures.SupportsHyperthreading) && (this->Features.HasAPIC)) { // Retrieve APIC information if there is one present. - this->Features.ExtendedFeatures.APIC_ID = ((localCPUAdvanced & 0xFF000000) >> 24); + this->Features.ExtendedFeatures.APIC_ID = ((cpuinfo[1] & 0xFF000000) >> 24); } } @@ -1755,7 +1849,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. @@ -1770,7 +1864,9 @@ void SystemInformationImplementation::FindManufacturer() else if (this->ChipID.Vendor == "Geode By NSC") this->ChipManufacturer = NSC; // National Semiconductor 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 == "Hewlett-Packard") this->ChipManufacturer = HP; // Hewlett-Packard 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 } @@ -1778,73 +1874,41 @@ void SystemInformationImplementation::FindManufacturer() /** */ bool SystemInformationImplementation::RetrieveCPUIdentity() { -#if USE_ASM_INSTRUCTIONS - int localCPUVendor[3]; - int localCPUSignature; +#if USE_CPUID + int localCPUVendor[4]; + int localCPUSignature[4]; - // Use assembly to detect CPUID information... - __try + if (!call_cpuid(0, localCPUVendor)) { - _asm - { -#ifdef CPUID_AWARE_COMPILER - ; we must push/pop the registers <<CPUID>> writes to, as the - ; optimiser doesn't know about <<CPUID>>, and so doesn't expect - ; these registers to change. - push eax - push ebx - push ecx - push edx -#endif - ; <<CPUID>> - ; eax = 0 --> eax: maximum value of CPUID instruction. - ; ebx: part 1 of 3; CPU signature. - ; edx: part 2 of 3; CPU signature. - ; ecx: part 3 of 3; CPU signature. - mov eax, 0 - CPUID_INSTRUCTION - mov localCPUVendor[0 * TYPE int], ebx - mov localCPUVendor[1 * TYPE int], edx - mov localCPUVendor[2 * TYPE int], ecx - - ; <<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 - ; edx: CPU feature flags - mov eax,1 - CPUID_INSTRUCTION - mov localCPUSignature, eax - -#ifdef CPUID_AWARE_COMPILER - pop edx - pop ecx - pop ebx - pop eax -#endif + return false; } - } - __except(1) + if (!call_cpuid(1, localCPUSignature)) { return false; } // Process the returned information. + // ; eax = 0 --> eax: maximum value of CPUID instruction. + // ; ebx: part 1 of 3; CPU signature. + // ; edx: part 2 of 3; CPU signature. + // ; ecx: part 3 of 3; CPU signature. char vbuf[13]; - memcpy (&(vbuf[0]), &(localCPUVendor[0]), sizeof (int)); - memcpy (&(vbuf[4]), &(localCPUVendor[1]), sizeof (int)); + memcpy (&(vbuf[0]), &(localCPUVendor[1]), sizeof (int)); + memcpy (&(vbuf[4]), &(localCPUVendor[3]), sizeof (int)); memcpy (&(vbuf[8]), &(localCPUVendor[2]), sizeof (int)); 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 - this->ChipID.Type = ((localCPUSignature & 0x0000F000) >> 12); // Bits 15..12 Used - this->ChipID.Family = ((localCPUSignature & 0x00000F00) >> 8); // Bits 11..8 Used - this->ChipID.Model = ((localCPUSignature & 0x000000F0) >> 4); // Bits 7..4 Used - this->ChipID.Revision = ((localCPUSignature & 0x0000000F) >> 0); // Bits 3..0 Used + // ; 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 processor ID, 15..8 - CFLUSH chunk size , 7..0 - brand ID + // ; edx: CPU feature flags + this->ChipID.ExtendedFamily = ((localCPUSignature[0] & 0x0FF00000) >> 20); // Bits 27..20 Used + this->ChipID.ExtendedModel = ((localCPUSignature[0] & 0x000F0000) >> 16); // Bits 19..16 Used + this->ChipID.Type = ((localCPUSignature[0] & 0x0000F000) >> 12); // Bits 15..12 Used + this->ChipID.Family = ((localCPUSignature[0] & 0x00000F00) >> 8); // Bits 11..8 Used + this->ChipID.Model = ((localCPUSignature[0] & 0x000000F0) >> 4); // Bits 7..4 Used + this->ChipID.Revision = ((localCPUSignature[0] & 0x0000000F) >> 0); // Bits 3..0 Used return true; @@ -1857,48 +1921,14 @@ bool SystemInformationImplementation::RetrieveCPUIdentity() /** */ bool SystemInformationImplementation::RetrieveCPUCacheDetails() { -#if USE_ASM_INSTRUCTIONS +#if USE_CPUID int L1Cache[4] = { 0, 0, 0, 0 }; int L2Cache[4] = { 0, 0, 0, 0 }; // Check to see if what we are about to do is supported... if (RetrieveCPUExtendedLevelSupport (0x80000005)) { - // Use assembly to retrieve the L1 cache information ... - __try - { - _asm - { -#ifdef CPUID_AWARE_COMPILER - ; we must push/pop the registers <<CPUID>> writes to, as the - ; optimiser doesn't know about <<CPUID>>, and so doesn't expect - ; these registers to change. - push eax - push ebx - push ecx - push edx -#endif - ; <<CPUID>> - ; eax = 0x80000005 --> eax: L1 cache information - Part 1 of 4. - ; ebx: L1 cache information - Part 2 of 4. - ; edx: L1 cache information - Part 3 of 4. - ; ecx: L1 cache information - Part 4 of 4. - mov eax, 0x80000005 - CPUID_INSTRUCTION - mov L1Cache[0 * TYPE int], eax - mov L1Cache[1 * TYPE int], ebx - mov L1Cache[2 * TYPE int], ecx - mov L1Cache[3 * TYPE int], edx - -#ifdef CPUID_AWARE_COMPILER - pop edx - pop ecx - pop ebx - pop eax -#endif - } - } - __except(1) + if (!call_cpuid(0x80000005, L1Cache)) { return false; } @@ -1915,41 +1945,7 @@ bool SystemInformationImplementation::RetrieveCPUCacheDetails() // Check to see if what we are about to do is supported... if (RetrieveCPUExtendedLevelSupport (0x80000006)) { - // Use assembly to retrieve the L2 cache information ... - __try - { - _asm - { -#ifdef CPUID_AWARE_COMPILER - ; we must push/pop the registers <<CPUID>> writes to, as the - ; optimiser doesn't know about <<CPUID>>, and so doesn't expect - ; these registers to change. - push eax - push ebx - push ecx - push edx -#endif - ; <<CPUID>> - ; eax = 0x80000006 --> eax: L2 cache information - Part 1 of 4. - ; ebx: L2 cache information - Part 2 of 4. - ; edx: L2 cache information - Part 3 of 4. - ; ecx: L2 cache information - Part 4 of 4. - mov eax, 0x80000006 - CPUID_INSTRUCTION - mov L2Cache[0 * TYPE int], eax - mov L2Cache[1 * TYPE int], ebx - mov L2Cache[2 * TYPE int], ecx - mov L2Cache[3 * TYPE int], edx - -#ifdef CPUID_AWARE_COMPILER - pop edx - pop ecx - pop ebx - pop eax -#endif - } - } - __except(1) + if (!call_cpuid(0x80000006, L2Cache)) { return false; } @@ -1975,7 +1971,7 @@ bool SystemInformationImplementation::RetrieveCPUCacheDetails() /** */ bool SystemInformationImplementation::RetrieveClassicalCPUCacheDetails() { -#if USE_ASM_INSTRUCTIONS +#if USE_CPUID int TLBCode = -1, TLBData = -1, L1Code = -1, L1Data = -1, L1Trace = -1, L2Unified = -1, L3Unified = -1; int TLBCacheData[4] = { 0, 0, 0, 0 }; int TLBPassCounter = 0; @@ -1983,39 +1979,7 @@ bool SystemInformationImplementation::RetrieveClassicalCPUCacheDetails() do { - // Use assembly to retrieve the L2 cache information ... - __try { - _asm { -#ifdef CPUID_AWARE_COMPILER - ; we must push/pop the registers <<CPUID>> writes to, as the - ; optimiser doesn't know about <<CPUID>>, and so doesn't expect - ; these registers to change. - push eax - push ebx - push ecx - push edx -#endif - ; <<CPUID>> - ; eax = 2 --> eax: TLB and cache information - Part 1 of 4. - ; ebx: TLB and cache information - Part 2 of 4. - ; ecx: TLB and cache information - Part 3 of 4. - ; edx: TLB and cache information - Part 4 of 4. - mov eax, 2 - CPUID_INSTRUCTION - mov TLBCacheData[0 * TYPE int], eax - mov TLBCacheData[1 * TYPE int], ebx - mov TLBCacheData[2 * TYPE int], ecx - mov TLBCacheData[3 * TYPE int], edx - -#ifdef CPUID_AWARE_COMPILER - pop edx - pop ecx - pop ebx - pop eax -#endif - } - } - __except(1) + if (!call_cpuid(2, TLBCacheData)) { return false; } @@ -2182,11 +2146,40 @@ bool SystemInformationImplementation::RetrieveCPUClockSpeed() bool retrieved = false; #if defined(_WIN32) - // First of all we check to see if the RDTSC (0x0F, 0x31) instruction is - // supported. If not, we fallback to trying to read this value from the - // registry: - // - if (!this->Features.HasTSC) + unsigned int uiRepetitions = 1; + unsigned int uiMSecPerRepetition = 50; + __int64 i64Total = 0; + __int64 i64Overhead = 0; + + // Check if the TSC implementation works at all + if (this->Features.HasTSC && + GetCyclesDifference(SystemInformationImplementation::Delay, + uiMSecPerRepetition) > 0) + { + for (unsigned int nCounter = 0; nCounter < uiRepetitions; nCounter ++) + { + i64Total += GetCyclesDifference (SystemInformationImplementation::Delay, + uiMSecPerRepetition); + i64Overhead += + GetCyclesDifference (SystemInformationImplementation::DelayOverhead, + uiMSecPerRepetition); + } + + // Calculate the MHz speed. + i64Total -= i64Overhead; + i64Total /= uiRepetitions; + i64Total /= uiMSecPerRepetition; + i64Total /= 1000; + + // Save the CPU speed. + this->CPUSpeedInMHz = (float) i64Total; + + retrieved = true; + } + + // If RDTSC is not supported, we fallback to trying to read this value + // from the registry: + if (!retrieved) { HKEY hKey = NULL; LONG err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, @@ -2211,34 +2204,7 @@ bool SystemInformationImplementation::RetrieveCPUClockSpeed() RegCloseKey(hKey); hKey = NULL; } - - return retrieved; - } - - unsigned int uiRepetitions = 1; - unsigned int uiMSecPerRepetition = 50; - __int64 i64Total = 0; - __int64 i64Overhead = 0; - - for (unsigned int nCounter = 0; nCounter < uiRepetitions; nCounter ++) - { - i64Total += GetCyclesDifference (SystemInformationImplementation::Delay, - uiMSecPerRepetition); - i64Overhead += - GetCyclesDifference (SystemInformationImplementation::DelayOverhead, - uiMSecPerRepetition); } - - // Calculate the MHz speed. - i64Total -= i64Overhead; - i64Total /= uiRepetitions; - i64Total /= uiMSecPerRepetition; - i64Total /= 1000; - - // Save the CPU speed. - this->CPUSpeedInMHz = (float) i64Total; - - retrieved = true; #endif return retrieved; @@ -2310,7 +2276,7 @@ bool SystemInformationImplementation::RetrieveClassicalCPUClockSpeed() /** */ bool SystemInformationImplementation::RetrieveCPUExtendedLevelSupport(int CPULevelToCheck) { - int MaxCPUExtendedLevel = 0; + int cpuinfo[4] = { 0, 0, 0, 0 }; // The extended CPUID is supported by various vendors starting with the following CPU models: // @@ -2353,35 +2319,8 @@ bool SystemInformationImplementation::RetrieveCPUExtendedLevelSupport(int CPULev } } -#if USE_ASM_INSTRUCTIONS - - // Use assembly to detect CPUID information... - __try { - _asm { -#ifdef CPUID_AWARE_COMPILER - ; we must push/pop the registers <<CPUID>> writes to, as the - ; optimiser doesn't know about <<CPUID>>, and so doesn't expect - ; these registers to change. - push eax - push ebx - push ecx - push edx -#endif - ; <<CPUID>> - ; eax = 0x80000000 --> eax: maximum supported extended level - mov eax,0x80000000 - CPUID_INSTRUCTION - mov MaxCPUExtendedLevel, eax - -#ifdef CPUID_AWARE_COMPILER - pop edx - pop ecx - pop ebx - pop eax -#endif - } - } - __except(1) +#if USE_CPUID + if (!call_cpuid(0x80000000, cpuinfo)) { return false; } @@ -2389,7 +2328,7 @@ bool SystemInformationImplementation::RetrieveCPUExtendedLevelSupport(int CPULev // Now we have to check the level wanted vs level returned... int nLevelWanted = (CPULevelToCheck & 0x7FFFFFFF); - int nLevelReturn = (MaxCPUExtendedLevel & 0x7FFFFFFF); + int nLevelReturn = (cpuinfo[0] & 0x7FFFFFFF); // Check to see if the level provided is supported... if (nLevelWanted > nLevelReturn) @@ -2417,60 +2356,30 @@ bool SystemInformationImplementation::RetrieveExtendedCPUFeatures() return false; } -#if USE_ASM_INSTRUCTIONS - int localCPUExtendedFeatures = 0; +#if USE_CPUID + int localCPUExtendedFeatures[4] = { 0, 0, 0, 0 }; - // Use assembly to detect CPUID information... - __try - { - _asm - { -#ifdef CPUID_AWARE_COMPILER - ; we must push/pop the registers <<CPUID>> writes to, as the - ; optimiser doesn't know about <<CPUID>>, and so doesn't expect - ; these registers to change. - push eax - push ebx - push ecx - push edx -#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 - ; edx: CPU feature flags - mov eax,0x80000001 - CPUID_INSTRUCTION - mov localCPUExtendedFeatures, edx - -#ifdef CPUID_AWARE_COMPILER - pop edx - pop ecx - pop ebx - pop eax -#endif - } - } - __except(1) + if (!call_cpuid(0x80000001, localCPUExtendedFeatures)) { return false; } // Retrieve the extended features of CPU present. - this->Features.ExtendedFeatures.Has3DNow = ((localCPUExtendedFeatures & 0x80000000) != 0); // 3DNow Present --> Bit 31. - this->Features.ExtendedFeatures.Has3DNowPlus = ((localCPUExtendedFeatures & 0x40000000) != 0); // 3DNow+ Present -- > Bit 30. - this->Features.ExtendedFeatures.HasSSEMMX = ((localCPUExtendedFeatures & 0x00400000) != 0); // SSE MMX Present --> Bit 22. - this->Features.ExtendedFeatures.SupportsMP = ((localCPUExtendedFeatures & 0x00080000) != 0); // MP Capable -- > Bit 19. + this->Features.ExtendedFeatures.Has3DNow = ((localCPUExtendedFeatures[3] & 0x80000000) != 0); // 3DNow Present --> Bit 31. + this->Features.ExtendedFeatures.Has3DNowPlus = ((localCPUExtendedFeatures[3] & 0x40000000) != 0); // 3DNow+ Present -- > Bit 30. + this->Features.ExtendedFeatures.HasSSEMMX = ((localCPUExtendedFeatures[3] & 0x00400000) != 0); // SSE MMX Present --> Bit 22. + this->Features.ExtendedFeatures.SupportsMP = ((localCPUExtendedFeatures[3] & 0x00080000) != 0); // MP Capable -- > Bit 19. // Retrieve AMD specific extended features. if (this->ChipManufacturer == AMD) { - this->Features.ExtendedFeatures.HasMMXPlus = ((localCPUExtendedFeatures & 0x00400000) != 0); // AMD specific: MMX-SSE --> Bit 22 + this->Features.ExtendedFeatures.HasMMXPlus = ((localCPUExtendedFeatures[3] & 0x00400000) != 0); // AMD specific: MMX-SSE --> Bit 22 } // Retrieve Cyrix specific extended features. if (this->ChipManufacturer == Cyrix) { - this->Features.ExtendedFeatures.HasMMXPlus = ((localCPUExtendedFeatures & 0x01000000) != 0); // Cyrix specific: Extended MMX --> Bit 24 + this->Features.ExtendedFeatures.HasMMXPlus = ((localCPUExtendedFeatures[3] & 0x01000000) != 0); // Cyrix specific: Extended MMX --> Bit 24 } return true; @@ -2490,51 +2399,20 @@ bool SystemInformationImplementation::RetrieveProcessorSerialNumber() return false; } -#if USE_ASM_INSTRUCTIONS - int SerialNumber[3]; - - // Use assembly to detect CPUID information... - __try { - _asm { -#ifdef CPUID_AWARE_COMPILER - ; we must push/pop the registers <<CPUID>> writes to, as the - ; optimiser doesn't know about <<CPUID>>, and so doesn't expect - ; these registers to change. - push eax - push ebx - push ecx - push edx -#endif - ; <<CPUID>> - ; eax = 3 --> ebx: top 32 bits are the processor signature bits --> NB: Transmeta only ?!? - ; ecx: middle 32 bits are the processor signature bits - ; edx: bottom 32 bits are the processor signature bits - mov eax, 3 - CPUID_INSTRUCTION - mov SerialNumber[0 * TYPE int], ebx - mov SerialNumber[1 * TYPE int], ecx - mov SerialNumber[2 * TYPE int], edx +#if USE_CPUID + int SerialNumber[4]; -#ifdef CPUID_AWARE_COMPILER - pop edx - pop ecx - pop ebx - pop eax -#endif - } - } - __except(1) + if (!call_cpuid(3, SerialNumber)) { return false; } // Process the returned information. + // ; eax = 3 --> ebx: top 32 bits are the processor signature bits --> NB: Transmeta only ?!? + // ; ecx: middle 32 bits are the processor signature bits + // ; edx: bottom 32 bits are the processor signature bits char sn[128]; sprintf (sn, "%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x", - ((SerialNumber[0] & 0xff000000) >> 24), - ((SerialNumber[0] & 0x00ff0000) >> 16), - ((SerialNumber[0] & 0x0000ff00) >> 8), - ((SerialNumber[0] & 0x000000ff) >> 0), ((SerialNumber[1] & 0xff000000) >> 24), ((SerialNumber[1] & 0x00ff0000) >> 16), ((SerialNumber[1] & 0x0000ff00) >> 8), @@ -2542,7 +2420,11 @@ bool SystemInformationImplementation::RetrieveProcessorSerialNumber() ((SerialNumber[2] & 0xff000000) >> 24), ((SerialNumber[2] & 0x00ff0000) >> 16), ((SerialNumber[2] & 0x0000ff00) >> 8), - ((SerialNumber[2] & 0x000000ff) >> 0)); + ((SerialNumber[2] & 0x000000ff) >> 0), + ((SerialNumber[3] & 0xff000000) >> 24), + ((SerialNumber[3] & 0x00ff0000) >> 16), + ((SerialNumber[3] & 0x0000ff00) >> 8), + ((SerialNumber[3] & 0x000000ff) >> 0)); this->ChipID.SerialNumber = sn; return true; @@ -2564,45 +2446,18 @@ bool SystemInformationImplementation::RetrieveCPUPowerManagement() return false; } -#if USE_ASM_INSTRUCTIONS - int localCPUPowerManagement = 0; - +#if USE_CPUID + int localCPUPowerManagement[4] = { 0, 0, 0, 0 }; - // Use assembly to detect CPUID information... - __try { - _asm { -#ifdef CPUID_AWARE_COMPILER - ; we must push/pop the registers <<CPUID>> writes to, as the - ; optimiser doesn't know about <<CPUID>>, and so doesn't expect - ; these registers to change. - push eax - push ebx - push ecx - push edx -#endif - ; <<CPUID>> - ; eax = 0x80000007 --> edx: get processor power management - mov eax,0x80000007 - CPUID_INSTRUCTION - mov localCPUPowerManagement, edx - -#ifdef CPUID_AWARE_COMPILER - pop edx - pop ecx - pop ebx - pop eax -#endif - } - } - __except(1) + if (!call_cpuid(0x80000007, localCPUPowerManagement)) { return false; } // Check for the power management capabilities of the CPU. - this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = ((localCPUPowerManagement & 0x00000001) != 0); - this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = ((localCPUPowerManagement & 0x00000002) != 0); - this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = ((localCPUPowerManagement & 0x00000004) != 0); + this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = ((localCPUPowerManagement[3] & 0x00000001) != 0); + this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = ((localCPUPowerManagement[3] & 0x00000002) != 0); + this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = ((localCPUPowerManagement[3] & 0x00000004) != 0); return true; @@ -2632,57 +2487,18 @@ bool SystemInformationImplementation::RetrieveExtendedCPUIdentity() if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000004))) return false; -#if USE_ASM_INSTRUCTIONS +#if USE_CPUID int CPUExtendedIdentity[12]; - // Use assembly to detect CPUID information... - __try { - _asm { -#ifdef CPUID_AWARE_COMPILER - ; we must push/pop the registers <<CPUID>> writes to, as the - ; optimiser doesn't know about <<CPUID>>, and so doesn't expect - ; these registers to change. - push eax - push ebx - push ecx - push edx -#endif - ; <<CPUID>> - ; eax = 0x80000002 --> eax, ebx, ecx, edx: get processor name string (part 1) - mov eax,0x80000002 - CPUID_INSTRUCTION - mov CPUExtendedIdentity[0 * TYPE int], eax - mov CPUExtendedIdentity[1 * TYPE int], ebx - mov CPUExtendedIdentity[2 * TYPE int], ecx - mov CPUExtendedIdentity[3 * TYPE int], edx - - ; <<CPUID>> - ; eax = 0x80000003 --> eax, ebx, ecx, edx: get processor name string (part 2) - mov eax,0x80000003 - CPUID_INSTRUCTION - mov CPUExtendedIdentity[4 * TYPE int], eax - mov CPUExtendedIdentity[5 * TYPE int], ebx - mov CPUExtendedIdentity[6 * TYPE int], ecx - mov CPUExtendedIdentity[7 * TYPE int], edx - - ; <<CPUID>> - ; eax = 0x80000004 --> eax, ebx, ecx, edx: get processor name string (part 3) - mov eax,0x80000004 - CPUID_INSTRUCTION - mov CPUExtendedIdentity[8 * TYPE int], eax - mov CPUExtendedIdentity[9 * TYPE int], ebx - mov CPUExtendedIdentity[10 * TYPE int], ecx - mov CPUExtendedIdentity[11 * TYPE int], edx - -#ifdef CPUID_AWARE_COMPILER - pop edx - pop ecx - pop ebx - pop eax -#endif + if (!call_cpuid(0x80000002, CPUExtendedIdentity)) + { + return false; } - } - __except(1) + if (!call_cpuid(0x80000003, CPUExtendedIdentity + 4)) + { + return false; + } + if (!call_cpuid(0x80000004, CPUExtendedIdentity + 8)) { return false; } @@ -3002,6 +2818,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); } } @@ -3010,7 +2836,7 @@ kwsys_stl::string SystemInformationImplementation::ExtractValueFromCpuInfoFile(k } /** Query for the cpu status */ -int SystemInformationImplementation::RetreiveInformationFromCpuInfoFile() +bool SystemInformationImplementation::RetreiveInformationFromCpuInfoFile() { this->NumberOfLogicalCPU = 0; this->NumberOfPhysicalCPU = 0; @@ -3020,7 +2846,7 @@ int SystemInformationImplementation::RetreiveInformationFromCpuInfoFile() if ( !fd ) { kwsys_ios::cout << "Problem opening /proc/cpuinfo" << kwsys_ios::endl; - return 0; + return false; } size_t fileSize = 0; @@ -3073,7 +2899,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,33 +2908,161 @@ 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; + + // processor feature flags (probably x86 specific) + kwsys_stl::string cpuflags = this->ExtractValueFromCpuInfoFile(buffer,"flags"); + if(!cpurev.empty()) + { + // now we can match every flags as space + flag + space + cpuflags = " " + cpuflags + " "; + if ((cpuflags.find(" fpu ")!=kwsys_stl::string::npos)) + { + this->Features.HasFPU = true; + } + if ((cpuflags.find(" tsc ")!=kwsys_stl::string::npos)) + { + this->Features.HasTSC = true; + } + if ((cpuflags.find(" mmx ")!=kwsys_stl::string::npos)) + { + this->Features.HasMMX = true; + } + if ((cpuflags.find(" sse ")!=kwsys_stl::string::npos)) + { + this->Features.HasSSE = true; + } + if ((cpuflags.find(" sse2 ")!=kwsys_stl::string::npos)) + { + this->Features.HasSSE2 = true; + } + if ((cpuflags.find(" apic ")!=kwsys_stl::string::npos)) + { + this->Features.HasAPIC = true; + } + if ((cpuflags.find(" cmov ")!=kwsys_stl::string::npos)) + { + this->Features.HasCMOV = true; + } + if ((cpuflags.find(" mtrr ")!=kwsys_stl::string::npos)) + { + this->Features.HasMTRR = true; + } + if ((cpuflags.find(" acpi ")!=kwsys_stl::string::npos)) + { + this->Features.HasACPI = true; + } + if ((cpuflags.find(" 3dnow ")!=kwsys_stl::string::npos)) + { + this->Features.ExtendedFeatures.Has3DNow = true; + } + } + + return true; +} + +bool SystemInformationImplementation::QueryProcessorBySysconf() +{ +#if defined(_SC_NPROC_ONLN) && !defined(_SC_NPROCESSORS_ONLN) +// IRIX names this slightly different +# define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN +#endif + +#ifdef _SC_NPROCESSORS_ONLN + long c = sysconf(_SC_NPROCESSORS_ONLN); + if (c <= 0) + { + return false; + } + + this->NumberOfPhysicalCPU = static_cast<unsigned int>(c); + this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; + + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryProcessor() +{ + return this->QueryProcessorBySysconf(); } /** @@ -3438,16 +3392,9 @@ void SystemInformationImplementation::SetStackTraceOnError(int enable) #endif } -/** Query for the memory status */ -int SystemInformationImplementation::QueryMemory() +bool SystemInformationImplementation::QueryWindowsMemory() { - this->TotalVirtualMemory = 0; - this->TotalPhysicalMemory = 0; - this->AvailableVirtualMemory = 0; - this->AvailablePhysicalMemory = 0; -#ifdef __CYGWIN__ - return 0; -#elif defined(_WIN32) +#if defined(_WIN32) # if defined(_MSC_VER) && _MSC_VER < 1300 MEMORYSTATUS ms; unsigned long tv, tp, av, ap; @@ -3472,8 +3419,15 @@ int SystemInformationImplementation::QueryMemory() this->TotalPhysicalMemory = tp>>10>>10; this->AvailableVirtualMemory = av>>10>>10; this->AvailablePhysicalMemory = ap>>10>>10; - return 1; -#elif defined(__linux) + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryLinuxMemory() +{ +#if defined(__linux) unsigned long tv=0; unsigned long tp=0; unsigned long av=0; @@ -3490,7 +3444,7 @@ int SystemInformationImplementation::QueryMemory() if( errorFlag!=0 ) { kwsys_ios::cout << "Problem calling uname(): " << strerror(errno) << kwsys_ios::endl; - return 0; + return false; } if( unameInfo.release!=0 && strlen(unameInfo.release)>=3 ) @@ -3514,7 +3468,7 @@ int SystemInformationImplementation::QueryMemory() if ( !fd ) { kwsys_ios::cout << "Problem opening /proc/meminfo" << kwsys_ios::endl; - return 0; + return false; } if( linuxMajor>=3 || ( (linuxMajor>=2) && (linuxMinor>=6) ) ) @@ -3553,7 +3507,7 @@ int SystemInformationImplementation::QueryMemory() { kwsys_ios::cout << "Problem parsing /proc/meminfo" << kwsys_ios::endl; fclose(fd); - return 0; + return false; } } else @@ -3585,42 +3539,95 @@ int SystemInformationImplementation::QueryMemory() { kwsys_ios::cout << "Problem parsing /proc/meminfo" << kwsys_ios::endl; fclose(fd); - return 0; + return false; } } fclose( fd ); - return 1; -#elif defined(__hpux) - unsigned long tv=0; - unsigned long tp=0; - unsigned long av=0; - unsigned long ap=0; - struct pst_static pst; - struct pst_dynamic pdy; - unsigned long ps = 0; - if (pstat_getstatic(&pst, sizeof(pst), (size_t) 1, 0) != -1) + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryCygwinMemory() +{ +#ifdef __CYGWIN__ + // _SC_PAGE_SIZE does return the mmap() granularity on Cygwin, + // see http://cygwin.com/ml/cygwin/2006-06/msg00350.html + // Therefore just use 4096 as the page size of Windows. + long m = sysconf(_SC_PHYS_PAGES); + if (m < 0) { - ps = pst.page_size; - tp = pst.physical_memory *ps; - tv = (pst.physical_memory + pst.pst_maxmem) * ps; - if (pstat_getdynamic(&pdy, sizeof(pdy), (size_t) 1, 0) != -1) - { - ap = tp - pdy.psd_rm * ps; - av = tv - pdy.psd_vm; - this->TotalVirtualMemory = tv>>10>>10; - this->TotalPhysicalMemory = tp>>10>>10; - this->AvailableVirtualMemory = av>>10>>10; - this->AvailablePhysicalMemory = ap>>10>>10; - return 1; - } + return false; } - return 0; + this->TotalPhysicalMemory = m >> 8; + return true; #else - return 0; + return false; +#endif +} + +bool SystemInformationImplementation::QueryAIXMemory() +{ +#if defined(_AIX) + long c = sysconf(_SC_AIX_REALMEM); + if (c <= 0) + { + return false; + } + + this->TotalPhysicalMemory = c / 1024; + + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryMemoryBySysconf() +{ +#if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE) + // Assume the mmap() granularity as returned by _SC_PAGESIZE is also + // the system page size. The only known system where this isn't true + // is Cygwin. + long p = sysconf(_SC_PHYS_PAGES); + long m = sysconf(_SC_PAGESIZE); + + if (p < 0 || m < 0) + { + return false; + } + + // assume pagesize is a power of 2 and smaller 1 MiB + size_t pagediv = (1024 * 1024 / m); + + this->TotalPhysicalMemory = p; + this->TotalPhysicalMemory /= pagediv; + +#if defined(_SC_AVPHYS_PAGES) + p = sysconf(_SC_AVPHYS_PAGES); + if (p < 0) + { + return false; + } + + this->AvailablePhysicalMemory = p; + this->AvailablePhysicalMemory /= pagediv; +#endif + + return true; +#else + return false; #endif } +/** Query for the memory status */ +bool SystemInformationImplementation::QueryMemory() +{ + return this->QueryMemoryBySysconf(); +} + /** */ size_t SystemInformationImplementation::GetTotalVirtualMemory() { @@ -3649,7 +3656,15 @@ SystemInformation::LongLong SystemInformationImplementation::GetCyclesDifference (DELAY_FUNC DelayFunction, unsigned int uiParameter) { -#if USE_ASM_INSTRUCTIONS +#if defined(_MSC_VER) && (_MSC_VER >= 1400) + unsigned __int64 stamp1, stamp2; + + stamp1 = __rdtsc(); + DelayFunction(uiParameter); + stamp2 = __rdtsc(); + + return stamp2 - stamp1; +#elif USE_ASM_INSTRUCTIONS unsigned int edx1, eax1; unsigned int edx2, eax2; @@ -3731,61 +3746,53 @@ unsigned char SystemInformationImplementation::LogicalCPUPerPhysicalCPU(void) } return static_cast<unsigned char>(cores_per_package); #else - unsigned int Regebx = 0; -#if USE_ASM_INSTRUCTIONS + int Regs[4] = { 0, 0, 0, 0 }; +#if USE_CPUID if (!this->IsHyperThreadingSupported()) { return static_cast<unsigned char>(1); // HT not supported } - __asm - { - mov eax, 1 - cpuid - mov Regebx, ebx - } + call_cpuid(1, Regs); #endif - return static_cast<unsigned char> ((Regebx & NUM_LOGICAL_BITS) >> 16); + return static_cast<unsigned char> ((Regs[1] & NUM_LOGICAL_BITS) >> 16); #endif } /** Works only for windows */ -unsigned int SystemInformationImplementation::IsHyperThreadingSupported() +bool SystemInformationImplementation::IsHyperThreadingSupported() { -#if USE_ASM_INSTRUCTIONS - unsigned int Regedx = 0, - Regeax = 0, - VendorId[3] = {0, 0, 0}; - __try // Verify cpuid instruction is supported + if (this->Features.ExtendedFeatures.SupportsHyperthreading) { - __asm - { - xor eax, eax // call cpuid with eax = 0 - cpuid // Get vendor id string - mov VendorId, ebx - mov VendorId + 4, edx - mov VendorId + 8, ecx - - mov eax, 1 // call cpuid with eax = 1 - cpuid - mov Regeax, eax // eax contains family processor type - mov Regedx, edx // edx has info about the availability of hyper-Threading - } + return true; + } + +#if USE_CPUID + int Regs[4] = { 0, 0, 0, 0 }, + VendorId[4] = { 0, 0, 0, 0 }; + // Get vendor id string + if (!call_cpuid(0, VendorId)) + { + return false; } - __except (EXCEPTION_EXECUTE_HANDLER) + // eax contains family processor type + // edx has info about the availability of hyper-Threading + if (!call_cpuid(1, Regs)) { - return(0); // cpuid is unavailable + return false; } - if (((Regeax & FAMILY_ID) == PENTIUM4_ID) || (Regeax & EXT_FAMILY_ID)) + if (((Regs[0] & FAMILY_ID) == PENTIUM4_ID) || (Regs[0] & EXT_FAMILY_ID)) { - if (VendorId[0] == 'uneG') + if (VendorId[1] == 0x756e6547) // 'uneG' { - if (VendorId[1] == 'Ieni') + if (VendorId[3] == 0x49656e69) // 'Ieni' { - if (VendorId[2] == 'letn') + if (VendorId[2] == 0x6c65746e) // 'letn' { - return(Regedx & HT_BIT); // Genuine Intel with hyper-Threading technology + // Genuine Intel with hyper-Threading technology + this->Features.ExtendedFeatures.SupportsHyperthreading = ((Regs[3] & HT_BIT) != 0); + return this->Features.ExtendedFeatures.SupportsHyperthreading; } } } @@ -3799,22 +3806,17 @@ unsigned int SystemInformationImplementation::IsHyperThreadingSupported() /** Return the APIC Id. Works only for windows. */ unsigned char SystemInformationImplementation::GetAPICId() { - unsigned int Regebx = 0; + int Regs[4] = { 0, 0, 0, 0 }; -#if USE_ASM_INSTRUCTIONS +#if USE_CPUID if (!this->IsHyperThreadingSupported()) { return static_cast<unsigned char>(-1); // HT not supported } // Logical processor = 1 - __asm - { - mov eax, 1 - cpuid - mov Regebx, ebx - } + call_cpuid(1, Regs); #endif - return static_cast<unsigned char>((Regebx & INITIAL_APIC_ID_BITS) >> 24); + return static_cast<unsigned char>((Regs[1] & INITIAL_APIC_ID_BITS) >> 24); } @@ -4040,6 +4042,81 @@ bool SystemInformationImplementation::ParseSysCtl() len = sizeof(value); err = sysctlbyname("machdep.cpu.model", &value, &len, NULL, 0); this->ChipID.Model = static_cast< int >( value ); + + // Chip Stepping + len = sizeof(value); + value = 0; + err = sysctlbyname("machdep.cpu.stepping", &value, &len, NULL, 0); + if (!err) + { + this->ChipID.Revision = static_cast< int >( value ); + } + + // feature string + char *buf = 0; + size_t allocSize = 128; + + err = 0; + len = 0; + + // sysctlbyname() will return with err==0 && len==0 if the buffer is too small + while (err == 0 && len == 0) + { + delete[] buf; + allocSize *= 2; + buf = new char[allocSize]; + if (!buf) + { + break; + } + buf[0] = ' '; + len = allocSize - 2; // keep space for leading and trailing space + err = sysctlbyname("machdep.cpu.features", buf + 1, &len, NULL, 0); + } + if (!err && buf && len) + { + // now we can match every flags as space + flag + space + buf[len + 1] = ' '; + kwsys_stl::string cpuflags(buf, len + 2); + + if ((cpuflags.find(" FPU ")!=kwsys_stl::string::npos)) + { + this->Features.HasFPU = true; + } + if ((cpuflags.find(" TSC ")!=kwsys_stl::string::npos)) + { + this->Features.HasTSC = true; + } + if ((cpuflags.find(" MMX ")!=kwsys_stl::string::npos)) + { + this->Features.HasMMX = true; + } + if ((cpuflags.find(" SSE ")!=kwsys_stl::string::npos)) + { + this->Features.HasSSE = true; + } + if ((cpuflags.find(" SSE2 ")!=kwsys_stl::string::npos)) + { + this->Features.HasSSE2 = true; + } + if ((cpuflags.find(" APIC ")!=kwsys_stl::string::npos)) + { + this->Features.HasAPIC = true; + } + if ((cpuflags.find(" CMOV ")!=kwsys_stl::string::npos)) + { + this->Features.HasCMOV = true; + } + if ((cpuflags.find(" MTRR ")!=kwsys_stl::string::npos)) + { + this->Features.HasMTRR = true; + } + if ((cpuflags.find(" ACPI ")!=kwsys_stl::string::npos)) + { + this->Features.HasACPI = true; + } + } + delete[] buf; } // brand string @@ -4099,13 +4176,12 @@ kwsys_stl::string SystemInformationImplementation::RunProcess(kwsys_stl::vector< char* data = NULL; int length; double timeout = 255; + int pipe; // pipe id as returned by kwsysProcess_WaitForData() - while(kwsysProcess_WaitForData(gp,&data,&length,&timeout)) // wait for 1s + while( ( pipe = kwsysProcess_WaitForData(gp,&data,&length,&timeout), + (pipe == kwsysProcess_Pipe_STDOUT || pipe == kwsysProcess_Pipe_STDERR) ) ) // wait for 1s { - for(int i=0;i<length;i++) - { - buffer += data[i]; - } + buffer.append(data, length); } kwsysProcess_WaitForExit(gp, 0); @@ -4213,48 +4289,55 @@ kwsys_stl::string SystemInformationImplementation::ParseValueFromKStat(const cha return value; } - /** Querying for system information from Solaris */ -bool SystemInformationImplementation::QuerySolarisInfo() +bool SystemInformationImplementation::QuerySolarisMemory() { - // Parse values - this->NumberOfPhysicalCPU = static_cast<unsigned int>( - atoi(this->ParseValueFromKStat("-n syste_misc -s ncpus").c_str())); - this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; +#if defined (__SVR4) && defined (__sun) + // Solaris allows querying this value by sysconf, but if this is + // a 32 bit process on a 64 bit host the returned memory will be + // limited to 4GiB. So if this is a 32 bit process or if the sysconf + // method fails use the kstat interface. +#if SIZEOF_VOID_P == 8 + if (this->QueryMemoryBySysconf()) + { + return true; + } +#endif + + char* tail; + unsigned long totalMemory = + strtoul(this->ParseValueFromKStat("-s physmem").c_str(),&tail,0); + this->TotalPhysicalMemory = totalMemory/128; + + return true; +#else + return false; +#endif +} - if(this->NumberOfPhysicalCPU!=0) +bool SystemInformationImplementation::QuerySolarisProcessor() +{ + if (!this->QueryProcessorBySysconf()) { - this->NumberOfLogicalCPU /= this->NumberOfPhysicalCPU; + return false; } + // Parse values this->CPUSpeedInMHz = static_cast<float>(atoi(this->ParseValueFromKStat("-s clock_MHz").c_str())); // Chip family this->ChipID.Family = 0; - // Chip Vendor - this->ChipID.Vendor = "Sun"; - this->FindManufacturer(); - // Chip Model this->ChipID.ProcessorName = this->ParseValueFromKStat("-s cpu_type"); this->ChipID.Model = 0; - // Cache size - this->Features.L1CacheSize = 0; - this->Features.L2CacheSize = 0; - - char* tail; - unsigned long totalMemory = - strtoul(this->ParseValueFromKStat("-s physmem").c_str(),&tail,0); - this->TotalPhysicalMemory = totalMemory/1024; - this->TotalPhysicalMemory *= 8192; - this->TotalPhysicalMemory /= 1024; - - // Undefined values (for now at least) - this->TotalVirtualMemory = 0; - this->AvailablePhysicalMemory = 0; - this->AvailableVirtualMemory = 0; + // Chip Vendor + if (this->ChipID.ProcessorName != "i386") + { + this->ChipID.Vendor = "Sun"; + this->FindManufacturer(); + } return true; } @@ -4363,6 +4446,31 @@ bool SystemInformationImplementation::QueryQNXMemory() return false; } +bool SystemInformationImplementation::QueryBSDMemory() +{ +#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) + int ctrl[2] = { CTL_HW, HW_PHYSMEM }; +#if defined(HW_PHYSMEM64) + int64_t k; + ctrl[1] = HW_PHYSMEM64; +#else + int k; +#endif + size_t sz = sizeof(k); + + if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0) + { + return false; + } + + this->TotalPhysicalMemory = k>>10>>10; + + return true; +#else + return false; +#endif +} + bool SystemInformationImplementation::QueryQNXProcessor() { #if defined(__QNX__) @@ -4416,6 +4524,163 @@ bool SystemInformationImplementation::QueryQNXProcessor() #endif } +bool SystemInformationImplementation::QueryBSDProcessor() +{ +#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) + int k; + size_t sz = sizeof(k); + int ctrl[2] = { CTL_HW, HW_NCPU }; + + if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0) + { + return false; + } + + this->NumberOfPhysicalCPU = k; + this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; + +#if defined(HW_CPUSPEED) + ctrl[1] = HW_CPUSPEED; + + if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0) + { + return false; + } + + this->CPUSpeedInMHz = (float) k; +#endif + +#if defined(CPU_SSE) + ctrl[0] = CTL_MACHDEP; + ctrl[1] = CPU_SSE; + + if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0) + { + return false; + } + + this->Features.HasSSE = (k > 0); +#endif + +#if defined(CPU_SSE2) + ctrl[0] = CTL_MACHDEP; + ctrl[1] = CPU_SSE2; + + if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0) + { + return false; + } + + this->Features.HasSSE2 = (k > 0); +#endif + +#if defined(CPU_CPUVENDOR) + ctrl[0] = CTL_MACHDEP; + ctrl[1] = CPU_CPUVENDOR; + char vbuf[25]; + ::memset(vbuf, 0, sizeof(vbuf)); + sz = sizeof(vbuf) - 1; + if (sysctl(ctrl, 2, vbuf, &sz, NULL, 0) != 0) + { + return false; + } + + this->ChipID.Vendor = vbuf; + this->FindManufacturer(); +#endif + + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryHPUXMemory() +{ +#if defined(__hpux) + unsigned long tv=0; + unsigned long tp=0; + unsigned long av=0; + unsigned long ap=0; + struct pst_static pst; + struct pst_dynamic pdy; + + unsigned long ps = 0; + if (pstat_getstatic(&pst, sizeof(pst), (size_t) 1, 0) == -1) + { + return false; + } + + ps = pst.page_size; + tp = pst.physical_memory *ps; + tv = (pst.physical_memory + pst.pst_maxmem) * ps; + if (pstat_getdynamic(&pdy, sizeof(pdy), (size_t) 1, 0) == -1) + { + return false; + } + + ap = tp - pdy.psd_rm * ps; + av = tv - pdy.psd_vm; + this->TotalVirtualMemory = tv>>10>>10; + this->TotalPhysicalMemory = tp>>10>>10; + this->AvailableVirtualMemory = av>>10>>10; + this->AvailablePhysicalMemory = ap>>10>>10; + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryHPUXProcessor() +{ +#if defined(__hpux) +# if defined(KWSYS_SYS_HAS_MPCTL_H) + int c = mpctl(MPC_GETNUMSPUS_SYS, 0, 0); + if (c <= 0) + { + return false; + } + + this->NumberOfPhysicalCPU = c; + this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; + + long t = sysconf(_SC_CPU_VERSION); + + if (t == -1) + { + return false; + } + + switch (t) + { + case CPU_PA_RISC1_0: + this->ChipID.Vendor = "Hewlett-Packard"; + this->ChipID.Family = 0x100; + case CPU_PA_RISC1_1: + this->ChipID.Vendor = "Hewlett-Packard"; + this->ChipID.Family = 0x110; + case CPU_PA_RISC2_0: + this->ChipID.Vendor = "Hewlett-Packard"; + this->ChipID.Family = 0x200; + case CPU_IA64_ARCHREV_0: + this->ChipID.Vendor = "GenuineIntel"; + this->Features.HasIA64 = true; + break; + default: + return false; + } + + this->FindManufacturer(); + + return true; +# else + return false; +# endif +#else + return false; +#endif +} + /** Query the operating system information */ bool SystemInformationImplementation::QueryOSInformation() { diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index 085d988..b75993e 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -157,7 +157,7 @@ public: #include <os/storage/Path.h> #endif -#if defined(__BEOS__) && !defined(__ZETA__) && !defined(__HAIKU__) +#if defined(__BEOS__) && !defined(__ZETA__) #include <be/kernel/OS.h> #include <be/storage/Path.h> @@ -622,11 +622,7 @@ bool SystemTools::MakeDirectory(const char* path) } SystemTools::ConvertToUnixSlashes(dir); - kwsys_stl::string::size_type pos = dir.find(':'); - if(pos == kwsys_stl::string::npos) - { - pos = 0; - } + kwsys_stl::string::size_type pos = 0; kwsys_stl::string topdir; while((pos = dir.find('/', pos)) != kwsys_stl::string::npos) { @@ -634,14 +630,7 @@ bool SystemTools::MakeDirectory(const char* path) Mkdir(topdir.c_str()); pos++; } - if(dir[dir.size()-1] == '/') - { - topdir = dir.substr(0, dir.size()); - } - else - { - topdir = dir; - } + topdir = dir; if(Mkdir(topdir.c_str()) != 0) { // There is a bug in the Borland Run time library which makes MKDIR @@ -2754,9 +2743,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) { @@ -4048,7 +4043,7 @@ kwsys_stl::string SystemTools::GetCurrentDateTime(const char* format) return kwsys_stl::string(buf); } -kwsys_stl::string SystemTools::MakeCindentifier(const char* s) +kwsys_stl::string SystemTools::MakeCidentifier(const char* s) { kwsys_stl::string str(s); if (str.find_first_of("0123456789") == 0) diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in index 5171125..9c56e96 100644 --- a/Source/kwsys/SystemTools.hxx.in +++ b/Source/kwsys/SystemTools.hxx.in @@ -91,8 +91,13 @@ public: * then an underscore is prepended. Note that this can produce * identifiers that the standard reserves (_[A-Z].* and __.*). */ - static kwsys_stl::string MakeCindentifier(const char* s); - + static kwsys_stl::string MakeCidentifier(const char* s); + + static kwsys_stl::string MakeCindentifier(const char* s) + { + return MakeCidentifier(s); + } + /** * Replace replace all occurences of the string in the source string. */ diff --git a/Source/kwsys/kwsysPlatformTestsCXX.cxx b/Source/kwsys/kwsysPlatformTestsCXX.cxx index ae58703..48976c4 100644 --- a/Source/kwsys/kwsysPlatformTestsCXX.cxx +++ b/Source/kwsys/kwsysPlatformTestsCXX.cxx @@ -580,3 +580,30 @@ int main() } } #endif + +#ifdef TEST_KWSYS_CXX_HAS_BORLAND_ASM +int main() +{ + int a = 1; + __asm { + xor EBX, EBX; + mov a, EBX; + } + + return a; +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_BORLAND_ASM_CPUID +int main() +{ + int a = 0; + __asm { + xor EAX, EAX; + cpuid; + mov a, EAX; + } + + return a; +} +#endif diff --git a/Source/kwsys/testDynamicLoader.cxx b/Source/kwsys/testDynamicLoader.cxx index a7adbca..cbfb65b 100644 --- a/Source/kwsys/testDynamicLoader.cxx +++ b/Source/kwsys/testDynamicLoader.cxx @@ -15,7 +15,7 @@ #include KWSYS_HEADER(ios/iostream) #include KWSYS_HEADER(stl/string) -#if defined(__BEOS__) && !defined(__HAIKU__) +#if defined(__BEOS__) #include <be/kernel/OS.h> /* disable_debugger() API. */ #endif diff --git a/Source/kwsys/testProcess.c b/Source/kwsys/testProcess.c index 877002a..269b84b 100644 --- a/Source/kwsys/testProcess.c +++ b/Source/kwsys/testProcess.c @@ -32,7 +32,7 @@ # pragma warn -8060 /* possibly incorrect assignment */ #endif -#if defined(__BEOS__) && !defined(__ZETA__) && !defined(__HAIKU__) +#if defined(__BEOS__) && !defined(__ZETA__) /* BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. */ # include <be/kernel/OS.h> static inline void testProcess_usleep(unsigned int msec) @@ -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..49a686c 100644 --- a/Source/kwsys/testSystemInformation.cxx +++ b/Source/kwsys/testSystemInformation.cxx @@ -47,6 +47,8 @@ int testSystemInformation(int, char*[]) { + kwsys_ios::cout << "CTEST_FULL_OUTPUT\n"; // avoid truncation + kwsys::SystemInformation info; info.RunCPUCheck(); info.RunOSCheck(); @@ -66,6 +68,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); @@ -85,6 +88,13 @@ int testSystemInformation(int, char*[]) printMethod3(info, GetHostMemoryUsed(), "KiB"); printMethod3(info, GetProcMemoryUsed(), "KiB"); + for (int i = 0; i <= 31; i++) + { + if (info.DoesCPUSupportFeature(1 << i)) + { + kwsys_ios::cout << "CPU feature " << i << "\n"; + } + } //int GetProcessorCacheXSize(long int); // bool DoesCPUSupportFeature(long int); return 0; |