From 01f92efeb0c486fa768161d317f59cb5f7806664 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 2 Apr 2025 11:22:35 -0400 Subject: [PATCH] Restore expansion of leading '~' as home directory in input paths This was accidentally dropped by commit 622596c6b2 (cmSystemTools: Re-implement ToNormalizedPathOnDisk without translation map, 2024-10-30, v4.0.0-rc1~528^2~5). Previously it was done by `CollapseFullPath`. `cm::PathResolver` intentionally does not expand `~` because it makes sense only for transforming input paths. Teach `ToNormalizedPathOnDisk` to handle it directly. Fixes: #26827 --- Source/CMakeLists.txt | 5 +++ Source/cmSystemTools.cxx | 39 +++++++++++++++++++ Tests/RunCMake/CommandLine/D-tilde.cmake | 21 ++++++++++ Tests/RunCMake/CommandLine/RunCMakeTest.cmake | 1 + 4 files changed, 66 insertions(+) create mode 100644 Tests/RunCMake/CommandLine/D-tilde.cmake diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 4d1fde9919..1d078ee50b 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -1033,6 +1033,11 @@ endif() if(CMAKE_SYSTEM_NAME STREQUAL "SunOS" AND CMAKE_SYSTEM_VERSION STREQUAL "5.10" AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(i386|x86_64)$") set_property(SOURCE cmSystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS CMAKE_NO_MKDTEMP) endif() +get_property(targetSupportsSharedLibs GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS) +if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT targetSupportsSharedLibs) + # Disable getpwnam for static linux builds since it depends on shared glibc. + set_property(SOURCE cmSystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS CMAKE_NO_GETPWNAM) +endif() # Some atomic instructions are implemented using libatomic on some platforms. if(CMake_HAVE_CXX_ATOMIC_LIB) diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index c2c5cd77cf..1968f3b75b 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -149,6 +149,15 @@ # include #endif +#ifndef CMAKE_NO_GETPWNAM +# if defined(_WIN32) +# define CMAKE_NO_GETPWNAM +# endif +#endif +#ifndef CMAKE_NO_GETPWNAM +# include +#endif + #if defined(_MSC_VER) && _MSC_VER >= 1800 # define CM_WINDOWS_DEPRECATED_GetVersionEx #endif @@ -160,6 +169,35 @@ cmSystemTools::MessageCallback s_MessageCallback; cmSystemTools::OutputCallback s_StderrCallback; cmSystemTools::OutputCallback s_StdoutCallback; +std::string ResolveTildePath(std::string p) +{ + if (!p.empty() && p[0] == '~') { + cm::optional home; + std::string::size_type last = p.find_first_of("/\\"); + if (last == std::string::npos) { + last = p.size(); + } + if (last == 1) { +#if defined(_WIN32) && !defined(__CYGWIN__) + home = cmSystemTools::GetEnvVar("USERPROFILE"); + if (!home) +#endif + home = cmSystemTools::GetEnvVar("HOME"); +#ifndef CMAKE_NO_GETPWNAM + } else if (last > 1) { + std::string user = p.substr(1, last - 1); + if (passwd* pw = getpwnam(user.c_str())) { + home = std::string(pw->pw_dir); + } +#endif + } + if (home) { + p.replace(0, last, *home); + } + } + return p; +} + #ifdef _WIN32 std::string GetDosDriveWorkingDirectory(char letter) { @@ -2044,6 +2082,7 @@ std::vector cmSystemTools::SplitEnvPathNormalized( std::string cmSystemTools::ToNormalizedPathOnDisk(std::string p) { + p = ResolveTildePath(p); using namespace cm::PathResolver; #ifdef _WIN32 // IWYU pragma: no_forward_declare cm::PathResolver::Policies::CasePath diff --git a/Tests/RunCMake/CommandLine/D-tilde.cmake b/Tests/RunCMake/CommandLine/D-tilde.cmake new file mode 100644 index 0000000000..63028ea246 --- /dev/null +++ b/Tests/RunCMake/CommandLine/D-tilde.cmake @@ -0,0 +1,21 @@ +if(NOT "$ENV{HOME}" STREQUAL "") + if(TILDE_PATH MATCHES "~" OR NOT IS_ABSOLUTE "${TILDE_PATH}") + message(SEND_ERROR "~ not expanded as expected:\n ${TILDE_PATH}") + endif() + + if(TILDE_SLASH_PATH MATCHES "~" OR NOT IS_ABSOLUTE "${TILDE_SLASH_PATH}" OR NOT TILDE_SLASH_PATH MATCHES "/InHome$") + message(SEND_ERROR "~/ not expanded as expected:\n ${TILDE_SLASH_PATH}") + endif() +else() + set(ENV{HOME} "${CMAKE_CURRENT_LIST_DIR}") +endif() + +set(TILDE "" CACHE PATH "") +if(TILDE MATCHES "~" OR NOT IS_ABSOLUTE "${TILDE}") + message(SEND_ERROR "~ not expanded as expected:\n ${TILDE}") +endif() + +set(TILDE_SLASH "" CACHE PATH "") +if(TILDE_SLASH MATCHES "~" OR NOT IS_ABSOLUTE "${TILDE_SLASH}" OR NOT TILDE_SLASH MATCHES "/InHome$") + message(SEND_ERROR "~/ not expanded as expected:\n ${TILDE_SLASH}") +endif() diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index 06ef1ebd2c..5c5d55658e 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -18,6 +18,7 @@ run_cmake_command(lists-no-file ${CMAKE_COMMAND} nosuchsubdir/CMakeLists.txt) run_cmake_command(D-no-arg ${CMAKE_COMMAND} -B DummyBuildDir -D) run_cmake_command(D-no-src ${CMAKE_COMMAND} -B DummyBuildDir -D VAR=VALUE) run_cmake_command(Dno-src ${CMAKE_COMMAND} -B DummyBuildDir -DVAR=VALUE) +run_cmake_script(D-tilde -DTILDE=~ -DTILDE_PATH:PATH=~ -DTILDE_SLASH=~/InHome -DTILDE_SLASH_PATH:PATH=~/InHome) run_cmake_command(U-no-arg ${CMAKE_COMMAND} -B DummyBuildDir -U) run_cmake_command(U-no-src ${CMAKE_COMMAND} -B DummyBuildDir -U VAR) run_cmake_command(Uno-src ${CMAKE_COMMAND} -B DummyBuildDir -UVAR)