CMake fails to compile test program on Windows using generator "MinGW Makefiles" when installed in network location
Summary
The "Check for working C Compiler" step fails when CMake is installed in a network location and the "MinGW Makefiles" generator is used, with the following syndrome:
The C compiler
"G:/MinGW/bin/gcc.exe"
is not able to compile a simple test program.
It fails with the following output:
Change Dir: U:/scratch/cmake_mingw_bug/CMakeFiles/CMakeTmp
Run Build Command(s):G:/MinGW/bin/mingw32-make.exe cmTC_07339/fast && G:/MinGW/bin/mingw32-make.exe -f CMakeFiles\cmTC_07339.dir\build.make CMakeFiles/cmTC_07339.dir/build
mingw32-make.exe[1]: Entering directory 'U:/scratch/cmake_mingw_bug/CMakeFiles/CMakeTmp'
process_begin: CreateProcess(NULL, \server\share\bin\cmake.exe -E cmake_echo_color --switch= --progress-dir=U:\scratch\cmake_mingw_bug\CMakeFiles\CMakeTmp\CMakeFiles --progress-num=1 "Building C object CMakeFiles/cmTC_07339.dir/testCCompiler.c.obj", ...) failed.
make (e=2): The system cannot find the file specified.
mingw32-make.exe[1]: *** [CMakeFiles\cmTC_07339.dir\build.make:83: CMakeFiles/cmTC_07339.dir/testCCompiler.c.obj] Error 2
mingw32-make.exe[1]: Leaving directory 'U:/scratch/cmake_mingw_bug/CMakeFiles/CMakeTmp'
mingw32-make.exe: *** [Makefile:139: cmTC_07339/fast] Error 2
Reproduction Steps
This appears to still be reproducible with an installation built from the master
branch.
- Install CMake on a mapped network drive on Windows.
- Try to build a project using that installation of CMake and the
MinGW Makefiles
generator.
Analysis
It appears that CMake always resolves a canonical UNC path to the CMake executable, even if it is on a mapped drive, and the root cause appears to be related to the definition of the variable in the generated makefile:
CMAKE_COMMAND = \\server\share\bin\cmake.exe
It looks like gmake interprets the first backslash in \\
as an escape character. Prepending a further escaped backslash would half solve the problem, except it also looks like there are some situations where the $(CMAKE_COMMAND)
expansion is used as arguments to external tools that do not interpret the backslash as an escape character, for example, when getting CMake to re-build itself in the following excerpt, the additional escape is needed in the first line, but not the second or third.
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --bold --progress-dir=T:\cmake_win\winbuild\CMakeFiles --progress-num=$(CMAKE_PROGRESS_18) "Linking CXX static library libcmsys.a"
cd /d T:\cmake_win\winbuild\Source\kwsys && $(CMAKE_COMMAND) -P CMakeFiles\cmsys.dir\cmake_clean_target.cmake
cd /d T:\cmake_win\winbuild\Source\kwsys && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles\cmsys.dir\link.txt --verbose=$(VERBOSE)
Therefore, a practical option might be to encapsulate UNC paths in quotes when using the "MinGW Makefiles" generator for example, e.g.,
CMAKE_COMMAND = "\\server\share\bin\cmake.exe"
I was able to get CMake hosted on a network drive to rebuild another instance of CMake, by applying the following modification:
--- a/Source/cmOutputConverter.cxx
+++ b/Source/cmOutputConverter.cxx
@@ -527,6 +527,13 @@ bool cmOutputConverter::Shell_ArgumentNeedsQuotes(cm::string_view in,
}
}
+ /* UNC paths in MinGW Makefiles need quotes */
+ if ((flags & Shell_Flag_MinGWMake) && (flags & Shell_Flag_Make) && in.size() > 1) {
+ if (in[0] == '\\' && in[1] == '\\') {
+ return true;
+ }
+ }
+
return false;
}