file(GENERATE): Issue when resolving relative path of a file which contains more than one slash in a row.
When generating files with full path containing more than one "/"(slashes} in a row in the path, it causes re-configuration of the project upon each build phase, despite the fact that build tree/sources have not been updated.
The issue is caused by the fact that the generated file is listed in the CMAKE_MAKEFILE_PRODUCTS with the wrong path. Which is due to the fact that the relative path of the file is resolved incorrectly.
Step to reproduce:
- Create a CMakeLists.txt with the following content:
set(file_path ${CMAKE_BINARY_DIR}//a_file.txt)
file(GENERATE OUTPUT ${file_path} CONTENT "Generating file with 2 times in a row slashes to check
relative path resolution for this file when build byproducts are generated")
- Configure a build directory referring to the above created cmake list file.
> mkdir build
> cd build
> cmake _path_to/CMakeLists.txt
- Now build the project
> make
Actual result: The project is configured one more time before build, as "/a_file.txt" byproduct dependency/existence is never satisfied.
Expected result: The project should not be configured upon build, unless anything is changed in the build tree or in the sources.
Details:
When cmake makefile products list is generated, all byproducts are resolved relative to CMAKE_BINARY_DIR. AND if byproduct path contains double slashes, the relative path is resolved incorrectly.
When the path is split into components and later joined to construct final relative path, empty components are not skipped which causes the issue. E.g.
- Input directory is
/A/B/C
- File path to be resolved relatively -
/A/B/C//D/E/F
- Returned relative path -
/D/E/F
The issue can be fixed by applying the following patch:
--- a/Source/kwsys/SystemTools.cxx 2017-05-16 16:32:37.662429395 +0200
+++ b/Source/kwsys/SystemTools.cxx 2017-05-16 15:29:26.882429395 +0200
@@ -4225,13 +4225,16 @@
if(*last == '/' || *last == '\\')
{
// End of a component. Save it.
- components.push_back(std::string(first, last));
+ if(first != last)
+ {
+ components.push_back(std::string(first, last));
+ }
first = last+1;
}
}
// Save the last component unless there were no components.
- if(last != c)
+ if(last != c && first != last)
{
components.push_back(std::string(first, last));
}