/*============================================================================ CMake - Cross Platform Makefile Generator 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 "cmFindBase.h" #include "cmAlgorithms.h" #include "cmState.h" cmFindBase::cmFindBase() { this->AlreadyInCache = false; this->AlreadyInCacheWithoutMetaInfo = false; this->NamesPerDir = false; this->NamesPerDirAllowed = false; } //---------------------------------------------------------------------------- bool cmFindBase::ParseArguments(std::vector const& argsIn) { if(argsIn.size() < 2 ) { this->SetError("called with incorrect number of arguments"); return false; } // copy argsIn into args so it can be modified, // in the process extract the DOC "documentation" size_t size = argsIn.size(); std::vector args; bool foundDoc = false; for(unsigned int j = 0; j < size; ++j) { if(foundDoc || argsIn[j] != "DOC" ) { if(argsIn[j] == "ENV") { if(j+1 < size) { j++; cmSystemTools::GetPath(args, argsIn[j].c_str()); } } else { args.push_back(argsIn[j]); } } else { if(j+1 < size) { foundDoc = true; this->VariableDocumentation = argsIn[j+1]; j++; if(j >= size) { break; } } } } if(args.size() < 2 ) { this->SetError("called with incorrect number of arguments"); return false; } this->VariableName = args[0]; if(this->CheckForVariableInCache()) { this->AlreadyInCache = true; return true; } this->AlreadyInCache = false; // Find the current root path mode. this->SelectDefaultRootPathMode(); // Find the current bundle/framework search policy. this->SelectDefaultMacMode(); bool newStyle = false; enum Doing { DoingNone, DoingNames, DoingPaths, DoingPathSuffixes, DoingHints }; Doing doing = DoingNames; // assume it starts with a name for (unsigned int j = 1; j < args.size(); ++j) { if(args[j] == "NAMES") { doing = DoingNames; newStyle = true; } else if (args[j] == "PATHS") { doing = DoingPaths; newStyle = true; } else if (args[j] == "HINTS") { doing = DoingHints; newStyle = true; } else if (args[j] == "PATH_SUFFIXES") { doing = DoingPathSuffixes; newStyle = true; } else if (args[j] == "NAMES_PER_DIR") { doing = DoingNone; if(this->NamesPerDirAllowed) { this->NamesPerDir = true; } else { this->SetError("does not support NAMES_PER_DIR"); return false; } } else if (args[j] == "NO_SYSTEM_PATH") { doing = DoingNone; this->NoDefaultPath = true; } else if (this->CheckCommonArgument(args[j])) { doing = DoingNone; // Some common arguments were accidentally supported by CMake // 2.4 and 2.6.0 in the short-hand form of the command, so we // must support it even though it is not documented. } else if(doing == DoingNames) { this->Names.push_back(args[j]); } else if(doing == DoingPaths) { this->UserGuessArgs.push_back(args[j]); } else if(doing == DoingHints) { this->UserHintsArgs.push_back(args[j]); } else if(doing == DoingPathSuffixes) { this->AddPathSuffix(args[j]); } } if(this->VariableDocumentation.empty()) { this->VariableDocumentation = "Where can "; if(this->Names.empty()) { this->VariableDocumentation += "the (unknown) library be found"; } else if(this->Names.size() == 1) { this->VariableDocumentation += "the " + this->Names[0] + " library be found"; } else { this->VariableDocumentation += "one of the "; this->VariableDocumentation += cmJoin(cmMakeRange(this->Names).retreat(1), ", "); this->VariableDocumentation += " or " + this->Names[this->Names.size() - 1] + " libraries be found"; } } // look for old style // FIND_*(VAR name path1 path2 ...) if(!newStyle) { // All the short-hand arguments have been recorded as names. std::vector shortArgs = this->Names; this->Names.clear(); // clear out any values in Names this->Names.push_back(shortArgs[0]); this->UserGuessArgs.insert(this->UserGuessArgs.end(), shortArgs.begin() + 1, shortArgs.end()); } this->ExpandPaths(); this->ComputeFinalPaths(); return true; } void cmFindBase::ExpandPaths() { if(!this->NoDefaultPath) { if(!this->NoCMakePath) { this->FillCMakeVariablePath(); } if(!this->NoCMakeEnvironmentPath) { this->FillCMakeEnvironmentPath(); } } this->FillUserHintsPath(); if(!this->NoDefaultPath) { if(!this->NoSystemEnvironmentPath) { this->FillSystemEnvironmentPath(); } if(!this->NoCMakeSystemPath) { this->FillCMakeSystemVariablePath(); } } this->FillUserGuessPath(); } //---------------------------------------------------------------------------- void cmFindBase::FillCMakeEnvironmentPath() { cmSearchPath &paths = this->LabeledPaths[PathLabel::CMakeEnvironment]; // Add CMAKE_*_PATH environment variables std::string var = "CMAKE_"; var += this->CMakePathName; var += "_PATH"; paths.AddEnvPrefixPath("CMAKE_PREFIX_PATH"); paths.AddEnvPath(var); if(this->CMakePathName == "PROGRAM") { paths.AddEnvPath("CMAKE_APPBUNDLE_PATH"); } else { paths.AddEnvPath("CMAKE_FRAMEWORK_PATH"); } paths.AddSuffixes(this->SearchPathSuffixes); } //---------------------------------------------------------------------------- void cmFindBase::FillCMakeVariablePath() { cmSearchPath &paths = this->LabeledPaths[PathLabel::CMake]; // Add CMake varibles of the same name as the previous environment // varibles CMAKE_*_PATH to be used most of the time with -D // command line options std::string var = "CMAKE_"; var += this->CMakePathName; var += "_PATH"; paths.AddCMakePrefixPath("CMAKE_PREFIX_PATH"); paths.AddCMakePath(var); if(this->CMakePathName == "PROGRAM") { paths.AddCMakePath("CMAKE_APPBUNDLE_PATH"); } else { paths.AddCMakePath("CMAKE_FRAMEWORK_PATH"); } paths.AddSuffixes(this->SearchPathSuffixes); } //---------------------------------------------------------------------------- void cmFindBase::FillSystemEnvironmentPath() { cmSearchPath &paths = this->LabeledPaths[PathLabel::SystemEnvironment]; // Add LIB or INCLUDE if(!this->EnvironmentPath.empty()) { paths.AddEnvPath(this->EnvironmentPath); paths.AddEnvPrefixPath("PATH", true); } // Add PATH paths.AddEnvPath("PATH"); paths.AddSuffixes(this->SearchPathSuffixes); } //---------------------------------------------------------------------------- void cmFindBase::FillCMakeSystemVariablePath() { cmSearchPath &paths = this->LabeledPaths[PathLabel::CMakeSystem]; std::string var = "CMAKE_SYSTEM_"; var += this->CMakePathName; var += "_PATH"; paths.AddCMakePrefixPath("CMAKE_SYSTEM_PREFIX_PATH"); paths.AddCMakePath(var); if(this->CMakePathName == "PROGRAM") { paths.AddCMakePath("CMAKE_SYSTEM_APPBUNDLE_PATH"); } else { paths.AddCMakePath("CMAKE_SYSTEM_FRAMEWORK_PATH"); } paths.AddSuffixes(this->SearchPathSuffixes); } //---------------------------------------------------------------------------- void cmFindBase::FillUserHintsPath() { cmSearchPath &paths = this->LabeledPaths[PathLabel::Hints]; for(std::vector::const_iterator p = this->UserHintsArgs.begin(); p != this->UserHintsArgs.end(); ++p) { paths.AddUserPath(*p); } paths.AddSuffixes(this->SearchPathSuffixes); } //---------------------------------------------------------------------------- void cmFindBase::FillUserGuessPath() { cmSearchPath &paths = this->LabeledPaths[PathLabel::Guess]; for(std::vector::const_iterator p = this->UserGuessArgs.begin(); p != this->UserGuessArgs.end(); ++p) { paths.AddUserPath(*p); } paths.AddSuffixes(this->SearchPathSuffixes); } //---------------------------------------------------------------------------- void cmFindBase::PrintFindStuff() { std::cerr << "SearchFrameworkLast: " << this->SearchFrameworkLast << "\n"; std::cerr << "SearchFrameworkOnly: " << this->SearchFrameworkOnly << "\n"; std::cerr << "SearchFrameworkFirst: " << this->SearchFrameworkFirst << "\n"; std::cerr << "SearchAppBundleLast: " << this->SearchAppBundleLast << "\n"; std::cerr << "SearchAppBundleOnly: " << this->SearchAppBundleOnly << "\n"; std::cerr << "SearchAppBundleFirst: " << this->SearchAppBundleFirst << "\n"; std::cerr << "VariableName " << this->VariableName << "\n"; std::cerr << "VariableDocumentation " << this->VariableDocumentation << "\n"; std::cerr << "NoDefaultPath " << this->NoDefaultPath << "\n"; std::cerr << "NoCMakeEnvironmentPath " << this->NoCMakeEnvironmentPath << "\n"; std::cerr << "NoCMakePath " << this->NoCMakePath << "\n"; std::cerr << "NoSystemEnvironmentPath " << this->NoSystemEnvironmentPath << "\n"; std::cerr << "NoCMakeSystemPath " << this->NoCMakeSystemPath << "\n"; std::cerr << "EnvironmentPath " << this->EnvironmentPath << "\n"; std::cerr << "CMakePathName " << this->CMakePathName << "\n"; std::cerr << "Names " << cmJoin(this->Names, " ") << "\n"; std::cerr << "\n"; std::cerr << "SearchPathSuffixes "; std::cerr << cmJoin(this->SearchPathSuffixes, "\n") << "\n"; std::cerr << "SearchPaths\n"; std::cerr << cmWrap("[", this->SearchPaths, "]", "\n") << "\n"; } bool cmFindBase::CheckForVariableInCache() { if(const char* cacheValue = this->Makefile->GetDefinition(this->VariableName)) { cmState* state = this->Makefile->GetState(); const char* cacheEntry = state->GetCacheEntryValue(this->VariableName); bool found = !cmSystemTools::IsNOTFOUND(cacheValue); bool cached = cacheEntry ? true : false; if(found) { // If the user specifies the entry on the command line without a // type we should add the type and docstring but keep the // original value. Tell the subclass implementations to do // this. if(cached && state->GetCacheEntryType(this->VariableName) == cmState::UNINITIALIZED) { this->AlreadyInCacheWithoutMetaInfo = true; } return true; } else if(cached) { const char* hs = state->GetCacheEntryProperty(this->VariableName, "HELPSTRING"); this->VariableDocumentation = hs?hs:"(none)"; } } return false; }