summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Chevrier <marc.chevrier@gmail.com>2020-08-26 12:33:18 (GMT)
committerMarc Chevrier <marc.chevrier@gmail.com>2020-09-08 16:33:57 (GMT)
commitbe36266dabee16d17a4f2e71fa9d05f8ef4769ce (patch)
tree57d4da5efc5b6b4dc8837acb63dcb471fd8266b5
parent503d0f80e1ccafa8352145b1a733dd41751dcd7f (diff)
downloadCMake-be36266dabee16d17a4f2e71fa9d05f8ef4769ce.zip
CMake-be36266dabee16d17a4f2e71fa9d05f8ef4769ce.tar.gz
CMake-be36266dabee16d17a4f2e71fa9d05f8ef4769ce.tar.bz2
file(): Add REAL_PATH sub-command
-rw-r--r--Help/command/file.rst14
-rw-r--r--Help/command/get_filename_component.rst5
-rw-r--r--Help/release/dev/file-REAL_PATH.rst5
-rw-r--r--Source/cmFileCommand.cxx46
-rw-r--r--Tests/RunCMake/file/REAL_PATH-no-base-dir-result.txt1
-rw-r--r--Tests/RunCMake/file/REAL_PATH-no-base-dir-stderr.txt2
-rw-r--r--Tests/RunCMake/file/REAL_PATH-no-base-dir.cmake2
-rw-r--r--Tests/RunCMake/file/REAL_PATH-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/file/REAL_PATH-unexpected-arg-stderr.txt2
-rw-r--r--Tests/RunCMake/file/REAL_PATH-unexpected-arg.cmake2
-rw-r--r--Tests/RunCMake/file/REAL_PATH.cmake14
-rw-r--r--Tests/RunCMake/file/RunCMakeTest.cmake3
12 files changed, 95 insertions, 2 deletions
diff --git a/Help/command/file.rst b/Help/command/file.rst
index f4a817e..d77ad2d 100644
--- a/Help/command/file.rst
+++ b/Help/command/file.rst
@@ -49,6 +49,7 @@ Synopsis
file(`CHMOD_RECURSE`_ <files>... <directories>... PERMISSIONS <permissions>... [...])
`Path Conversion`_
+ file(`REAL_PATH`_ <path> <out-var> [BASE_DIRECTORY <dir>])
file(`RELATIVE_PATH`_ <out-var> <directory> <file>)
file({`TO_CMAKE_PATH`_ | `TO_NATIVE_PATH`_} <path> <out-var>)
@@ -806,6 +807,19 @@ the ``<directories>..`` recursively.
Path Conversion
^^^^^^^^^^^^^^^
+.. _REAL_PATH:
+
+.. code-block:: cmake
+
+ file(REAL_PATH <path> <out-var> [BASE_DIRECTORY <dir>])
+
+Compute the absolute path to an existing file or directory with symlinks
+resolved.
+
+If the provided ``<path>`` is a relative path, it is evaluated relative to the
+given base directory ``<dir>``. If no base directory is provided, the default
+base directory will be :variable:`CMAKE_CURRENT_SOURCE_DIR`.
+
.. _RELATIVE_PATH:
.. code-block:: cmake
diff --git a/Help/command/get_filename_component.rst b/Help/command/get_filename_component.rst
index 9d33a0a..e8c68b2 100644
--- a/Help/command/get_filename_component.rst
+++ b/Help/command/get_filename_component.rst
@@ -46,8 +46,9 @@ cache.
.. note::
- All previous sub-commands, except ``REALPATH``, has been superseded by
- :command:`cmake_path` command.
+ All previous sub-commands has been superseded by
+ :command:`cmake_path` command, except ``REALPATH`` now offered by
+ :ref:`file(REAL_PATH) <REAL_PATH>` command.
.. code-block:: cmake
diff --git a/Help/release/dev/file-REAL_PATH.rst b/Help/release/dev/file-REAL_PATH.rst
new file mode 100644
index 0000000..32768ca
--- /dev/null
+++ b/Help/release/dev/file-REAL_PATH.rst
@@ -0,0 +1,5 @@
+file-REAL_PATH
+--------------
+
+* The :command:`file` gained sub-command `REAL_PATH` to compute a path with
+ symlinks resolved.
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index cdb1492..84639a7 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -28,6 +28,7 @@
#include "cmAlgorithms.h"
#include "cmArgumentParser.h"
+#include "cmCMakePath.h"
#include "cmCryptoHash.h"
#include "cmExecutionStatus.h"
#include "cmFSPermissions.h"
@@ -1234,6 +1235,50 @@ bool HandleInstallCommand(std::vector<std::string> const& args,
return installer.Run(args);
}
+bool HandleRealPathCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 3) {
+ status.SetError("REAL_PATH requires a path and an output variable");
+ return false;
+ }
+
+ struct Arguments
+ {
+ std::string BaseDirectory;
+ };
+ static auto const parser = cmArgumentParser<Arguments>{}.Bind(
+ "BASE_DIRECTORY"_s, &Arguments::BaseDirectory);
+
+ std::vector<std::string> unparsedArguments;
+ std::vector<std::string> keywordsMissingValue;
+ std::vector<std::string> parsedKeywords;
+ auto arguments =
+ parser.Parse(cmMakeRange(args).advance(3), &unparsedArguments,
+ &keywordsMissingValue, &parsedKeywords);
+
+ if (!unparsedArguments.empty()) {
+ status.SetError("REAL_PATH called with unexpected arguments");
+ return false;
+ }
+ if (!keywordsMissingValue.empty()) {
+ status.SetError("BASE_DIRECTORY requires a value");
+ return false;
+ }
+
+ if (parsedKeywords.empty()) {
+ arguments.BaseDirectory = status.GetMakefile().GetCurrentSourceDirectory();
+ }
+
+ cmCMakePath path(args[1]);
+ path = path.Absolute(arguments.BaseDirectory).Normal();
+ auto realPath = cmSystemTools::GetRealPath(path.GenericString());
+
+ status.GetMakefile().AddDefinition(args[2], realPath);
+
+ return true;
+}
+
bool HandleRelativePathCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
@@ -3360,6 +3405,7 @@ bool cmFileCommand(std::vector<std::string> const& args,
{ "RPATH_CHECK"_s, HandleRPathCheckCommand },
{ "RPATH_REMOVE"_s, HandleRPathRemoveCommand },
{ "READ_ELF"_s, HandleReadElfCommand },
+ { "REAL_PATH"_s, HandleRealPathCommand },
{ "RELATIVE_PATH"_s, HandleRelativePathCommand },
{ "TO_CMAKE_PATH"_s, HandleCMakePathCommand },
{ "TO_NATIVE_PATH"_s, HandleNativePathCommand },
diff --git a/Tests/RunCMake/file/REAL_PATH-no-base-dir-result.txt b/Tests/RunCMake/file/REAL_PATH-no-base-dir-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/file/REAL_PATH-no-base-dir-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/file/REAL_PATH-no-base-dir-stderr.txt b/Tests/RunCMake/file/REAL_PATH-no-base-dir-stderr.txt
new file mode 100644
index 0000000..7c58aeb
--- /dev/null
+++ b/Tests/RunCMake/file/REAL_PATH-no-base-dir-stderr.txt
@@ -0,0 +1,2 @@
+CMake Error at REAL_PATH-no-base-dir.cmake:[0-9]+ \(file\):
+ file BASE_DIRECTORY requires a value
diff --git a/Tests/RunCMake/file/REAL_PATH-no-base-dir.cmake b/Tests/RunCMake/file/REAL_PATH-no-base-dir.cmake
new file mode 100644
index 0000000..132aee6
--- /dev/null
+++ b/Tests/RunCMake/file/REAL_PATH-no-base-dir.cmake
@@ -0,0 +1,2 @@
+
+file(REAL_PATH "some-path" real_path BASE_DIRECTORY)
diff --git a/Tests/RunCMake/file/REAL_PATH-unexpected-arg-result.txt b/Tests/RunCMake/file/REAL_PATH-unexpected-arg-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/file/REAL_PATH-unexpected-arg-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/file/REAL_PATH-unexpected-arg-stderr.txt b/Tests/RunCMake/file/REAL_PATH-unexpected-arg-stderr.txt
new file mode 100644
index 0000000..301db75
--- /dev/null
+++ b/Tests/RunCMake/file/REAL_PATH-unexpected-arg-stderr.txt
@@ -0,0 +1,2 @@
+CMake Error at REAL_PATH-unexpected-arg.cmake:[0-9]+ \(file\):
+ file REAL_PATH called with unexpected arguments
diff --git a/Tests/RunCMake/file/REAL_PATH-unexpected-arg.cmake b/Tests/RunCMake/file/REAL_PATH-unexpected-arg.cmake
new file mode 100644
index 0000000..144f30b
--- /dev/null
+++ b/Tests/RunCMake/file/REAL_PATH-unexpected-arg.cmake
@@ -0,0 +1,2 @@
+
+file(REAL_PATH "some-path" real_path extra_arg)
diff --git a/Tests/RunCMake/file/REAL_PATH.cmake b/Tests/RunCMake/file/REAL_PATH.cmake
new file mode 100644
index 0000000..be25706
--- /dev/null
+++ b/Tests/RunCMake/file/REAL_PATH.cmake
@@ -0,0 +1,14 @@
+
+file(TOUCH "${CMAKE_CURRENT_BINARY_DIR}/test.txt")
+file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/test.sym")
+file(CREATE_LINK "test.txt" "${CMAKE_CURRENT_BINARY_DIR}/test.sym" SYMBOLIC)
+
+file(REAL_PATH "${CMAKE_CURRENT_BINARY_DIR}/test.sym" real_path)
+if (NOT real_path STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/test.txt")
+ message(SEND_ERROR "real path is \"${real_path}\", should be \"${CMAKE_CURRENT_BINARY_DIR}/test.txt\"")
+endif()
+
+file(REAL_PATH "test.sym" real_path BASE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+if (NOT real_path STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/test.txt")
+ message(SEND_ERROR "real path is \"${real_path}\", should be \"${CMAKE_CURRENT_BINARY_DIR}/test.txt\"")
+endif()
diff --git a/Tests/RunCMake/file/RunCMakeTest.cmake b/Tests/RunCMake/file/RunCMakeTest.cmake
index 8d84943..22813eb 100644
--- a/Tests/RunCMake/file/RunCMakeTest.cmake
+++ b/Tests/RunCMake/file/RunCMakeTest.cmake
@@ -72,6 +72,9 @@ if(NOT WIN32 OR CYGWIN)
run_cmake(READ_SYMLINK-noexist)
run_cmake(READ_SYMLINK-notsymlink)
run_cmake(INSTALL-FOLLOW_SYMLINK_CHAIN)
+ run_cmake(REAL_PATH-unexpected-arg)
+ run_cmake(REAL_PATH-no-base-dir)
+ run_cmake(REAL_PATH)
endif()
if(RunCMake_GENERATOR MATCHES "Ninja")