浏览代码

Teach find_(library|file|path) to get prefixes from PATH (#15370)

The find_package command already knows how to compute installation
prefixes from PATH.  Use the same approach to establish prefixes for
find_library, find_file, and find_path to use to look in directories
like "<prefix>/lib[/<arch>]" and "<prefix>/include" for libraries and
headers.  This will reduce the amount of configuration end users need to
do to establish a work environment rooted under a specific prefix.
Brad King 10 年之前
父节点
当前提交
ffc06c1239

+ 4 - 0
Help/command/FIND_XXX.txt

@@ -53,6 +53,10 @@ If NO_DEFAULT_PATH is not specified, the search process is as follows:
 .. |CMAKE_PREFIX_PATH_XXX_SUBDIR| replace::
    <prefix>/|XXX_SUBDIR| for each <prefix> in CMAKE_PREFIX_PATH
 
+.. |SYSTEM_ENVIRONMENT_PREFIX_PATH_XXX_SUBDIR| replace::
+   <prefix>/|XXX_SUBDIR| for each <prefix>/[s]bin in PATH, and
+   <entry>/|XXX_SUBDIR| for other entries in PATH
+
 .. |CMAKE_SYSTEM_PREFIX_PATH_XXX_SUBDIR| replace::
    <prefix>/|XXX_SUBDIR| for each <prefix> in CMAKE_SYSTEM_PREFIX_PATH
 

+ 4 - 1
Help/command/find_file.rst

@@ -13,7 +13,10 @@ find_file
 .. |CMAKE_XXX_PATH| replace:: CMAKE_INCLUDE_PATH
 .. |CMAKE_XXX_MAC_PATH| replace:: CMAKE_FRAMEWORK_PATH
 
-.. |SYSTEM_ENVIRONMENT_PATH_XXX| replace:: PATH and INCLUDE
+.. |SYSTEM_ENVIRONMENT_PATH_XXX| replace:: Directories in INCLUDE,
+   <prefix>/include/<arch> if CMAKE_LIBRARY_ARCHITECTURE is set, and
+   |SYSTEM_ENVIRONMENT_PREFIX_PATH_XXX_SUBDIR|,
+   and the directories in PATH itself.
 
 .. |CMAKE_SYSTEM_PREFIX_PATH_XXX| replace::
    <prefix>/include/<arch> if CMAKE_LIBRARY_ARCHITECTURE is set, and

+ 4 - 1
Help/command/find_library.rst

@@ -13,7 +13,10 @@ find_library
 .. |CMAKE_XXX_PATH| replace:: CMAKE_LIBRARY_PATH
 .. |CMAKE_XXX_MAC_PATH| replace:: CMAKE_FRAMEWORK_PATH
 
-.. |SYSTEM_ENVIRONMENT_PATH_XXX| replace:: PATH and LIB
+.. |SYSTEM_ENVIRONMENT_PATH_XXX| replace:: Directories in LIB,
+   <prefix>/lib/<arch> if CMAKE_LIBRARY_ARCHITECTURE is set, and
+   |SYSTEM_ENVIRONMENT_PREFIX_PATH_XXX_SUBDIR|,
+   and the directories in PATH itself.
 
 .. |CMAKE_SYSTEM_PREFIX_PATH_XXX| replace::
    <prefix>/lib/<arch> if CMAKE_LIBRARY_ARCHITECTURE is set, and

+ 4 - 1
Help/command/find_path.rst

@@ -13,7 +13,10 @@ find_path
 .. |CMAKE_XXX_PATH| replace:: CMAKE_INCLUDE_PATH
 .. |CMAKE_XXX_MAC_PATH| replace:: CMAKE_FRAMEWORK_PATH
 
-.. |SYSTEM_ENVIRONMENT_PATH_XXX| replace:: PATH and INCLUDE
+.. |SYSTEM_ENVIRONMENT_PATH_XXX| replace:: Directories in INCLUDE,
+   <prefix>/include/<arch> if CMAKE_LIBRARY_ARCHITECTURE is set, and
+   |SYSTEM_ENVIRONMENT_PREFIX_PATH_XXX_SUBDIR|,
+   and the directories in PATH itself.
 
 .. |CMAKE_SYSTEM_PREFIX_PATH_XXX| replace::
    <prefix>/include/<arch> if CMAKE_LIBRARY_ARCHITECTURE is set, and

+ 6 - 0
Help/release/dev/find-command-prefix-from-PATH.rst

@@ -0,0 +1,6 @@
+find-command-prefix-from-PATH
+-----------------------------
+
+* The :command:`find_library`, :command:`find_path`, and :command:`find_file`
+  commands now search in installation prefixes derived from the ``PATH``
+  environment variable.

+ 1 - 0
Source/cmFindBase.cxx

@@ -275,6 +275,7 @@ void cmFindBase::FillSystemEnvironmentPath()
   if(!this->EnvironmentPath.empty())
     {
     paths.AddEnvPath(this->EnvironmentPath);
+    paths.AddEnvPrefixPath("PATH", true);
     }
   // Add PATH
   paths.AddEnvPath("PATH");

+ 21 - 1
Source/cmSearchPath.cxx

@@ -136,10 +136,30 @@ void cmSearchPath::AddCMakePrefixPath(const std::string& variable)
 }
 
 //----------------------------------------------------------------------------
-void cmSearchPath::AddEnvPrefixPath(const std::string& variable)
+static std::string cmSearchPathStripBin(std::string const& s)
+{
+  // If the path is a PREFIX/bin case then add its parent instead.
+  if((cmHasLiteralSuffix(s, "/bin")) ||
+     (cmHasLiteralSuffix(s, "/sbin")))
+    {
+    return cmSystemTools::GetFilenamePath(s);
+    }
+  else
+    {
+    return s;
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmSearchPath::AddEnvPrefixPath(const std::string& variable, bool stripBin)
 {
   std::vector<std::string> expanded;
   cmSystemTools::GetPath(expanded, variable.c_str());
+  if (stripBin)
+    {
+    std::transform(expanded.begin(), expanded.end(), expanded.begin(),
+                   cmSearchPathStripBin);
+    }
   this->AddPrefixPaths(expanded);
 }
 

+ 1 - 1
Source/cmSearchPath.h

@@ -42,7 +42,7 @@ public:
   void AddCMakePath(const std::string& variable);
   void AddEnvPath(const std::string& variable);
   void AddCMakePrefixPath(const std::string& variable);
-  void AddEnvPrefixPath(const std::string& variable);
+  void AddEnvPrefixPath(const std::string& variable, bool stripBin = false);
   void AddSuffixes(const std::vector<std::string>& suffixes);
 
 protected:

+ 2 - 0
Tests/RunCMake/CMakeLists.txt

@@ -131,8 +131,10 @@ add_RunCMake_test(export)
 add_RunCMake_test(cmake_minimum_required)
 add_RunCMake_test(continue)
 add_RunCMake_test(file)
+add_RunCMake_test(find_file)
 add_RunCMake_test(find_library)
 add_RunCMake_test(find_package)
+add_RunCMake_test(find_path)
 add_RunCMake_test(get_filename_component)
 add_RunCMake_test(get_property)
 add_RunCMake_test(if)

+ 3 - 0
Tests/RunCMake/find_file/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.1)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)

+ 4 - 0
Tests/RunCMake/find_file/PrefixInPATH-stdout.txt

@@ -0,0 +1,4 @@
+-- PrefixInPATH_INCLUDE_DIR='PrefixInPATH_INCLUDE_DIR-NOTFOUND'
+-- PrefixInPATH_INCLUDE_DIR='.*/Tests/RunCMake/find_file/include/PrefixInPATH.h'
+-- PrefixInPATH_INCLUDE_DIR='.*/Tests/RunCMake/find_file/include/PrefixInPATH.h'
+-- PrefixInPATH_INCLUDE_DIR='.*/Tests/RunCMake/find_file/include/PrefixInPATH.h'

+ 8 - 0
Tests/RunCMake/find_file/PrefixInPATH.cmake

@@ -0,0 +1,8 @@
+set(ENV_PATH "$ENV{PATH}")
+foreach(path "/does_not_exist" "" "/bin" "/sbin")
+  unset(PrefixInPATH_INCLUDE_DIR CACHE)
+  set(ENV{PATH} "${CMAKE_CURRENT_SOURCE_DIR}${path}")
+  find_file(PrefixInPATH_INCLUDE_DIR NAMES PrefixInPATH.h)
+  message(STATUS "PrefixInPATH_INCLUDE_DIR='${PrefixInPATH_INCLUDE_DIR}'")
+endforeach()
+set(ENV{PATH} "${ENV_PATH}")

+ 3 - 0
Tests/RunCMake/find_file/RunCMakeTest.cmake

@@ -0,0 +1,3 @@
+include(RunCMake)
+
+run_cmake(PrefixInPATH)

+ 0 - 0
Tests/RunCMake/find_file/include/PrefixInPATH.h


+ 4 - 0
Tests/RunCMake/find_library/PrefixInPATH-stdout.txt

@@ -0,0 +1,4 @@
+-- PrefixInPATH_LIBRARY='PrefixInPATH_LIBRARY-NOTFOUND'
+-- PrefixInPATH_LIBRARY='.*/Tests/RunCMake/find_library/lib/libPrefixInPATH.a'
+-- PrefixInPATH_LIBRARY='.*/Tests/RunCMake/find_library/lib/libPrefixInPATH.a'
+-- PrefixInPATH_LIBRARY='.*/Tests/RunCMake/find_library/lib/libPrefixInPATH.a'

+ 11 - 0
Tests/RunCMake/find_library/PrefixInPATH.cmake

@@ -0,0 +1,11 @@
+list(APPEND CMAKE_FIND_LIBRARY_PREFIXES lib)
+list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES .a)
+
+set(ENV_PATH "$ENV{PATH}")
+foreach(path "/does_not_exist" "" "/bin" "/sbin")
+  unset(PrefixInPATH_LIBRARY CACHE)
+  set(ENV{PATH} "${CMAKE_CURRENT_SOURCE_DIR}${path}")
+  find_library(PrefixInPATH_LIBRARY NAMES PrefixInPATH)
+  message(STATUS "PrefixInPATH_LIBRARY='${PrefixInPATH_LIBRARY}'")
+endforeach()
+set(ENV{PATH} "${ENV_PATH}")

+ 1 - 0
Tests/RunCMake/find_library/RunCMakeTest.cmake

@@ -1,3 +1,4 @@
 include(RunCMake)
 
 run_cmake(Created)
+run_cmake(PrefixInPATH)

+ 0 - 0
Tests/RunCMake/find_library/lib/libPrefixInPATH.a


+ 3 - 0
Tests/RunCMake/find_path/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.1)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)

+ 4 - 0
Tests/RunCMake/find_path/PrefixInPATH-stdout.txt

@@ -0,0 +1,4 @@
+-- PrefixInPATH_INCLUDE_DIR='PrefixInPATH_INCLUDE_DIR-NOTFOUND'
+-- PrefixInPATH_INCLUDE_DIR='.*/Tests/RunCMake/find_path/include'
+-- PrefixInPATH_INCLUDE_DIR='.*/Tests/RunCMake/find_path/include'
+-- PrefixInPATH_INCLUDE_DIR='.*/Tests/RunCMake/find_path/include'

+ 8 - 0
Tests/RunCMake/find_path/PrefixInPATH.cmake

@@ -0,0 +1,8 @@
+set(ENV_PATH "$ENV{PATH}")
+foreach(path "/does_not_exist" "" "/bin" "/sbin")
+  unset(PrefixInPATH_INCLUDE_DIR CACHE)
+  set(ENV{PATH} "${CMAKE_CURRENT_SOURCE_DIR}${path}")
+  find_path(PrefixInPATH_INCLUDE_DIR NAMES PrefixInPATH.h)
+  message(STATUS "PrefixInPATH_INCLUDE_DIR='${PrefixInPATH_INCLUDE_DIR}'")
+endforeach()
+set(ENV{PATH} "${ENV_PATH}")

+ 3 - 0
Tests/RunCMake/find_path/RunCMakeTest.cmake

@@ -0,0 +1,3 @@
+include(RunCMake)
+
+run_cmake(PrefixInPATH)

+ 0 - 0
Tests/RunCMake/find_path/include/PrefixInPATH.h