diff --git a/Source/cmDocumentVariables.cxx b/Source/cmDocumentVariables.cxx index 2ed959f42..961735551 100644 --- a/Source/cmDocumentVariables.cxx +++ b/Source/cmDocumentVariables.cxx @@ -587,7 +587,39 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "directories for the current system. It is NOT intended " "to be modified by the project, use CMAKE_PREFIX_PATH for this. See also " "CMAKE_SYSTEM_INCLUDE_PATH, CMAKE_SYSTEM_LIBRARY_PATH, " - "CMAKE_SYSTEM_PROGRAM_PATH.", false, + "CMAKE_SYSTEM_PROGRAM_PATH, and CMAKE_SYSTEM_IGNORE_PATH.", false, + "Variables That Change Behavior"); + + cm->DefineProperty + ("CMAKE_SYSTEM_IGNORE_PATH", cmProperty::VARIABLE, + "Path to be ignored by FIND_XXX() commands.", + "Specifies directories to be ignored by searches in FIND_XXX() commands " + "This is useful in cross-compiled environments where some system " + "directories contain incompatible but possibly linkable libraries. For " + "example, on cross-compiled cluster environments, this allows a user to " + "ignore directories containing libraries meant for the front-end " + "machine that modules like FindX11 (and others) would normally search. " + "By default this contains a list of directories containing incompatible " + "binaries for the host system. " + "See also CMAKE_SYSTEM_PREFIX_PATH, CMAKE_SYSTEM_LIBRARY_PATH, " + "CMAKE_SYSTEM_INCLUDE_PATH, and CMAKE_SYSTEM_PROGRAM_PATH.", false, + "Variables That Change Behavior"); + + cm->DefineProperty + ("CMAKE_IGNORE_PATH", cmProperty::VARIABLE, + "Path to be ignored by FIND_XXX() commands.", + "Specifies directories to be ignored by searches in FIND_XXX() commands " + "This is useful in cross-compiled environments where some system " + "directories contain incompatible but possibly linkable libraries. For " + "example, on cross-compiled cluster environments, this allows a user to " + "ignore directories containing libraries meant for the front-end " + "machine that modules like FindX11 (and others) would normally search. " + "By default this is empty; it is intended to be set by the project. " + "Note that CMAKE_IGNORE_PATH takes a list of directory names, NOT a " + "list of prefixes. If you want to ignore paths under prefixes (bin, " + "include, lib, etc.), you'll need to specify them explicitly. " + "See also CMAKE_PREFIX_PATH, CMAKE_LIBRARY_PATH, CMAKE_INCLUDE_PATH, " + "CMAKE_PROGRAM_PATH.", false, "Variables That Change Behavior"); cm->DefineProperty diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx index a54ad7a90..e1188d5bb 100644 --- a/Source/cmFindBase.cxx +++ b/Source/cmFindBase.cxx @@ -269,6 +269,11 @@ bool cmFindBase::ParseArguments(std::vector const& argsIn) } this->ExpandPaths(); + // Filter out ignored paths from the prefix list + std::set ignored; + this->GetIgnoredPaths(ignored); + this->FilterPaths(this->SearchPaths, ignored); + // Handle search root stuff. this->RerootPaths(this->SearchPaths); diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx index f35217262..b7d3e52f9 100644 --- a/Source/cmFindCommon.cxx +++ b/Source/cmFindCommon.cxx @@ -240,6 +240,63 @@ void cmFindCommon::RerootPaths(std::vector& paths) } } +//---------------------------------------------------------------------------- +void cmFindCommon::FilterPaths(std::vector& paths, + const std::set& ignore) +{ + // Now filter out anything that's in the ignore set. + std::vector unfiltered; + unfiltered.swap(paths); + + for(std::vector::iterator pi = unfiltered.begin(); + pi != unfiltered.end(); ++pi) + { + if (ignore.count(*pi) == 0) + { + paths.push_back(*pi); + } + } +} + + +//---------------------------------------------------------------------------- +void cmFindCommon::GetIgnoredPaths(std::vector& ignore) +{ + // null-terminated list of paths. + static const char *paths[] = + { "CMAKE_SYSTEM_IGNORE_PATH", "CMAKE_IGNORE_PATH", 0 }; + + // Construct the list of path roots with no trailing slashes. + for(const char **pathName = paths; *pathName; ++pathName) + { + // Get the list of paths to ignore from the variable. + const char* ignorePath = this->Makefile->GetDefinition(*pathName); + if((ignorePath == 0) || (strlen(ignorePath) == 0)) + { + continue; + } + + cmSystemTools::ExpandListArgument(ignorePath, ignore); + } + + for(std::vector::iterator i = ignore.begin(); + i != ignore.end(); ++i) + { + cmSystemTools::ConvertToUnixSlashes(*i); + } +} + + +//---------------------------------------------------------------------------- +void cmFindCommon::GetIgnoredPaths(std::set& ignore) +{ + std::vector ignoreVec; + GetIgnoredPaths(ignoreVec); + ignore.insert(ignoreVec.begin(), ignoreVec.end()); +} + + + //---------------------------------------------------------------------------- bool cmFindCommon::CheckCommonArgument(std::string const& arg) { diff --git a/Source/cmFindCommon.h b/Source/cmFindCommon.h index 2ffbd0053..a4866ba6f 100644 --- a/Source/cmFindCommon.h +++ b/Source/cmFindCommon.h @@ -39,6 +39,14 @@ protected: /** Place a set of search paths under the search roots. */ void RerootPaths(std::vector& paths); + /** Get ignored paths from CMAKE_[SYSTEM_]IGNORE_path variables. */ + void GetIgnoredPaths(std::vector& ignore); + void GetIgnoredPaths(std::set& ignore); + + /** Remove paths in the ignore set from the supplied vector. */ + void FilterPaths(std::vector& paths, + const std::set& ignore); + /** Add trailing slashes to all search paths. */ void AddTrailingSlashes(std::vector& paths); diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index bd58f566a..eb860143e 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -596,6 +596,15 @@ bool cmFindPackageCommand } } + // get igonored paths from vars and reroot them. + std::vector ignored; + this->GetIgnoredPaths(ignored); + this->RerootPaths(ignored); + + // Construct a set of ignored paths + this->IgnoredPaths.clear(); + this->IgnoredPaths.insert(ignored.begin(), ignored.end()); + // Find and load the package. bool result = this->HandlePackageMode(); this->AppendSuccessInformation(); @@ -1431,6 +1440,11 @@ bool cmFindPackageCommand::CheckDirectory(std::string const& dir) bool cmFindPackageCommand::FindConfigFile(std::string const& dir, std::string& file) { + if (this->IgnoredPaths.count(dir)) + { + return false; + } + for(std::vector::const_iterator ci = this->Configs.begin(); ci != this->Configs.end(); ++ci) { diff --git a/Source/cmFindPackageCommand.h b/Source/cmFindPackageCommand.h index 63f411161..53ea4fc09 100644 --- a/Source/cmFindPackageCommand.h +++ b/Source/cmFindPackageCommand.h @@ -136,6 +136,7 @@ private: bool PolicyScope; std::vector Names; std::vector Configs; + std::set IgnoredPaths; }; #endif diff --git a/Tests/FindPackageTest/CMakeLists.txt b/Tests/FindPackageTest/CMakeLists.txt index 74cc11568..a472beab6 100644 --- a/Tests/FindPackageTest/CMakeLists.txt +++ b/Tests/FindPackageTest/CMakeLists.txt @@ -54,6 +54,10 @@ SET(CMAKE_FIND_APPBUNDLE FIRST) # Set the wrong answer for a find to make sure it re-finds. set(VersionedA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lib/cmake/zot-4.0) +# Test that CMAKE_IGNORE_PATH can ignore the purposely bad package +# files in the lib/cmake/zot-3.1 directory. +set(CMAKE_IGNORE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib/cmake/zot-3.1) + # Look for packages with new-style signatures. FIND_PACKAGE(foo NO_MODULE) FIND_PACKAGE(Foo CONFIGS FooConfig.cmake) diff --git a/Tests/FindPackageTest/lib/cmake/zot-3.1/zot-config-version.cmake b/Tests/FindPackageTest/lib/cmake/zot-3.1/zot-config-version.cmake new file mode 100644 index 000000000..bee2f0eea --- /dev/null +++ b/Tests/FindPackageTest/lib/cmake/zot-3.1/zot-config-version.cmake @@ -0,0 +1,4 @@ +# Claim to be any version to test that CMAKE_IGNORE_PATH hides us. +SET(PACKAGE_VERSION 3.1) +SET(PACKAGE_VERSION_COMPATIBLE 1) +SET(PACKAGE_VERSION_EXACT 1) diff --git a/Tests/FindPackageTest/lib/cmake/zot-3.1/zot-config.cmake b/Tests/FindPackageTest/lib/cmake/zot-3.1/zot-config.cmake new file mode 100644 index 000000000..2fbd525f3 --- /dev/null +++ b/Tests/FindPackageTest/lib/cmake/zot-3.1/zot-config.cmake @@ -0,0 +1,2 @@ +# Test config file. +message(WARNING "CMAKE_IGNORE_PATH failed to ignore this file!")