From d46bac5d38320907cc1f11a223fddd9a11c9b184 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 24 Jul 2019 09:53:53 -0400 Subject: 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 --- Source/kwsys/SystemTools.cxx | 7 ++++++- Source/kwsys/testSystemTools.cxx | 8 ++++++-- Tests/RunCMake/BuildDepends/BuildUnderSource.c | 5 +++++ Tests/RunCMake/BuildDepends/BuildUnderSource.cmake | 9 +++++++++ Tests/RunCMake/BuildDepends/BuildUnderSource.step1.cmake | 3 +++ Tests/RunCMake/BuildDepends/BuildUnderSource.step2.cmake | 3 +++ Tests/RunCMake/BuildDepends/RunCMakeTest.cmake | 16 +++++++++++++++- 7 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 Tests/RunCMake/BuildDepends/BuildUnderSource.c create mode 100644 Tests/RunCMake/BuildDepends/BuildUnderSource.cmake create mode 100644 Tests/RunCMake/BuildDepends/BuildUnderSource.step1.cmake create mode 100644 Tests/RunCMake/BuildDepends/BuildUnderSource.step2.cmake diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index 2135913..ae7a18a 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -3394,8 +3394,13 @@ static void SystemToolsAppendComponents( static const std::string cur = "."; for (std::vector::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) diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx index 9a40b53..ffa6a29 100644 --- a/Source/kwsys/testSystemTools.cxx +++ b/Source/kwsys/testSystemTools.cxx @@ -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; } diff --git a/Tests/RunCMake/BuildDepends/BuildUnderSource.c b/Tests/RunCMake/BuildDepends/BuildUnderSource.c new file mode 100644 index 0000000..688a040 --- /dev/null +++ b/Tests/RunCMake/BuildDepends/BuildUnderSource.c @@ -0,0 +1,5 @@ +#include "BuildUnderSource.h" +int main(void) +{ + return BUILD_UNDER_SOURCE; +} diff --git a/Tests/RunCMake/BuildDepends/BuildUnderSource.cmake b/Tests/RunCMake/BuildDepends/BuildUnderSource.cmake new file mode 100644 index 0000000..aa2a44f --- /dev/null +++ b/Tests/RunCMake/BuildDepends/BuildUnderSource.cmake @@ -0,0 +1,9 @@ +enable_language(C) +include_directories(include) +add_executable(BuildUnderSource BuildUnderSource.c) + +file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$>.cmake CONTENT " +set(check_pairs + \"$|${CMAKE_CURRENT_SOURCE_DIR}/include/BuildUnderSource.h\" + ) +") diff --git a/Tests/RunCMake/BuildDepends/BuildUnderSource.step1.cmake b/Tests/RunCMake/BuildDepends/BuildUnderSource.step1.cmake new file mode 100644 index 0000000..2cdd32b --- /dev/null +++ b/Tests/RunCMake/BuildDepends/BuildUnderSource.step1.cmake @@ -0,0 +1,3 @@ +file(WRITE "${RunCMake_TEST_SOURCE_DIR}/include/BuildUnderSource.h" [[ +#define BUILD_UNDER_SOURCE 1 +]]) diff --git a/Tests/RunCMake/BuildDepends/BuildUnderSource.step2.cmake b/Tests/RunCMake/BuildDepends/BuildUnderSource.step2.cmake new file mode 100644 index 0000000..8e4b858 --- /dev/null +++ b/Tests/RunCMake/BuildDepends/BuildUnderSource.step2.cmake @@ -0,0 +1,3 @@ +file(WRITE "${RunCMake_TEST_SOURCE_DIR}/include/BuildUnderSource.h" [[ +#define BUILD_UNDER_SOURCE 2 +]]) diff --git a/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake b/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake index 3445beb..14ae243 100644 --- a/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake +++ b/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake @@ -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}") -- cgit v0.12