/*========================================================================= 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& paths) { #if 0 for(std::vector::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 roots; cmSystemTools::ExpandListArgument(rootPath, roots); for(std::vector::iterator ri = roots.begin(); ri != roots.end(); ++ri) { cmSystemTools::ConvertToUnixSlashes(*ri); } // Copy the original set of unrooted paths. std::vector unrootedPaths = paths; paths.clear(); for(std::vector::const_iterator ri = roots.begin(); ri != roots.end(); ++ri) { for(std::vector::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& paths) { if(this->NoDefaultPath) { return; } std::vector 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& paths) { if(this->NoDefaultPath) { return; } std::vector 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& out_paths, const char* variable, std::set* emmitted) { // Get a path from a CMake variable. if(const char* varPath = this->Makefile->GetDefinition(variable)) { std::vector 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& out_paths, const char* variable, std::set* emmitted) { // Get a path from the environment. std::vector 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& out_paths, std::vector const& in_paths, PathType pathType, std::set* emmitted) { for(std::vector::const_iterator i = in_paths.begin(); i != in_paths.end(); ++i) { this->AddPathInternal(out_paths, *i, pathType, emmitted); } } //---------------------------------------------------------------------------- void cmFindCommon::AddPathInternal(std::vector& out_paths, std::string const& in_path, PathType pathType, std::set* 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()); } }