Makefile: Fix regression in dependencies on relative includes

Since commit a13a5c948e (Replace use of CollapseCombinedPath with
CollapseFullPath, 2019-03-19, v3.15.0-rc1~361^2~1), one code path now
calls `CollapseFullPath` with a base path that may be relative.
Backport KWSys commit c6f8e24a3 (SystemTools: Fix CollapseFullPath with
relative base path, 2019-07-24) to handle such base paths.

This case occurs when a build tree is placed in a directory inside a
source tree such that CMake is willing to generate a relative path from
the build tree to the source tree.  Add a test covering this case.

Fixes: #19507
This commit is contained in:
Brad King 2019-07-24 09:53:53 -04:00
parent 79bcf4e165
commit d46bac5d38
7 changed files with 47 additions and 4 deletions

View File

@ -3394,8 +3394,13 @@ static void SystemToolsAppendComponents(
static const std::string cur = ".";
for (std::vector<std::string>::const_iterator i = first; i != last; ++i) {
if (*i == up) {
if (out_components.size() > 1) {
// Remove the previous component if possible. Ignore ../ components
// that try to go above the root. Keep ../ components if they are
// at the beginning of a relative path (base path is relative).
if (out_components.size() > 1 && out_components.back() != up) {
out_components.resize(out_components.size() - 1);
} else if (!out_components.empty() && out_components[0].empty()) {
out_components.emplace_back(std::move(*i));
}
} else if (!i->empty() && *i != cur) {
#if __cplusplus >= 201103L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201103L)

View File

@ -684,9 +684,10 @@ static bool CheckRelativePaths()
}
static bool CheckCollapsePath(const std::string& path,
const std::string& expected)
const std::string& expected,
const char* base = nullptr)
{
std::string result = kwsys::SystemTools::CollapseFullPath(path);
std::string result = kwsys::SystemTools::CollapseFullPath(path, base);
if (!kwsys::SystemTools::ComparePath(expected, result)) {
std::cerr << "CollapseFullPath(" << path << ") yielded " << result
<< " instead of " << expected << std::endl;
@ -710,6 +711,9 @@ static bool CheckCollapsePath()
res &= CheckCollapsePath("C:/", "C:/");
res &= CheckCollapsePath("C:/../", "C:/");
res &= CheckCollapsePath("C:/../../", "C:/");
res &= CheckCollapsePath("../b", "../../b", "../");
res &= CheckCollapsePath("../a/../b", "../b", "../rel");
res &= CheckCollapsePath("a/../b", "../rel/b", "../rel");
return res;
}

View File

@ -0,0 +1,5 @@
#include "BuildUnderSource.h"
int main(void)
{
return BUILD_UNDER_SOURCE;
}

View File

@ -0,0 +1,9 @@
enable_language(C)
include_directories(include)
add_executable(BuildUnderSource BuildUnderSource.c)
file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
set(check_pairs
\"$<TARGET_FILE:BuildUnderSource>|${CMAKE_CURRENT_SOURCE_DIR}/include/BuildUnderSource.h\"
)
")

View File

@ -0,0 +1,3 @@
file(WRITE "${RunCMake_TEST_SOURCE_DIR}/include/BuildUnderSource.h" [[
#define BUILD_UNDER_SOURCE 1
]])

View File

@ -0,0 +1,3 @@
file(WRITE "${RunCMake_TEST_SOURCE_DIR}/include/BuildUnderSource.h" [[
#define BUILD_UNDER_SOURCE 2
]])

View File

@ -9,7 +9,9 @@ endif()
function(run_BuildDepends CASE)
# Use a single build tree for a few tests without cleaning.
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${CASE}-build)
if(NOT RunCMake_TEST_BINARY_DIR)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${CASE}-build)
endif()
set(RunCMake_TEST_NO_CLEAN 1)
if(NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
@ -44,6 +46,18 @@ endif()
run_BuildDepends(Custom-Symbolic-and-Byproduct)
run_BuildDepends(Custom-Always)
# Test header dependencies with a build tree underneath a source tree.
set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/BuildUnderSource")
set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/BuildUnderSource/build")
file(REMOVE_RECURSE "${RunCMake_TEST_SOURCE_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_SOURCE_DIR}/include")
foreach(f CMakeLists.txt BuildUnderSource.cmake BuildUnderSource.c)
configure_file("${RunCMake_SOURCE_DIR}/${f}" "${RunCMake_TEST_SOURCE_DIR}/${f}" COPYONLY)
endforeach()
run_BuildDepends(BuildUnderSource)
unset(RunCMake_TEST_BINARY_DIR)
unset(RunCMake_TEST_SOURCE_DIR)
if(RunCMake_GENERATOR MATCHES "Make")
run_BuildDepends(MakeCustomIncludes)
if(NOT "${RunCMake_BINARY_DIR}" STREQUAL "${RunCMake_SOURCE_DIR}")