summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/manual/cmake.1.rst5
-rw-r--r--Help/release/dev/create_symlink-windows.rst5
-rw-r--r--Source/cmSystemTools.cxx25
-rw-r--r--Source/cmSystemTools.h5
-rw-r--r--Source/cmcmd.cxx7
-rw-r--r--Tests/RunCMake/CommandLine/E_create_symlink-broken-create-check.cmake14
-rw-r--r--Tests/RunCMake/CommandLine/E_create_symlink-broken-replace-check.cmake8
-rw-r--r--Tests/RunCMake/CommandLine/RunCMakeTest.cmake51
8 files changed, 76 insertions, 44 deletions
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index 9fe0c0b..b11526c 100644
--- a/Help/manual/cmake.1.rst
+++ b/Help/manual/cmake.1.rst
@@ -354,11 +354,6 @@ Available commands are:
Touch a file if it exists but do not create it. If a file does
not exist it will be silently ignored.
-UNIX-specific Command-Line Tools
---------------------------------
-
-The following ``cmake -E`` commands are available only on UNIX:
-
``create_symlink <old> <new>``
Create a symbolic link ``<new>`` naming ``<old>``.
diff --git a/Help/release/dev/create_symlink-windows.rst b/Help/release/dev/create_symlink-windows.rst
new file mode 100644
index 0000000..e3ea491
--- /dev/null
+++ b/Help/release/dev/create_symlink-windows.rst
@@ -0,0 +1,5 @@
+create_symlink-windows
+-------------------------
+
+* The :manual:`cmake(1)` ``-E create_symlink`` command can now be used
+ on Windows.
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 79e5ccf..8339aac 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -6,6 +6,7 @@
#include "cmDuration.h"
#include "cmProcessOutput.h"
#include "cm_sys_stat.h"
+#include "cm_uv.h"
#if defined(CMAKE_BUILD_WITH_CMAKE)
# include "cmArchiveWrite.h"
@@ -55,8 +56,6 @@
# include <wincrypt.h>
# include <fcntl.h> /* _O_TEXT */
-
-# include "cm_uv.h"
#else
# include <sys/time.h>
# include <unistd.h>
@@ -2988,3 +2987,25 @@ bool cmSystemTools::StringToULong(const char* str, unsigned long* value)
*value = strtoul(str, &endp, 10);
return (*endp == '\0') && (endp != str) && (errno == 0);
}
+
+bool cmSystemTools::CreateSymlink(const std::string& origName,
+ const std::string& newName)
+{
+ uv_fs_t req;
+ int flags = 0;
+#if defined(_WIN32)
+ if (cmsys::SystemTools::FileIsDirectory(origName)) {
+ flags |= UV_FS_SYMLINK_DIR;
+ }
+#endif
+ int err = uv_fs_symlink(nullptr, &req, origName.c_str(), newName.c_str(),
+ flags, nullptr);
+ if (err) {
+ std::string e =
+ "failed to create symbolic link '" + newName + "': " + uv_strerror(err);
+ cmSystemTools::Error(e.c_str());
+ return false;
+ }
+
+ return true;
+}
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 5c383ee..98300eb 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -513,6 +513,11 @@ public:
/** Perform one-time initialization of libuv. */
static void InitializeLibUV();
+ /** Create a symbolic link if the platform supports it. Returns whether
+ creation succeeded. */
+ static bool CreateSymlink(const std::string& origName,
+ const std::string& newName);
+
private:
static bool s_ForceUnixPaths;
static bool s_RunCommandHideConsole;
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 87da108..1d2f741 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -108,6 +108,7 @@ void CMakeCommandUsage(const char* program)
<< " time command [args...] - run command and display elapsed time\n"
<< " touch file - touch a file.\n"
<< " touch_nocreate file - touch a file but do not create it.\n"
+ << " create_symlink old new - create a symbolic link new -> old\n"
#if defined(_WIN32) && !defined(__CYGWIN__)
<< "Available on Windows only:\n"
<< " delete_regv key - delete registry value\n"
@@ -116,9 +117,6 @@ void CMakeCommandUsage(const char* program)
<< " env_vs9_wince sdkname - displays a batch file which sets the "
"environment for the provided Windows CE SDK installed in VS2008\n"
<< " write_regv key value - write registry value\n"
-#else
- << "Available on UNIX only:\n"
- << " create_symlink old new - create a symbolic link new -> old\n"
#endif
;
/* clang-format on */
@@ -868,9 +866,6 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
return 1;
}
if (!cmSystemTools::CreateSymlink(args[2], args[3])) {
- std::string emsg = cmSystemTools::GetLastSystemError();
- std::cerr << "failed to create symbolic link '" << destinationFileName
- << "': " << emsg << "\n";
return 1;
}
return 0;
diff --git a/Tests/RunCMake/CommandLine/E_create_symlink-broken-create-check.cmake b/Tests/RunCMake/CommandLine/E_create_symlink-broken-create-check.cmake
index d7e652d..5df5f2f 100644
--- a/Tests/RunCMake/CommandLine/E_create_symlink-broken-create-check.cmake
+++ b/Tests/RunCMake/CommandLine/E_create_symlink-broken-create-check.cmake
@@ -1,6 +1,10 @@
-if(NOT IS_SYMLINK ${RunCMake_TEST_BINARY_DIR}/L)
- set(RunCMake_TEST_FAILED "Symlink 'L' incorrectly not created!")
-endif()
-if(EXISTS ${RunCMake_TEST_BINARY_DIR}/L)
- set(RunCMake_TEST_FAILED "Symlink 'L' not broken!")
+if(${actual_stderr_var} MATCHES "operation not permitted")
+ unset(msg)
+else()
+ if(NOT IS_SYMLINK ${RunCMake_TEST_BINARY_DIR}/L)
+ set(RunCMake_TEST_FAILED "Symlink 'L' incorrectly not created!")
+ endif()
+ if(EXISTS ${RunCMake_TEST_BINARY_DIR}/L)
+ set(RunCMake_TEST_FAILED "Symlink 'L' not broken!")
+ endif()
endif()
diff --git a/Tests/RunCMake/CommandLine/E_create_symlink-broken-replace-check.cmake b/Tests/RunCMake/CommandLine/E_create_symlink-broken-replace-check.cmake
index c078ae8..d37df01 100644
--- a/Tests/RunCMake/CommandLine/E_create_symlink-broken-replace-check.cmake
+++ b/Tests/RunCMake/CommandLine/E_create_symlink-broken-replace-check.cmake
@@ -1,3 +1,7 @@
-if(NOT IS_DIRECTORY ${RunCMake_TEST_BINARY_DIR}/L)
- set(RunCMake_TEST_FAILED "Symlink 'L' not replaced correctly!")
+if(${actual_stderr_var} MATCHES "operation not permitted")
+ unset(msg)
+else()
+ if(NOT IS_DIRECTORY ${RunCMake_TEST_BINARY_DIR}/L)
+ set(RunCMake_TEST_FAILED "Symlink 'L' not replaced correctly!")
+ endif()
endif()
diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
index e332336..9859df1 100644
--- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
@@ -127,32 +127,35 @@ if(RunCMake_GENERATOR STREQUAL "Ninja")
unset(RunCMake_TEST_NO_CLEAN)
endif()
-if(UNIX)
- run_cmake_command(E_create_symlink-no-arg
- ${CMAKE_COMMAND} -E create_symlink
- )
- run_cmake_command(E_create_symlink-missing-dir
- ${CMAKE_COMMAND} -E create_symlink T missing-dir/L
- )
+run_cmake_command(E_create_symlink-no-arg
+ ${CMAKE_COMMAND} -E create_symlink
+ )
+run_cmake_command(E_create_symlink-missing-dir
+ ${CMAKE_COMMAND} -E create_symlink T missing-dir/L
+ )
- # Use a single build tree for a few tests without cleaning.
- set(RunCMake_TEST_BINARY_DIR
- ${RunCMake_BINARY_DIR}/E_create_symlink-broken-build)
- set(RunCMake_TEST_NO_CLEAN 1)
- file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
- run_cmake_command(E_create_symlink-broken-create
- ${CMAKE_COMMAND} -E create_symlink T L
- )
- run_cmake_command(E_create_symlink-broken-replace
- ${CMAKE_COMMAND} -E create_symlink . L
- )
- unset(RunCMake_TEST_BINARY_DIR)
- unset(RunCMake_TEST_NO_CLEAN)
+# Use a single build tree for a few tests without cleaning.
+# These tests are special on Windows since it will only fail if the user
+# running the test does not have the priveldge to create symlinks. If this
+# happens we clear the msg in the -check.cmake and say that the test passes
+set(RunCMake_DEFAULT_stderr "(operation not permitted)?")
+set(RunCMake_TEST_BINARY_DIR
+ ${RunCMake_BINARY_DIR}/E_create_symlink-broken-build)
+set(RunCMake_TEST_NO_CLEAN 1)
+file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+run_cmake_command(E_create_symlink-broken-create
+ ${CMAKE_COMMAND} -E create_symlink T L
+ )
+run_cmake_command(E_create_symlink-broken-replace
+ ${CMAKE_COMMAND} -E create_symlink . L
+ )
+unset(RunCMake_TEST_BINARY_DIR)
+unset(RunCMake_TEST_NO_CLEAN)
+unset(RunCMake_DEFAULT_stderr)
- run_cmake_command(E_create_symlink-no-replace-dir
- ${CMAKE_COMMAND} -E create_symlink T .
- )
-endif()
+run_cmake_command(E_create_symlink-no-replace-dir
+ ${CMAKE_COMMAND} -E create_symlink T .
+ )
set(in ${RunCMake_SOURCE_DIR}/copy_input)
set(out ${RunCMake_BINARY_DIR}/copy_output)