From 81650e488c734702384ef903630838015a3f81b1 Mon Sep 17 00:00:00 2001 From: Tushar Maheshwari Date: Thu, 27 Dec 2018 17:28:30 +0530 Subject: cmFileCommand: Add CREATE_LINK subcommand This brings the functionality of `cmake -E create_symlink` and more to scripts. The default behavior is to create hard links. The `SYMBOLIC` argument can be used to create symlinks instead. The `COPY_ON_ERROR` argument enables a fallback to copying the file in case the link fails. The `RESULT ` retrieves the error message generated by the system. It is set to "0" on success. Fixes: #16926 --- Source/cmFileCommand.cxx | 121 +++++++++++++++++++++++++++++++++++++++++++++++ Source/cmFileCommand.h | 1 + Source/cmSystemTools.cxx | 16 +++++++ Source/cmSystemTools.h | 5 ++ 4 files changed, 143 insertions(+) diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index db2fde8..2cdf827 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -185,6 +185,9 @@ bool cmFileCommand::InitialPass(std::vector const& args, if (subCommand == "READ_SYMLINK") { return this->HandleReadSymlinkCommand(args); } + if (subCommand == "CREATE_LINK") { + return this->HandleCreateLinkCommand(args); + } std::string e = "does not recognize sub-command " + subCommand; this->SetError(e); @@ -3670,3 +3673,121 @@ bool cmFileCommand::HandleReadSymlinkCommand( return true; } + +bool cmFileCommand::HandleCreateLinkCommand( + std::vector const& args) +{ + if (args.size() < 3) { + this->SetError("CREATE_LINK must be called with at least two additional " + "arguments"); + return false; + } + + cmCommandArgumentsHelper argHelper; + cmCommandArgumentGroup group; + + cmCAString linkArg(&argHelper, "CREATE_LINK"); + cmCAString fileArg(&argHelper, nullptr); + cmCAString newFileArg(&argHelper, nullptr); + + cmCAString resultArg(&argHelper, "RESULT", &group); + cmCAEnabler copyOnErrorArg(&argHelper, "COPY_ON_ERROR", &group); + cmCAEnabler symbolicArg(&argHelper, "SYMBOLIC", &group); + + linkArg.Follows(nullptr); + fileArg.Follows(&linkArg); + newFileArg.Follows(&fileArg); + group.Follows(&newFileArg); + + std::vector unconsumedArgs; + argHelper.Parse(&args, &unconsumedArgs); + + if (!unconsumedArgs.empty()) { + this->SetError("unknown argument: \"" + unconsumedArgs.front() + '\"'); + return false; + } + + std::string fileName = fileArg.GetString(); + std::string newFileName = newFileArg.GetString(); + + // Output variable for storing the result. + const std::string& resultVar = resultArg.GetString(); + + // The system error message generated in the operation. + std::string result; + + // Check if the paths are distinct. + if (fileName == newFileName) { + result = "CREATE_LINK cannot use same file and newfile"; + if (!resultVar.empty()) { + this->Makefile->AddDefinition(resultVar, result.c_str()); + return true; + } + this->SetError(result); + return false; + } + + // Hard link requires original file to exist. + if (!symbolicArg.IsEnabled() && !cmSystemTools::FileExists(fileName)) { + result = "Cannot hard link \'" + fileName + "\' as it does not exist."; + if (!resultVar.empty()) { + this->Makefile->AddDefinition(resultVar, result.c_str()); + return true; + } + this->SetError(result); + return false; + } + + // Check if the new file already exists and remove it. + if ((cmSystemTools::FileExists(newFileName) || + cmSystemTools::FileIsSymlink(newFileName)) && + !cmSystemTools::RemoveFile(newFileName)) { + std::ostringstream e; + e << "Failed to create link '" << newFileName + << "' because existing path cannot be removed: " + << cmSystemTools::GetLastSystemError() << "\n"; + + if (!resultVar.empty()) { + this->Makefile->AddDefinition(resultVar, e.str().c_str()); + return true; + } + this->SetError(e.str()); + return false; + } + + // Whether the operation completed successfully. + bool completed = false; + + // Check if the command requires a symbolic link. + if (symbolicArg.IsEnabled()) { + completed = cmSystemTools::CreateSymlink(fileName, newFileName); + } else { + completed = cmSystemTools::CreateLink(fileName, newFileName); + } + + if (!completed) { + // The link method did not succeed. Get the error message. + result = "Link failed: " + cmSystemTools::GetLastSystemError(); + + // Check if copy-on-error is enabled in the arguments. + if (copyOnErrorArg.IsEnabled()) { + completed = + cmSystemTools::cmCopyFile(fileName.c_str(), newFileName.c_str()); + if (!completed) { + result = "Copy failed: " + cmSystemTools::GetLastSystemError(); + } + } + } + + // Check if the operation was successful. + if (completed) { + result = "0"; + } + + if (!resultVar.empty()) { + this->Makefile->AddDefinition(resultVar, result.c_str()); + return true; + } + + return completed; +} diff --git a/Source/cmFileCommand.h b/Source/cmFileCommand.h index fe05c98..12c5115 100644 --- a/Source/cmFileCommand.h +++ b/Source/cmFileCommand.h @@ -61,6 +61,7 @@ protected: bool HandleLockCommand(std::vector const& args); bool HandleSizeCommand(std::vector const& args); bool HandleReadSymlinkCommand(std::vector const& args); + bool HandleCreateLinkCommand(std::vector const& args); private: void AddEvaluationFile(const std::string& inputName, diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index be65853..a1c8c03 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -3134,3 +3134,19 @@ bool cmSystemTools::CreateSymlink(const std::string& origName, return true; } + +bool cmSystemTools::CreateLink(const std::string& origName, + const std::string& newName) +{ + uv_fs_t req; + int err = + uv_fs_link(nullptr, &req, origName.c_str(), newName.c_str(), nullptr); + if (err) { + std::string e = + "failed to create 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 c0999e7..15f27e5 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -530,6 +530,11 @@ public: static bool CreateSymlink(const std::string& origName, const std::string& newName); + /** Create a hard link if the platform supports it. Returns whether + creation succeeded. */ + static bool CreateLink(const std::string& origName, + const std::string& newName); + private: static bool s_ForceUnixPaths; static bool s_RunCommandHideConsole; -- cgit v0.12 From 8bb7562f1a4e75fa5cd00f4ebd868d1494b63e7a Mon Sep 17 00:00:00 2001 From: Tushar Maheshwari Date: Thu, 27 Dec 2018 20:59:51 +0530 Subject: Help: Add documentation for file(CREATE_LINK) subcommand --- Help/command/file.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Help/command/file.rst b/Help/command/file.rst index 6e2a6dd..db4d6fc 100644 --- a/Help/command/file.rst +++ b/Help/command/file.rst @@ -27,6 +27,7 @@ Synopsis file({`COPY`_ | `INSTALL`_} ... DESTINATION [...]) file(`SIZE`_ ) file(`READ_SYMLINK`_ ) + file(`CREATE_LINK`_ [...]) `Path Conversion`_ file(`RELATIVE_PATH`_ ) @@ -368,6 +369,28 @@ could do something like this: set(result "${dir}/${result}") endif() +.. _CREATE_LINK: + +.. code-block:: cmake + + file(CREATE_LINK + [RESULT ] [COPY_ON_ERROR] [SYMBOLIC]) + +Create a link to ```` at ````. + +It is a hard link by default. This can be changed to symbolic links by +using ``SYMBOLIC``. The original file needs to exist for hard links. + +The ```` variable, if specified, gets the status of the operation. +It is set to ``0`` in case of success. Otherwise, it contains the error +generated. In case of failures, if ``RESULT`` is not specified, a fatal error +is emitted. + +Specifying ``COPY_ON_ERROR`` enables copying the file as a fallback if +creating the link fails. + +Overwrites the ```` if it exists. + Path Conversion ^^^^^^^^^^^^^^^ -- cgit v0.12 From 45aa9c65a13105ff505e18f5029ef794b7aef9ab Mon Sep 17 00:00:00 2001 From: Tushar Maheshwari Date: Thu, 27 Dec 2018 21:36:31 +0530 Subject: Tests: file CREATE_LINK subcommand test cases --- Tests/RunCMake/file/CREATE_LINK-noexist-stderr.txt | 1 + Tests/RunCMake/file/CREATE_LINK-noexist.cmake | 9 +++++++++ Tests/RunCMake/file/CREATE_LINK.cmake | 9 +++++++++ Tests/RunCMake/file/RunCMakeTest.cmake | 2 ++ 4 files changed, 21 insertions(+) create mode 100644 Tests/RunCMake/file/CREATE_LINK-noexist-stderr.txt create mode 100644 Tests/RunCMake/file/CREATE_LINK-noexist.cmake create mode 100644 Tests/RunCMake/file/CREATE_LINK.cmake diff --git a/Tests/RunCMake/file/CREATE_LINK-noexist-stderr.txt b/Tests/RunCMake/file/CREATE_LINK-noexist-stderr.txt new file mode 100644 index 0000000..97eee4f --- /dev/null +++ b/Tests/RunCMake/file/CREATE_LINK-noexist-stderr.txt @@ -0,0 +1 @@ +Hard link error: Cannot hard link 'does_not_exist.txt' as it does not exist. diff --git a/Tests/RunCMake/file/CREATE_LINK-noexist.cmake b/Tests/RunCMake/file/CREATE_LINK-noexist.cmake new file mode 100644 index 0000000..1c4dc12 --- /dev/null +++ b/Tests/RunCMake/file/CREATE_LINK-noexist.cmake @@ -0,0 +1,9 @@ +file(CREATE_LINK does_not_exist.txt TestLink.txt RESULT result) +if(NOT result STREQUAL "0") + message("Hard link error: ${result}") +endif() + +file(CREATE_LINK does_not_exist.txt TestSymLink.txt RESULT sym_result SYMBOLIC) +if(NOT sym_result STREQUAL "0") + message("Symlink fail: ${sym_result}") +endif() diff --git a/Tests/RunCMake/file/CREATE_LINK.cmake b/Tests/RunCMake/file/CREATE_LINK.cmake new file mode 100644 index 0000000..1d65b69 --- /dev/null +++ b/Tests/RunCMake/file/CREATE_LINK.cmake @@ -0,0 +1,9 @@ +file(CREATE_LINK ${CMAKE_CURRENT_LIST_FILE} TestLink.cmake RESULT result) +if(NOT result STREQUAL "0") + message(SEND_ERROR "Hard link result='${result}'") +endif() + +file(CREATE_LINK ${CMAKE_CURRENT_LIST_FILE} TestSymLink.cmake RESULT sym_result SYMBOLIC) +if(NOT sym_result STREQUAL "0") + message(SEND_ERROR "Symlink result='${sym_result}'") +endif() diff --git a/Tests/RunCMake/file/RunCMakeTest.cmake b/Tests/RunCMake/file/RunCMakeTest.cmake index b872824..0962c17 100644 --- a/Tests/RunCMake/file/RunCMakeTest.cmake +++ b/Tests/RunCMake/file/RunCMakeTest.cmake @@ -1,5 +1,7 @@ include(RunCMake) +run_cmake(CREATE_LINK) +run_cmake(CREATE_LINK-noexist) run_cmake(DOWNLOAD-hash-mismatch) run_cmake(DOWNLOAD-unused-argument) run_cmake(DOWNLOAD-httpheader-not-set) -- cgit v0.12 From e68ea269d72773e53db0c6c6848f6f69f3fd7329 Mon Sep 17 00:00:00 2001 From: Tushar Maheshwari Date: Thu, 27 Dec 2018 22:05:32 +0530 Subject: Tests: CREATE_LINK subcommand negative test case --- Tests/RunCMake/file/CREATE_LINK-noarg-result.txt | 1 + Tests/RunCMake/file/CREATE_LINK-noarg-stderr.txt | 4 ++++ Tests/RunCMake/file/CREATE_LINK-noarg.cmake | 1 + Tests/RunCMake/file/RunCMakeTest.cmake | 1 + 4 files changed, 7 insertions(+) create mode 100644 Tests/RunCMake/file/CREATE_LINK-noarg-result.txt create mode 100644 Tests/RunCMake/file/CREATE_LINK-noarg-stderr.txt create mode 100644 Tests/RunCMake/file/CREATE_LINK-noarg.cmake diff --git a/Tests/RunCMake/file/CREATE_LINK-noarg-result.txt b/Tests/RunCMake/file/CREATE_LINK-noarg-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/file/CREATE_LINK-noarg-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/file/CREATE_LINK-noarg-stderr.txt b/Tests/RunCMake/file/CREATE_LINK-noarg-stderr.txt new file mode 100644 index 0000000..12494f8 --- /dev/null +++ b/Tests/RunCMake/file/CREATE_LINK-noarg-stderr.txt @@ -0,0 +1,4 @@ +CMake Error at CREATE_LINK-noarg\.cmake:[0-9]+ \(file\): + file CREATE_LINK must be called with at least two additional arguments +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/file/CREATE_LINK-noarg.cmake b/Tests/RunCMake/file/CREATE_LINK-noarg.cmake new file mode 100644 index 0000000..65002fa --- /dev/null +++ b/Tests/RunCMake/file/CREATE_LINK-noarg.cmake @@ -0,0 +1 @@ +file(CREATE_LINK ${CMAKE_CURRENT_LIST_FILE}) diff --git a/Tests/RunCMake/file/RunCMakeTest.cmake b/Tests/RunCMake/file/RunCMakeTest.cmake index 0962c17..4259680 100644 --- a/Tests/RunCMake/file/RunCMakeTest.cmake +++ b/Tests/RunCMake/file/RunCMakeTest.cmake @@ -1,6 +1,7 @@ include(RunCMake) run_cmake(CREATE_LINK) +run_cmake(CREATE_LINK-noarg) run_cmake(CREATE_LINK-noexist) run_cmake(DOWNLOAD-hash-mismatch) run_cmake(DOWNLOAD-unused-argument) -- cgit v0.12 From 9a3d85cfc501fe3c1655e4a6ae9fd08fd9a1fbb7 Mon Sep 17 00:00:00 2001 From: Tushar Maheshwari Date: Fri, 11 Jan 2019 18:37:05 +0530 Subject: Tests: Skip symlink tests on Windows --- Tests/RunCMake/file/CREATE_LINK-SYMBOLIC-noexist.cmake | 4 ++++ Tests/RunCMake/file/CREATE_LINK-SYMBOLIC.cmake | 4 ++++ Tests/RunCMake/file/CREATE_LINK-noexist.cmake | 5 ----- Tests/RunCMake/file/CREATE_LINK.cmake | 5 ----- Tests/RunCMake/file/RunCMakeTest.cmake | 2 ++ 5 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 Tests/RunCMake/file/CREATE_LINK-SYMBOLIC-noexist.cmake create mode 100644 Tests/RunCMake/file/CREATE_LINK-SYMBOLIC.cmake diff --git a/Tests/RunCMake/file/CREATE_LINK-SYMBOLIC-noexist.cmake b/Tests/RunCMake/file/CREATE_LINK-SYMBOLIC-noexist.cmake new file mode 100644 index 0000000..61aaf38 --- /dev/null +++ b/Tests/RunCMake/file/CREATE_LINK-SYMBOLIC-noexist.cmake @@ -0,0 +1,4 @@ +file(CREATE_LINK does_not_exist.txt TestSymLink.txt RESULT sym_result SYMBOLIC) +if(NOT sym_result STREQUAL "0") + message("Symlink fail: ${sym_result}") +endif() diff --git a/Tests/RunCMake/file/CREATE_LINK-SYMBOLIC.cmake b/Tests/RunCMake/file/CREATE_LINK-SYMBOLIC.cmake new file mode 100644 index 0000000..77b899c --- /dev/null +++ b/Tests/RunCMake/file/CREATE_LINK-SYMBOLIC.cmake @@ -0,0 +1,4 @@ +file(CREATE_LINK ${CMAKE_CURRENT_LIST_FILE} TestSymLink.cmake RESULT sym_result SYMBOLIC) +if(NOT sym_result STREQUAL "0") + message(SEND_ERROR "Symlink result='${sym_result}'") +endif() diff --git a/Tests/RunCMake/file/CREATE_LINK-noexist.cmake b/Tests/RunCMake/file/CREATE_LINK-noexist.cmake index 1c4dc12..5ee2580 100644 --- a/Tests/RunCMake/file/CREATE_LINK-noexist.cmake +++ b/Tests/RunCMake/file/CREATE_LINK-noexist.cmake @@ -2,8 +2,3 @@ file(CREATE_LINK does_not_exist.txt TestLink.txt RESULT result) if(NOT result STREQUAL "0") message("Hard link error: ${result}") endif() - -file(CREATE_LINK does_not_exist.txt TestSymLink.txt RESULT sym_result SYMBOLIC) -if(NOT sym_result STREQUAL "0") - message("Symlink fail: ${sym_result}") -endif() diff --git a/Tests/RunCMake/file/CREATE_LINK.cmake b/Tests/RunCMake/file/CREATE_LINK.cmake index 1d65b69..b7c090e 100644 --- a/Tests/RunCMake/file/CREATE_LINK.cmake +++ b/Tests/RunCMake/file/CREATE_LINK.cmake @@ -2,8 +2,3 @@ file(CREATE_LINK ${CMAKE_CURRENT_LIST_FILE} TestLink.cmake RESULT result) if(NOT result STREQUAL "0") message(SEND_ERROR "Hard link result='${result}'") endif() - -file(CREATE_LINK ${CMAKE_CURRENT_LIST_FILE} TestSymLink.cmake RESULT sym_result SYMBOLIC) -if(NOT sym_result STREQUAL "0") - message(SEND_ERROR "Symlink result='${sym_result}'") -endif() diff --git a/Tests/RunCMake/file/RunCMakeTest.cmake b/Tests/RunCMake/file/RunCMakeTest.cmake index 4259680..bbabddd 100644 --- a/Tests/RunCMake/file/RunCMakeTest.cmake +++ b/Tests/RunCMake/file/RunCMakeTest.cmake @@ -56,6 +56,8 @@ run_cmake_command(GLOB-error-CONFIGURE_DEPENDS-SCRIPT_MODE ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/GLOB-error-CONFIGURE_DEPENDS-SCRIPT_MODE.cmake) if(NOT WIN32 OR CYGWIN) + run_cmake(CREATE_LINK-SYMBOLIC) + run_cmake(CREATE_LINK-SYMBOLIC-noexist) run_cmake(GLOB_RECURSE-cyclic-recursion) run_cmake(INSTALL-SYMLINK) run_cmake(READ_SYMLINK) -- cgit v0.12 From 593d986470ce1938436da312e0c93e3c9c07017e Mon Sep 17 00:00:00 2001 From: Tushar Maheshwari Date: Sun, 13 Jan 2019 21:05:58 +0530 Subject: Tests: Avoid cross-device links in CREATE_LINK test Add a test for COPY_ON_ERROR to cover that scenario. --- Tests/RunCMake/file/CREATE_LINK-COPY_ON_ERROR.cmake | 11 +++++++++++ Tests/RunCMake/file/CREATE_LINK.cmake | 9 ++++++++- Tests/RunCMake/file/RunCMakeTest.cmake | 1 + 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 Tests/RunCMake/file/CREATE_LINK-COPY_ON_ERROR.cmake diff --git a/Tests/RunCMake/file/CREATE_LINK-COPY_ON_ERROR.cmake b/Tests/RunCMake/file/CREATE_LINK-COPY_ON_ERROR.cmake new file mode 100644 index 0000000..777ef4e --- /dev/null +++ b/Tests/RunCMake/file/CREATE_LINK-COPY_ON_ERROR.cmake @@ -0,0 +1,11 @@ +# Use COPY_ON_ERROR to handle the case where the source and destination +# directory are on different devices. Cross-device links are not permitted +# and the following command falls back to copying the file if link fails. +file(CREATE_LINK + ${CMAKE_CURRENT_LIST_FILE} TestCreateLink.cmake + RESULT result + COPY_ON_ERROR + ) +if(NOT result STREQUAL "0") + message(SEND_ERROR "COPY_ON_ERROR failed: '${result}'") +endif() diff --git a/Tests/RunCMake/file/CREATE_LINK.cmake b/Tests/RunCMake/file/CREATE_LINK.cmake index b7c090e..ca61646 100644 --- a/Tests/RunCMake/file/CREATE_LINK.cmake +++ b/Tests/RunCMake/file/CREATE_LINK.cmake @@ -1,4 +1,11 @@ -file(CREATE_LINK ${CMAKE_CURRENT_LIST_FILE} TestLink.cmake RESULT result) +# start with a file in the same directory to avoid cross-device links +set(test_file ${CMAKE_CURRENT_BINARY_DIR}/CreateLinkTest.txt) +file(TOUCH ${test_file}) + +file(CREATE_LINK + ${test_file} ${CMAKE_CURRENT_BINARY_DIR}/TestCreateLink.txt + RESULT result + ) if(NOT result STREQUAL "0") message(SEND_ERROR "Hard link result='${result}'") endif() diff --git a/Tests/RunCMake/file/RunCMakeTest.cmake b/Tests/RunCMake/file/RunCMakeTest.cmake index bbabddd..128e8f3 100644 --- a/Tests/RunCMake/file/RunCMakeTest.cmake +++ b/Tests/RunCMake/file/RunCMakeTest.cmake @@ -1,6 +1,7 @@ include(RunCMake) run_cmake(CREATE_LINK) +run_cmake(CREATE_LINK-COPY_ON_ERROR) run_cmake(CREATE_LINK-noarg) run_cmake(CREATE_LINK-noexist) run_cmake(DOWNLOAD-hash-mismatch) -- cgit v0.12 From 0f08ed89362d207e18b06e806f127cd683b79141 Mon Sep 17 00:00:00 2001 From: Tushar Maheshwari Date: Tue, 15 Jan 2019 20:34:46 +0530 Subject: cmSystemTools: Silence CreateLink and CreateSymlink errors If provided, report errors to a std::string. This allows "silent" fallback to another flow, like COPY_ON_ERROR. --- Source/cmFileCommand.cxx | 28 +++++++++++++--------------- Source/cmSystemTools.cxx | 18 ++++++++++++++---- Source/cmSystemTools.h | 6 ++++-- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 2cdf827..999af54 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -3760,34 +3760,32 @@ bool cmFileCommand::HandleCreateLinkCommand( // Check if the command requires a symbolic link. if (symbolicArg.IsEnabled()) { - completed = cmSystemTools::CreateSymlink(fileName, newFileName); + completed = cmSystemTools::CreateSymlink(fileName, newFileName, &result); } else { - completed = cmSystemTools::CreateLink(fileName, newFileName); + completed = cmSystemTools::CreateLink(fileName, newFileName, &result); } - if (!completed) { - // The link method did not succeed. Get the error message. - result = "Link failed: " + cmSystemTools::GetLastSystemError(); - - // Check if copy-on-error is enabled in the arguments. - if (copyOnErrorArg.IsEnabled()) { - completed = - cmSystemTools::cmCopyFile(fileName.c_str(), newFileName.c_str()); - if (!completed) { - result = "Copy failed: " + cmSystemTools::GetLastSystemError(); - } + // Check if copy-on-error is enabled in the arguments. + if (!completed && copyOnErrorArg.IsEnabled()) { + completed = + cmSystemTools::cmCopyFile(fileName.c_str(), newFileName.c_str()); + if (!completed) { + result = "Copy failed: " + cmSystemTools::GetLastSystemError(); } } // Check if the operation was successful. if (completed) { result = "0"; + } else if (resultVar.empty()) { + // The operation failed and the result is not reported in a variable. + this->SetError(result); + return false; } if (!resultVar.empty()) { this->Makefile->AddDefinition(resultVar, result.c_str()); - return true; } - return completed; + return true; } diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index a1c8c03..52957c1 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -3114,7 +3114,8 @@ std::string cmSystemTools::EncodeURL(std::string const& in, bool escapeSlashes) } bool cmSystemTools::CreateSymlink(const std::string& origName, - const std::string& newName) + const std::string& newName, + std::string* errorMessage) { uv_fs_t req; int flags = 0; @@ -3128,7 +3129,11 @@ bool cmSystemTools::CreateSymlink(const std::string& origName, if (err) { std::string e = "failed to create symbolic link '" + newName + "': " + uv_strerror(err); - cmSystemTools::Error(e.c_str()); + if (errorMessage) { + *errorMessage = std::move(e); + } else { + cmSystemTools::Error(e.c_str()); + } return false; } @@ -3136,7 +3141,8 @@ bool cmSystemTools::CreateSymlink(const std::string& origName, } bool cmSystemTools::CreateLink(const std::string& origName, - const std::string& newName) + const std::string& newName, + std::string* errorMessage) { uv_fs_t req; int err = @@ -3144,7 +3150,11 @@ bool cmSystemTools::CreateLink(const std::string& origName, if (err) { std::string e = "failed to create link '" + newName + "': " + uv_strerror(err); - cmSystemTools::Error(e.c_str()); + if (errorMessage) { + *errorMessage = std::move(e); + } else { + cmSystemTools::Error(e.c_str()); + } return false; } diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 15f27e5..489811d 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -528,12 +528,14 @@ public: /** Create a symbolic link if the platform supports it. Returns whether creation succeeded. */ static bool CreateSymlink(const std::string& origName, - const std::string& newName); + const std::string& newName, + std::string* errorMessage = nullptr); /** Create a hard link if the platform supports it. Returns whether creation succeeded. */ static bool CreateLink(const std::string& origName, - const std::string& newName); + const std::string& newName, + std::string* errorMessage = nullptr); private: static bool s_ForceUnixPaths; -- cgit v0.12