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:
parent
575f97763f
commit
c76c1ea208
@ -34,6 +34,9 @@ struct cmFindProgramHelper
|
||||
// Current names under consideration.
|
||||
std::vector<std::string> Names;
|
||||
|
||||
// Current name with extension under consideration.
|
||||
std::string TestNameExt;
|
||||
|
||||
// Current full path under consideration.
|
||||
std::string TestPath;
|
||||
|
||||
@ -43,6 +46,19 @@ struct cmFindProgramHelper
|
||||
this->Names.clear();
|
||||
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)
|
||||
{
|
||||
for (std::string const& n : this->Names) {
|
||||
@ -55,14 +71,16 @@ struct cmFindProgramHelper
|
||||
bool CheckDirectoryForName(std::string const& path, std::string const& name)
|
||||
{
|
||||
for (std::string const& ext : this->Extensions) {
|
||||
this->TestPath = path;
|
||||
this->TestPath += name;
|
||||
if (!ext.empty() && cmSystemTools::StringEndsWith(name, ext.c_str())) {
|
||||
continue;
|
||||
}
|
||||
this->TestPath += ext;
|
||||
this->TestNameExt = name;
|
||||
this->TestNameExt += ext;
|
||||
this->TestPath =
|
||||
cmSystemTools::CollapseCombinedPath(path, this->TestNameExt);
|
||||
|
||||
if (cmSystemTools::FileExists(this->TestPath, true)) {
|
||||
this->BestPath = cmSystemTools::CollapseFullPath(this->TestPath);
|
||||
this->BestPath = this->TestPath;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -145,8 +163,8 @@ std::string cmFindProgramCommand::FindNormalProgramNamesPerDir()
|
||||
helper.AddName(n);
|
||||
}
|
||||
|
||||
// Check for the names themselves (e.g. absolute paths).
|
||||
if (helper.CheckDirectory(std::string())) {
|
||||
// Check for the names themselves if they contain a directory separator.
|
||||
if (helper.CheckCompoundNames()) {
|
||||
return helper.BestPath;
|
||||
}
|
||||
|
||||
@ -168,8 +186,8 @@ std::string cmFindProgramCommand::FindNormalProgramDirsPerName()
|
||||
// Switch to searching for this name.
|
||||
helper.SetName(n);
|
||||
|
||||
// Check for the name by itself (e.g. an absolute path).
|
||||
if (helper.CheckDirectory(std::string())) {
|
||||
// Check for the names themselves if they contain a directory separator.
|
||||
if (helper.CheckCompoundNames()) {
|
||||
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(DirsPerName)
|
||||
run_cmake(NamesPerDir)
|
||||
run_cmake(RelAndAbsPath)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "^(Windows|CYGWIN)$")
|
||||
run_cmake(WindowsCom)
|
||||
|
1
Tests/RunCMake/find_program/testCWD
Executable file
1
Tests/RunCMake/find_program/testCWD
Executable file
@ -0,0 +1 @@
|
||||
#!/bin/sh
|
Loading…
Reference in New Issue
Block a user