mirror of
https://github.com/reactos/CMake.git
synced 2025-02-04 02:47:29 +00:00
cmake: Add '-E create_symlink' support on Windows
The allows `-E create_symlink` to work on Windows. It utilizes `uv_fs_symlink`. I am still unsure exactly which Windows platforms will work without requiring Administrator privileges or needing a user/group with the "Create Symbolic Links" User Rights. It does work with my Windows 10 Pro with Developer Mode turned on. In the test suite check that the symlink either worked or failed with a permissions error. Use recent changes in cmSystemTools::FileExists to check that a symlink is broken.
This commit is contained in:
parent
49cb2a504d
commit
afb7f6e4ff
@ -353,11 +353,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>``.
|
||||
|
||||
|
5
Help/release/dev/create_symlink-windows.rst
Normal file
5
Help/release/dev/create_symlink-windows.rst
Normal file
@ -0,0 +1,5 @@
|
||||
create_symlink-windows
|
||||
-------------------------
|
||||
|
||||
* The :manual:`cmake(1)` ``-E create_symlink`` command can now be used
|
||||
on Windows.
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -102,32 +102,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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user