CMake "remove_directory" command is inconsistent on Windows
The Problem
create_symlink
and remove_directory
inconsistency
1. The CMake CMake command create_symlink
creates a symbolic link. When CMake remove_directory
command is called directly on this link it will follow the link and remove the content of the target directory.
Consider following batch script:
mkdir sample-dir
echo important data > sample-dir\data.txt
:: Create the link
cmake -E create_symlink sample-dir link-dir
:: Remove the link
cmake -E remove_directory link-dir
:: Now important data from sample-dir\data.txt is gone
dir sample-dir
:: 0 File(s) 0 bytes
But if the symlinked directory is inside the folder that is being removed then the link is not followed.
mkdir sample-dir
echo important data > sample-dir\data.txt
mkdir temporary-dir
:: Create the link
cmake -E create_symlink sample-dir temporary-dir\link-dir
:: Remove the directory with the link
cmake -E remove_directory temporary-dir
:: The important data is intact
dir sample-dir
::29/07/2019 15:43 17 data.txt
:: 1 File(s) 17 bytes
If the links created with mklink /D
the results are the same. But if instead cmake -E remove_directory
you would use rmdir /Q /S
command the links are not followed and the directories are unlinked in both cases.
2. Directory Junctions
The symbolic link problem on Windows.
CMake command create_symlink
creates the symbolic link. Which on its own is a problem - it has vulnurability. And there fore by default Windows users do not have permission to create symbolic links. They either need to have admin rights or be assigned corresponding permissions by the admin.
As an alternative Windows provide directory junctions.
remove_directory
The junctions and CMake CMake command remove_directory
being called directly on junction follows the link and removes the content of the source directory.
mkdir sample-dir
echo important data > sample-dir\data.txt
:: Create the link
mklink /J link-dir sample-dir
:: Remove the link
cmake -E remove_directory link-dir
:: Now important data from sample-dir\data.txt is gone
dir sample-dir
:: 0 File(s) 0 bytes
But if the junction is inside the folder that is being removed then CMake fails.
mkdir sample-dir
echo important data > sample-dir\data.txt
mkdir temporary-dir
:: Create the link
mklink /J temporary-dir\link-dir sample-dir
:: Remove the directory with the link
cmake -E remove_directory temporary-dir
:: CMake fails with error:
::Error removing directory "temporary-dir".
What is interesting is that the junction is unlinked now and calling cmake -E remove_directory temporary-dir
would succeed. Leaving the source folder intact.
Calling rmdir /S /Q
in both cases would result in unlinking junctions.
Proposal
Make the CMake command remove_directory
behave the same way the rmdir
behaves.
- When calling
cmake -E remove_directory
with symbolic link the symbolic link should not be followed. The link should only be removed leaving the target directory intact. - When calling
cmake -E remove_directory
with junction the junction should not be followed. The junction (and the link directory) should be removed leaving the target directory intact. - When calling
cmake -E remove_directory
with folder that contains junctions the junctions should not be followed. The junction (and the link directory) should be removed leaving the target directory intact.
P.S. The behavior was checked on CMake versions 3.14.1, 3.14.2, 3.14.3, 3.14.4, and 3.12.0