From ae873d4a8987fc840d7b7515719d438918ea8f5b Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 9 Feb 2009 09:23:55 -0500 Subject: [PATCH] ENH: Add get_filename_component(... REALPATH) This patch from Philip Lowman creates a REALPATH mode in the get_filename_component command. It is like ABSOLUTE, but will also resolve symlinks (which ABSOLUTE once did but was broken long ago). See issue #8423. --- Source/cmGetFilenameComponentCommand.cxx | 8 ++- Source/cmGetFilenameComponentCommand.h | 5 +- Tests/CMakeTests/CMakeLists.txt | 1 + .../GetFilenameComponentRealpathTest.cmake.in | 57 +++++++++++++++++++ 4 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 Tests/CMakeTests/GetFilenameComponentRealpathTest.cmake.in diff --git a/Source/cmGetFilenameComponentCommand.cxx b/Source/cmGetFilenameComponentCommand.cxx index d06efe88e..8502e5738 100644 --- a/Source/cmGetFilenameComponentCommand.cxx +++ b/Source/cmGetFilenameComponentCommand.cxx @@ -75,7 +75,8 @@ bool cmGetFilenameComponentCommand { result = cmSystemTools::GetFilenameWithoutExtension(filename); } - else if (args[2] == "ABSOLUTE") + else if (args[2] == "ABSOLUTE" || + args[2] == "REALPATH") { // If the path given is relative evaluate it relative to the // current source directory. @@ -92,6 +93,11 @@ bool cmGetFilenameComponentCommand // Collapse the path to its simplest form. result = cmSystemTools::CollapseFullPath(filename.c_str()); + if(args[2] == "REALPATH") + { + // Resolve symlinks if possible + result = cmSystemTools::GetRealPath(filename.c_str()); + } } else { diff --git a/Source/cmGetFilenameComponentCommand.h b/Source/cmGetFilenameComponentCommand.h index e058e0be2..65cf1a230 100644 --- a/Source/cmGetFilenameComponentCommand.h +++ b/Source/cmGetFilenameComponentCommand.h @@ -68,11 +68,12 @@ public: { return " get_filename_component(VarName FileName\n" - " PATH|ABSOLUTE|NAME|EXT|NAME_WE\n" + " PATH|ABSOLUTE|NAME|EXT|NAME_WE|REALPATH\n" " [CACHE])\n" "Set VarName to be the path (PATH), file name (NAME), file " "extension (EXT), file name without extension (NAME_WE) of FileName, " - "or the full path (ABSOLUTE). " + "the full path (ABSOLUTE), or the full path with all symlinks " + "resolved (REALPATH). " "Note that the path is converted to Unix slashes format and has no " "trailing slashes. The longest file extension is always considered. " "If the optional CACHE argument is specified, the result variable is " diff --git a/Tests/CMakeTests/CMakeLists.txt b/Tests/CMakeTests/CMakeLists.txt index 9f91abc82..9e3c3e7d2 100644 --- a/Tests/CMakeTests/CMakeLists.txt +++ b/Tests/CMakeTests/CMakeLists.txt @@ -14,6 +14,7 @@ AddCMakeTest(VariableWatch "") AddCMakeTest(Include "") AddCMakeTest(FindBase "") AddCMakeTest(Toolchain "") +AddCMakeTest(GetFilenameComponentRealpath "") SET(GetPrerequisites_PreArgs "-DCTEST_CONFIGURATION_TYPE:STRING=\\\${CTEST_CONFIGURATION_TYPE}" diff --git a/Tests/CMakeTests/GetFilenameComponentRealpathTest.cmake.in b/Tests/CMakeTests/GetFilenameComponentRealpathTest.cmake.in new file mode 100644 index 000000000..c795512a2 --- /dev/null +++ b/Tests/CMakeTests/GetFilenameComponentRealpathTest.cmake.in @@ -0,0 +1,57 @@ +set(bindir ${CMAKE_CURRENT_BINARY_DIR}) + +# +# Test nonexistent REALPATH & ABSOLUTE resolution +# +get_filename_component(nonexistent1 ${bindir}/THIS_IS_A_NONEXISTENT_FILE REALPATH) +get_filename_component(nonexistent2 ${bindir}/THIS_IS_A_NONEXISTENT_FILE ABSOLUTE) +if(NOT nonexistent1 STREQUAL "${bindir}/THIS_IS_A_NONEXISTENT_FILE") + message(FATAL_ERROR "REALPATH is not preserving nonexistent files") +endif() +if(NOT nonexistent2 STREQUAL "${bindir}/THIS_IS_A_NONEXISTENT_FILE") + message(FATAL_ERROR "ABSOLUTE is not preserving nonexistent files") +endif() + +# +# Test symbolic link resolution +# +if(UNIX) + # file1 => file2 => file3 (real) + file(WRITE ${bindir}/file3 "test file") + + find_program(LN NAMES "ln") + if(LN) + # Create symlinks using "ln -s" + if(NOT EXISTS ${bindir}/file2) + execute_process(COMMAND ${LN} "-s" "${bindir}/file3" "${bindir}/file2") + endif() + if(NOT EXISTS ${bindir}/file1) + execute_process(COMMAND ${LN} "-s" "${bindir}/file2" "${bindir}/file1") + endif() + + get_filename_component(file1 ${bindir}/file1 REALPATH) + get_filename_component(file2 ${bindir}/file2 REALPATH) + get_filename_component(file3 ${bindir}/file3 REALPATH) + + if(NOT file3 STREQUAL "${bindir}/file3") + message(FATAL_ERROR "CMake fails resolving REALPATH file file3") + endif() + + if(NOT file2 STREQUAL "${bindir}/file3") + message(FATAL_ERROR "CMake fails resolving simple symlink") + endif() + + if(NOT file1 STREQUAL "${bindir}/file3") + message(FATAL_ERROR "CMake fails resolving double symlink") + endif() + + # cleanup + file(REMOVE ${bindir}/file1) + file(REMOVE ${bindir}/file2) + if(EXISTS file1 OR EXISTS file2) + message(FATAL_ERROR "removal of file1 or file2 failed") + endif() + endif(LN) + + file(REMOVE ${bindir}/file3) +endif()