mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-16 22:37:30 +08:00
find_program: Consider CWD only for paths with separator
find_program() incorrectly prepended search path components to absolute file paths, and incorrectly searched the current working directory for files that contained no directory separators. * Replace calls cmFindProgramHelper::CheckDirectory(std::string()) with call of new method cmFindProgramHelper::CheckCompoundNames() that checks for the presence of a directory separator in the file name. * Use cmSystemTools::CollapseCombinedPath rather than string concatenation to properly combine absolute file names with search path components. * Add unit tests to verify corrections. Fixes: #18044
This commit is contained in:
@@ -34,6 +34,9 @@ struct cmFindProgramHelper
|
|||||||
// Current names under consideration.
|
// Current names under consideration.
|
||||||
std::vector<std::string> Names;
|
std::vector<std::string> Names;
|
||||||
|
|
||||||
|
// Current name with extension under consideration.
|
||||||
|
std::string TestNameExt;
|
||||||
|
|
||||||
// Current full path under consideration.
|
// Current full path under consideration.
|
||||||
std::string TestPath;
|
std::string TestPath;
|
||||||
|
|
||||||
@@ -43,6 +46,19 @@ struct cmFindProgramHelper
|
|||||||
this->Names.clear();
|
this->Names.clear();
|
||||||
this->AddName(name);
|
this->AddName(name);
|
||||||
}
|
}
|
||||||
|
bool CheckCompoundNames()
|
||||||
|
{
|
||||||
|
for (std::string const& n : this->Names) {
|
||||||
|
// Only perform search relative to current directory if the file name
|
||||||
|
// contains a directory separator.
|
||||||
|
if (n.find('/') != std::string::npos) {
|
||||||
|
if (this->CheckDirectoryForName("", n)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
bool CheckDirectory(std::string const& path)
|
bool CheckDirectory(std::string const& path)
|
||||||
{
|
{
|
||||||
for (std::string const& n : this->Names) {
|
for (std::string const& n : this->Names) {
|
||||||
@@ -55,14 +71,16 @@ struct cmFindProgramHelper
|
|||||||
bool CheckDirectoryForName(std::string const& path, std::string const& name)
|
bool CheckDirectoryForName(std::string const& path, std::string const& name)
|
||||||
{
|
{
|
||||||
for (std::string const& ext : this->Extensions) {
|
for (std::string const& ext : this->Extensions) {
|
||||||
this->TestPath = path;
|
|
||||||
this->TestPath += name;
|
|
||||||
if (!ext.empty() && cmSystemTools::StringEndsWith(name, ext.c_str())) {
|
if (!ext.empty() && cmSystemTools::StringEndsWith(name, ext.c_str())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
this->TestPath += ext;
|
this->TestNameExt = name;
|
||||||
|
this->TestNameExt += ext;
|
||||||
|
this->TestPath =
|
||||||
|
cmSystemTools::CollapseCombinedPath(path, this->TestNameExt);
|
||||||
|
|
||||||
if (cmSystemTools::FileExists(this->TestPath, true)) {
|
if (cmSystemTools::FileExists(this->TestPath, true)) {
|
||||||
this->BestPath = cmSystemTools::CollapseFullPath(this->TestPath);
|
this->BestPath = this->TestPath;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,8 +163,8 @@ std::string cmFindProgramCommand::FindNormalProgramNamesPerDir()
|
|||||||
helper.AddName(n);
|
helper.AddName(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for the names themselves (e.g. absolute paths).
|
// Check for the names themselves if they contain a directory separator.
|
||||||
if (helper.CheckDirectory(std::string())) {
|
if (helper.CheckCompoundNames()) {
|
||||||
return helper.BestPath;
|
return helper.BestPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,8 +186,8 @@ std::string cmFindProgramCommand::FindNormalProgramDirsPerName()
|
|||||||
// Switch to searching for this name.
|
// Switch to searching for this name.
|
||||||
helper.SetName(n);
|
helper.SetName(n);
|
||||||
|
|
||||||
// Check for the name by itself (e.g. an absolute path).
|
// Check for the names themselves if they contain a directory separator.
|
||||||
if (helper.CheckDirectory(std::string())) {
|
if (helper.CheckCompoundNames()) {
|
||||||
return helper.BestPath;
|
return helper.BestPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
6
Tests/RunCMake/find_program/RelAndAbsPath-stdout.txt
Normal file
6
Tests/RunCMake/find_program/RelAndAbsPath-stdout.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
-- PROG_ABS='PROG_ABS-NOTFOUND'
|
||||||
|
-- PROG_ABS_NPD='PROG_ABS_NPD-NOTFOUND'
|
||||||
|
-- PROG_CWD='PROG_CWD-NOTFOUND'
|
||||||
|
-- PROG_CWD_NPD='PROG_CWD_NPD-NOTFOUND'
|
||||||
|
-- PROG_CWD_DOT='[^']*/Tests/RunCMake/find_program/testCWD'
|
||||||
|
-- PROG_CWD_DOT_NPD='[^']*/Tests/RunCMake/find_program/testCWD'
|
63
Tests/RunCMake/find_program/RelAndAbsPath.cmake
Normal file
63
Tests/RunCMake/find_program/RelAndAbsPath.cmake
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# testNoSuchFile should only be found if the file absolute path is
|
||||||
|
# incorrectly prepended with the search path.
|
||||||
|
|
||||||
|
function(strip_windows_path_prefix p outvar)
|
||||||
|
if(CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
|
||||||
|
string(REGEX REPLACE "^.:" "" p "${p}")
|
||||||
|
endif()
|
||||||
|
set(${outvar} "${p}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
strip_windows_path_prefix("${CMAKE_CURRENT_SOURCE_DIR}" srcdir)
|
||||||
|
|
||||||
|
file(MAKE_DIRECTORY "tmp${srcdir}")
|
||||||
|
configure_file(testCWD "tmp${srcdir}/testNoSuchFile" COPYONLY)
|
||||||
|
|
||||||
|
find_program(PROG_ABS
|
||||||
|
NAMES "${srcdir}/testNoSuchFile"
|
||||||
|
PATHS "${CMAKE_CURRENT_BINARY_DIR}/tmp"
|
||||||
|
NO_DEFAULT_PATH
|
||||||
|
)
|
||||||
|
message(STATUS "PROG_ABS='${PROG_ABS}'")
|
||||||
|
|
||||||
|
find_program(PROG_ABS_NPD
|
||||||
|
NAMES "${srcdir}/testNoSuchFile"
|
||||||
|
PATHS "${CMAKE_CURRENT_BINARY_DIR}/tmp"
|
||||||
|
NAMES_PER_DIR
|
||||||
|
NO_DEFAULT_PATH
|
||||||
|
)
|
||||||
|
message(STATUS "PROG_ABS_NPD='${PROG_ABS_NPD}'")
|
||||||
|
|
||||||
|
# ./testCWD should not be found without '.' being in the path list.
|
||||||
|
|
||||||
|
configure_file(testCWD testCWD COPYONLY)
|
||||||
|
|
||||||
|
find_program(PROG_CWD
|
||||||
|
NAMES testCWD
|
||||||
|
NO_DEFAULT_PATH
|
||||||
|
)
|
||||||
|
message(STATUS "PROG_CWD='${PROG_CWD}'")
|
||||||
|
|
||||||
|
find_program(PROG_CWD_NPD
|
||||||
|
NAMES testCWD
|
||||||
|
NAMES_PER_DIR
|
||||||
|
NO_DEFAULT_PATH
|
||||||
|
)
|
||||||
|
message(STATUS "PROG_CWD_NPD='${PROG_CWD_NPD}'")
|
||||||
|
|
||||||
|
# Confirm that adding '.' to path does locate ./testCWD.
|
||||||
|
|
||||||
|
find_program(PROG_CWD_DOT
|
||||||
|
NAMES testCWD
|
||||||
|
PATHS .
|
||||||
|
NO_DEFAULT_PATH
|
||||||
|
)
|
||||||
|
message(STATUS "PROG_CWD_DOT='${PROG_CWD_DOT}'")
|
||||||
|
|
||||||
|
find_program(PROG_CWD_DOT_NPD
|
||||||
|
NAMES testCWD
|
||||||
|
PATHS .
|
||||||
|
NAMES_PER_DIR
|
||||||
|
NO_DEFAULT_PATH
|
||||||
|
)
|
||||||
|
message(STATUS "PROG_CWD_DOT_NPD='${PROG_CWD_DOT_NPD}'")
|
@@ -3,6 +3,7 @@ include(RunCMake)
|
|||||||
run_cmake(EnvAndHints)
|
run_cmake(EnvAndHints)
|
||||||
run_cmake(DirsPerName)
|
run_cmake(DirsPerName)
|
||||||
run_cmake(NamesPerDir)
|
run_cmake(NamesPerDir)
|
||||||
|
run_cmake(RelAndAbsPath)
|
||||||
|
|
||||||
if(CMAKE_SYSTEM_NAME MATCHES "^(Windows|CYGWIN)$")
|
if(CMAKE_SYSTEM_NAME MATCHES "^(Windows|CYGWIN)$")
|
||||||
run_cmake(WindowsCom)
|
run_cmake(WindowsCom)
|
||||||
|
1
Tests/RunCMake/find_program/testCWD
Executable file
1
Tests/RunCMake/find_program/testCWD
Executable file
@@ -0,0 +1 @@
|
|||||||
|
#!/bin/sh
|
Reference in New Issue
Block a user