diff options
author | Brad King <brad.king@kitware.com> | 2008-01-17 14:02:31 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2008-01-17 14:02:31 (GMT) |
commit | b424df917dc14ea7376940c6c22a3a274aedcc2b (patch) | |
tree | c29fc8171c1a13c74746dd2e28e10016614e16cb /Source/cmFindCommon.cxx | |
parent | 491d5d01049e515fa5317f943d9e48ff531f69a6 (diff) | |
download | CMake-b424df917dc14ea7376940c6c22a3a274aedcc2b.zip CMake-b424df917dc14ea7376940c6c22a3a274aedcc2b.tar.gz CMake-b424df917dc14ea7376940c6c22a3a274aedcc2b.tar.bz2 |
ENH: Major improvements to the FIND_PACKAGE command. See bug #3659.
- Use CMAKE_PREFIX_PATH and CMAKE_SYSTEM_PREFIX_PATH among other means
to locate package configuration files.
- Create cmFindCommon as base for cmFindBase and cmFindPackageCommand
- Move common functionality up to cmFindCommon
- Improve documentation of FIND_* commands.
- Fix FIND_* commands to not add framework/app paths in wrong place.
Diffstat (limited to 'Source/cmFindCommon.cxx')
-rw-r--r-- | Source/cmFindCommon.cxx | 479 |
1 files changed, 479 insertions, 0 deletions
diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx new file mode 100644 index 0000000..0c6af0d --- /dev/null +++ b/Source/cmFindCommon.cxx @@ -0,0 +1,479 @@ +/*========================================================================= + + Program: CMake - Cross-Platform Makefile Generator + Module: $RCSfile$ + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. + See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#include "cmFindCommon.h" + +//---------------------------------------------------------------------------- +cmFindCommon::cmFindCommon() +{ + this->FindRootPathMode = RootPathModeBoth; + this->NoDefaultPath = false; + this->NoCMakePath = false; + this->NoCMakeEnvironmentPath = false; + this->NoSystemEnvironmentPath = false; + this->NoCMakeSystemPath = false; + + // OS X Bundle and Framework search policy. The default is to + // search frameworks first on apple. +#if defined(__APPLE__) + this->SearchFrameworkFirst = true; + this->SearchAppBundleFirst = true; +#else + this->SearchFrameworkFirst = false; + this->SearchAppBundleFirst = false; +#endif + this->SearchFrameworkOnly = false; + this->SearchFrameworkLast = false; + this->SearchAppBundleOnly = false; + this->SearchAppBundleLast = false; + + // Documentation components. + this->GenericDocumentationMacPolicy = + "On Darwin or systems supporting OS X Frameworks, the cmake variable" + " CMAKE_FIND_FRAMEWORK can be set to empty or one of the following:\n" + " \"FIRST\" - Try to find frameworks before standard\n" + " libraries or headers. This is the default on Darwin.\n" + " \"LAST\" - Try to find frameworks after standard\n" + " libraries or headers.\n" + " \"ONLY\" - Only try to find frameworks.\n" + " \"NEVER\". - Never try to find frameworks.\n" + "On Darwin or systems supporting OS X Application Bundles, the cmake " + "variable CMAKE_FIND_APPBUNDLE can be set to empty or one of the " + "following:\n" + " \"FIRST\" - Try to find application bundles before standard\n" + " programs. This is the default on Darwin.\n" + " \"LAST\" - Try to find application bundles after standard\n" + " programs.\n" + " \"ONLY\" - Only try to find application bundles.\n" + " \"NEVER\". - Never try to find application bundles.\n"; + this->GenericDocumentationRootPath = + "The CMake variable CMAKE_FIND_ROOT_PATH specifies one or more " + "directories to be prepended to all other search directories. " + "This effectively \"re-roots\" the entire search under given locations. " + "By default it is empty. It is especially useful when " + "cross-compiling to point to the root directory of the " + "target environment and CMake will search there too. By default at first " + "the directories listed in CMAKE_FIND_ROOT_PATH and then the non-rooted " + "directories will be searched. " + "The default behavior can be adjusted by setting " + "CMAKE_FIND_ROOT_PATH_MODE_XXX. This behavior can be manually " + "overridden on a per-call basis. " + "By using CMAKE_FIND_ROOT_PATH_BOTH the search order will " + "be as described above. If NO_CMAKE_FIND_ROOT_PATH is used " + "then CMAKE_FIND_ROOT_PATH will not be used. If ONLY_CMAKE_FIND_ROOT_PATH " + "is used then only the re-rooted directories will be searched.\n"; + this->GenericDocumentationPathsOrder = + "The reason the paths listed in the call to the command are searched " + "last is that most users of CMake would expect things to be found " + "first in the locations specified by their environment. Projects may " + "override this behavior by simply calling the command twice:\n" + " FIND_XXX(FIND_ARGS_XXX PATHS paths... NO_DEFAULT_PATH)\n" + " FIND_XXX(FIND_ARGS_XXX)\n" + "Once one of these calls succeeds the result variable will be set " + "and stored in the cache so that neither call will search again."; +} + +//---------------------------------------------------------------------------- +cmFindCommon::~cmFindCommon() +{ +} + +//---------------------------------------------------------------------------- +void cmFindCommon::SelectDefaultRootPathMode() +{ + // Use both by default. + this->FindRootPathMode = RootPathModeBoth; + + // Check the policy variable for this find command type. + std::string findRootPathVar = "CMAKE_FIND_ROOT_PATH_MODE_"; + findRootPathVar += this->CMakePathName; + std::string rootPathMode = + this->Makefile->GetSafeDefinition(findRootPathVar.c_str()); + if (rootPathMode=="NEVER") + { + this->FindRootPathMode = RootPathModeNoRootPath; + } + else if (rootPathMode=="ONLY") + { + this->FindRootPathMode = RootPathModeOnlyRootPath; + } + else if (rootPathMode=="BOTH") + { + this->FindRootPathMode = RootPathModeBoth; + } +} + +//---------------------------------------------------------------------------- +void cmFindCommon::SelectDefaultMacMode() +{ + std::string ff = this->Makefile->GetSafeDefinition("CMAKE_FIND_FRAMEWORK"); + if(ff == "NEVER") + { + this->SearchFrameworkLast = false; + this->SearchFrameworkFirst = false; + this->SearchFrameworkOnly = false; + } + else if(ff == "ONLY") + { + this->SearchFrameworkLast = false; + this->SearchFrameworkFirst = false; + this->SearchFrameworkOnly = true; + } + else if(ff == "FIRST") + { + this->SearchFrameworkLast = false; + this->SearchFrameworkFirst = true; + this->SearchFrameworkOnly = false; + } + else if(ff == "LAST") + { + this->SearchFrameworkLast = true; + this->SearchFrameworkFirst = false; + this->SearchFrameworkOnly = false; + } + + std::string fab = this->Makefile->GetSafeDefinition("CMAKE_FIND_APPBUNDLE"); + if(fab == "NEVER") + { + this->SearchAppBundleLast = false; + this->SearchAppBundleFirst = false; + this->SearchAppBundleOnly = false; + } + else if(fab == "ONLY") + { + this->SearchAppBundleLast = false; + this->SearchAppBundleFirst = false; + this->SearchAppBundleOnly = true; + } + else if(fab == "FIRST") + { + this->SearchAppBundleLast = false; + this->SearchAppBundleFirst = true; + this->SearchAppBundleOnly = false; + } + else if(fab == "LAST") + { + this->SearchAppBundleLast = true; + this->SearchAppBundleFirst = false; + this->SearchAppBundleOnly = false; + } +} + +//---------------------------------------------------------------------------- +void cmFindCommon::RerootPaths(std::vector<std::string>& paths) +{ +#if 0 + for(std::vector<std::string>::const_iterator i = paths.begin(); + i != paths.end(); ++i) + { + fprintf(stderr, "[%s]\n", i->c_str()); + } +#endif + + // Short-circuit if there is nothing to do. + if(this->FindRootPathMode == RootPathModeNoRootPath) + { + return; + } + const char* rootPath = + this->Makefile->GetDefinition("CMAKE_FIND_ROOT_PATH"); + if((rootPath == 0) || (strlen(rootPath) == 0)) + { + return; + } + + // Construct the list of path roots with no trailing slashes. + std::vector<std::string> roots; + cmSystemTools::ExpandListArgument(rootPath, roots); + for(std::vector<std::string>::iterator ri = roots.begin(); + ri != roots.end(); ++ri) + { + cmSystemTools::ConvertToUnixSlashes(*ri); + } + + // Copy the original set of unrooted paths. + std::vector<std::string> unrootedPaths = paths; + paths.clear(); + + for(std::vector<std::string>::const_iterator ri = roots.begin(); + ri != roots.end(); ++ri) + { + for(std::vector<std::string>::const_iterator ui = unrootedPaths.begin(); + ui != unrootedPaths.end(); ++ui) + { + // Place the unrooted path under the current root if it is not + // already inside. Skip the unrooted path if it is relative to + // a user home directory or is empty. + std::string rootedDir; + if(cmSystemTools::IsSubDirectory(ui->c_str(), ri->c_str())) + { + rootedDir = *ui; + } + else if(!ui->empty() && (*ui)[0] != '~') + { + // Start with the new root. + rootedDir = *ri; + rootedDir += "/"; + + // Append the original path with its old root removed. + rootedDir += cmSystemTools::SplitPathRootComponent(ui->c_str()); + } + + // Store the new path. + paths.push_back(rootedDir); + } + } + + // If searching both rooted and unrooted paths add the original + // paths again. + if(this->FindRootPathMode == RootPathModeBoth) + { + paths.insert(paths.end(), unrootedPaths.begin(), unrootedPaths.end()); + } +} + +//---------------------------------------------------------------------------- +bool cmFindCommon::CheckCommonArgument(std::string const& arg) +{ + if(arg == "NO_DEFAULT_PATH") + { + this->NoDefaultPath = true; + } + else if(arg == "NO_CMAKE_ENVIRONMENT_PATH") + { + this->NoCMakeEnvironmentPath = true; + } + else if(arg == "NO_CMAKE_PATH") + { + this->NoCMakePath = true; + } + else if(arg == "NO_SYSTEM_ENVIRONMENT_PATH") + { + this->NoSystemEnvironmentPath = true; + } + else if(arg == "NO_CMAKE_SYSTEM_PATH") + { + this->NoCMakeSystemPath = true; + } + else if(arg == "NO_CMAKE_FIND_ROOT_PATH") + { + this->FindRootPathMode = RootPathModeNoRootPath; + } + else if(arg == "ONLY_CMAKE_FIND_ROOT_PATH") + { + this->FindRootPathMode = RootPathModeOnlyRootPath; + } + else if(arg == "CMAKE_FIND_ROOT_PATH_BOTH") + { + this->FindRootPathMode = RootPathModeBoth; + } + else + { + // The argument is not one of the above. + return false; + } + + // The argument is one of the above. + return true; +} + +//---------------------------------------------------------------------------- +void cmFindCommon::AddPathSuffix(std::string const& arg) +{ + std::string suffix = arg; + + // Strip leading and trailing slashes. + if(suffix.empty()) + { + return; + } + if(suffix[0] == '/') + { + suffix = suffix.substr(1, suffix.npos); + } + if(suffix.empty()) + { + return; + } + if(suffix[suffix.size()-1] == '/') + { + suffix = suffix.substr(0, suffix.size()-1); + } + if(suffix.empty()) + { + return; + } + + // Store the suffix. + this->SearchPathSuffixes.push_back(suffix); +} + +//---------------------------------------------------------------------------- +void cmFindCommon::GetAppBundlePaths(std::vector<std::string>& paths) +{ + if(this->NoDefaultPath) + { + return; + } + std::vector<std::string> tmp; + + // first environment variables + if(!this->NoCMakeEnvironmentPath) + { + cmSystemTools::GetPath(tmp, "CMAKE_APPBUNDLE_PATH"); + this->AddPathsInternal(paths, tmp, EnvPath); + tmp.clear(); + } + + // add cmake variables + if(!this->NoCMakePath) + { + if(const char* path = + this->Makefile->GetDefinition("CMAKE_APPBUNDLE_PATH")) + { + cmSystemTools::ExpandListArgument(path, tmp); + this->AddPathsInternal(paths, tmp, CMakePath); + tmp.clear(); + } + } + + // add cmake system variables + if(!this->NoCMakeSystemPath) + { + if(const char* path = + this->Makefile->GetDefinition("CMAKE_SYSTEM_APPBUNDLE_PATH")) + { + cmSystemTools::ExpandListArgument(path, tmp); + this->AddPathsInternal(paths, tmp, CMakePath); + tmp.clear(); + } + } +} + +//---------------------------------------------------------------------------- +void cmFindCommon::GetFrameworkPaths(std::vector<std::string>& paths) +{ + if(this->NoDefaultPath) + { + return; + } + std::vector<std::string> tmp; + + // first environment variables + if(!this->NoCMakeEnvironmentPath) + { + cmSystemTools::GetPath(tmp, "CMAKE_FRAMEWORK_PATH"); + this->AddPathsInternal(paths, tmp, EnvPath); + tmp.clear(); + } + + // add cmake variables + if(!this->NoCMakePath) + { + if(const char* path = + this->Makefile->GetDefinition("CMAKE_FRAMEWORK_PATH")) + { + cmSystemTools::ExpandListArgument(path, tmp); + this->AddPathsInternal(paths, tmp, CMakePath); + tmp.clear(); + } + } + + // add cmake system variables + if(!this->NoCMakeSystemPath) + { + if(const char* path = + this->Makefile->GetDefinition("CMAKE_SYSTEM_FRAMEWORK_PATH")) + { + cmSystemTools::ExpandListArgument(path, tmp); + this->AddPathsInternal(paths, tmp, CMakePath); + tmp.clear(); + } + } +} + +//---------------------------------------------------------------------------- +void cmFindCommon::AddCMakePath(std::vector<std::string>& out_paths, + const char* variable, + std::set<cmStdString>* emmitted) +{ + // Get a path from a CMake variable. + if(const char* varPath = this->Makefile->GetDefinition(variable)) + { + std::vector<std::string> tmp; + cmSystemTools::ExpandListArgument(varPath, tmp); + + // Relative paths are interpreted with respect to the current + // source directory. + this->AddPathsInternal(out_paths, tmp, CMakePath, emmitted); + } +} + +//---------------------------------------------------------------------------- +void cmFindCommon::AddEnvPath(std::vector<std::string>& out_paths, + const char* variable, + std::set<cmStdString>* emmitted) +{ + // Get a path from the environment. + std::vector<std::string> tmp; + cmSystemTools::GetPath(tmp, variable); + + // Relative paths are interpreted with respect to the current + // working directory. + this->AddPathsInternal(out_paths, tmp, EnvPath, emmitted); +} + +//---------------------------------------------------------------------------- +void cmFindCommon::AddPathsInternal(std::vector<std::string>& out_paths, + std::vector<std::string> const& in_paths, + PathType pathType, + std::set<cmStdString>* emmitted) +{ + for(std::vector<std::string>::const_iterator i = in_paths.begin(); + i != in_paths.end(); ++i) + { + this->AddPathInternal(out_paths, *i, pathType, emmitted); + } +} + +//---------------------------------------------------------------------------- +void cmFindCommon::AddPathInternal(std::vector<std::string>& out_paths, + std::string const& in_path, + PathType pathType, + std::set<cmStdString>* emmitted) +{ + if(in_path.empty()) + { + return; + } + + // Select the base path with which to interpret relative paths. + const char* relbase = 0; + if(pathType == CMakePath) + { + relbase = this->Makefile->GetCurrentDirectory(); + } + + // Convert to clean full path. + std::string fullPath = + cmSystemTools::CollapseFullPath(in_path.c_str(), relbase); + + // Insert the path if has not already been emmitted. + if(!emmitted || emmitted->insert(fullPath).second) + { + out_paths.push_back(fullPath.c_str()); + } +} |