From b0423a260ccea427da5e6da85e5fd5df837e6ae7 Mon Sep 17 00:00:00 2001 From: Dominik Gschwind Date: Wed, 10 Aug 2022 16:27:14 +0200 Subject: [PATCH 1/2] Copy files instead of hard-linking on Windows Fixes an issue on Windows where when source and build directory are on different drives hard-linking to files or directory fails as it doesn't work across filesystem boundaries. Note that symlinking is also not possible because it requires administrator privileges on Windows. The solution copies the files using the built-in cmake `configure_file(src dest COPYONLY)` command. As this command only operates on files, if a directory is specified the files will be globbed recursively and through symlinks. Signed-off-by: Dominik Gschwind --- CMakeLists.txt | 35 +++++++++++-------------- ChangeLog.d/fix_hard_link_across_drives | 3 +++ 2 files changed, 18 insertions(+), 20 deletions(-) create mode 100644 ChangeLog.d/fix_hard_link_across_drives diff --git a/CMakeLists.txt b/CMakeLists.txt index e18f607be..755ac271e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,35 +137,30 @@ endif() # Create a symbolic link from ${base_name} in the binary directory # to the corresponding path in the source directory. +# Note: Copies the file(s) on Windows. function(link_to_source base_name) - # Get OS dependent path to use in `execute_process` - if (CMAKE_HOST_WIN32) - #mklink is an internal command of cmd.exe it can only work with \ - string(REPLACE "/" "\\" link "${CMAKE_CURRENT_BINARY_DIR}/${base_name}") - string(REPLACE "/" "\\" target "${CMAKE_CURRENT_SOURCE_DIR}/${base_name}") - else() - set(link "${CMAKE_CURRENT_BINARY_DIR}/${base_name}") - set(target "${CMAKE_CURRENT_SOURCE_DIR}/${base_name}") - endif() + set(link "${CMAKE_CURRENT_BINARY_DIR}/${base_name}") + set(target "${CMAKE_CURRENT_SOURCE_DIR}/${base_name}") if (NOT EXISTS ${link}) if (CMAKE_HOST_UNIX) - set(command ln -s ${target} ${link}) + execute_process(COMMAND ln -s ${target} ${link} + RESULT_VARIABLE result + ERROR_VARIABLE output) + + if (NOT ${result} EQUAL 0) + message(FATAL_ERROR "Could not create symbolic link for: ${target} --> ${output}") + endif() else() if (IS_DIRECTORY ${target}) - set(command cmd.exe /c mklink /j ${link} ${target}) + file(GLOB_RECURSE files FOLLOW_SYMLINKS LIST_DIRECTORIES false RELATIVE ${target} "${target}/*") + foreach(file IN LISTS files) + configure_file("${target}/${file}" "${link}/${file}" COPYONLY) + endforeach(file) else() - set(command cmd.exe /c mklink /h ${link} ${target}) + configure_file(${target} ${link} COPYONLY) endif() endif() - - execute_process(COMMAND ${command} - RESULT_VARIABLE result - ERROR_VARIABLE output) - - if (NOT ${result} EQUAL 0) - message(FATAL_ERROR "Could not create symbolic link for: ${target} --> ${output}") - endif() endif() endfunction(link_to_source) diff --git a/ChangeLog.d/fix_hard_link_across_drives b/ChangeLog.d/fix_hard_link_across_drives new file mode 100644 index 000000000..0c55c3038 --- /dev/null +++ b/ChangeLog.d/fix_hard_link_across_drives @@ -0,0 +1,3 @@ +Bugfix + * Fix a build issue on Windows where the source and build directory could not be on + different drives (#5751). From 29cf15dfbcd1091fd44bcc12ebd659866ac5de91 Mon Sep 17 00:00:00 2001 From: David Horstmann Date: Thu, 8 Dec 2022 12:12:37 +0100 Subject: [PATCH 2/2] Improve CMake backward compatibility Use code with clear behavior in CMake 2.8.12 (which we try to support in Mbed TLS 2.28, although that's mostly for the sake of RHEL, not Windows). The code in the previous commit relied on features introduced in CMake 3.x, although it worked as desired by accident because `LIST_DIRECTORIES false` was effectively ignored and `configure_file` on a directory had no harmful effect. Signed-off-by: Gilles Peskine Signed-off-by: David Horstmann --- CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 755ac271e..72cc737c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,9 +153,11 @@ function(link_to_source base_name) endif() else() if (IS_DIRECTORY ${target}) - file(GLOB_RECURSE files FOLLOW_SYMLINKS LIST_DIRECTORIES false RELATIVE ${target} "${target}/*") + file(GLOB_RECURSE files FOLLOW_SYMLINKS RELATIVE ${target} "${target}/*") foreach(file IN LISTS files) - configure_file("${target}/${file}" "${link}/${file}" COPYONLY) + if(NOT IS_DIRECTORY "${target}/${file}") + configure_file("${target}/${file}" "${link}/${file}" COPYONLY) + endif() endforeach(file) else() configure_file(${target} ${link} COPYONLY)