From 491dddfbdeb7b958805e931b37783cca448eb8d8 Mon Sep 17 00:00:00 2001
From: Kyle Edwards <kyle.edwards@kitware.com>
Date: Mon, 10 Aug 2020 14:40:17 -0400
Subject: [PATCH] Bootstrap: Add support for Ninja

---
 Source/cmMakefile.cxx     |   6 +-
 Source/cmake.cxx          |  15 +-
 Source/cmcmd.cxx          |   2 +-
 Tests/BootstrapTest.cmake |   7 +-
 Tests/CMakeLists.txt      |   1 +
 bootstrap                 | 360 ++++++++++++++++++++++++++++++--------
 6 files changed, 315 insertions(+), 76 deletions(-)

diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 5e1f0702bb..5cfe5f1dbb 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -20,8 +20,10 @@
 #include <cmext/algorithm>
 #include <cmext/string_view>
 
-#include <cm3p/json/value.h>
-#include <cm3p/json/writer.h>
+#ifndef CMAKE_BOOTSTRAP
+#  include <cm3p/json/value.h>
+#  include <cm3p/json/writer.h>
+#endif
 
 #include "cmsys/FStream.hxx"
 #include "cmsys/RegularExpression.hxx"
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index dcb96f8f72..f630a7e9fb 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -93,9 +93,13 @@
 #if defined(CMAKE_USE_WMAKE)
 #  include "cmGlobalWatcomWMakeGenerator.h"
 #endif
-#include "cmGlobalUnixMakefileGenerator3.h"
 #if !defined(CMAKE_BOOTSTRAP)
 #  include "cmGlobalNinjaGenerator.h"
+#  include "cmGlobalUnixMakefileGenerator3.h"
+#elif defined(CMAKE_BOOTSTRAP_MAKEFILES)
+#  include "cmGlobalUnixMakefileGenerator3.h"
+#elif defined(CMAKE_BOOTSTRAP_NINJA)
+#  include "cmGlobalNinjaGenerator.h"
 #endif
 
 #if !defined(CMAKE_BOOTSTRAP)
@@ -1750,6 +1754,9 @@ std::unique_ptr<cmGlobalGenerator> cmake::EvaluateDefaultGlobalGenerator()
     gen = cm::make_unique<cmGlobalNMakeMakefileGenerator>(this);
   }
   return std::unique_ptr<cmGlobalGenerator>(std::move(gen));
+#elif defined(CMAKE_BOOTSTRAP_NINJA)
+  return std::unique_ptr<cmGlobalGenerator>(
+    cm::make_unique<cmGlobalNinjaGenerator>(this));
 #else
   return std::unique_ptr<cmGlobalGenerator>(
     cm::make_unique<cmGlobalUnixMakefileGenerator3>(this));
@@ -2026,13 +2033,17 @@ void cmake::AddDefaultGenerators()
   this->Generators.push_back(cmGlobalMSYSMakefileGenerator::NewFactory());
   this->Generators.push_back(cmGlobalMinGWMakefileGenerator::NewFactory());
 #endif
-  this->Generators.push_back(cmGlobalUnixMakefileGenerator3::NewFactory());
 #if !defined(CMAKE_BOOTSTRAP)
 #  if defined(__linux__) || defined(_WIN32)
   this->Generators.push_back(cmGlobalGhsMultiGenerator::NewFactory());
 #  endif
+  this->Generators.push_back(cmGlobalUnixMakefileGenerator3::NewFactory());
   this->Generators.push_back(cmGlobalNinjaGenerator::NewFactory());
   this->Generators.push_back(cmGlobalNinjaMultiGenerator::NewFactory());
+#elif defined(CMAKE_BOOTSTRAP_NINJA)
+  this->Generators.push_back(cmGlobalNinjaGenerator::NewFactory());
+#elif defined(CMAKE_BOOTSTRAP_MAKEFILES)
+  this->Generators.push_back(cmGlobalUnixMakefileGenerator3::NewFactory());
 #endif
 #if defined(CMAKE_USE_WMAKE)
   this->Generators.push_back(cmGlobalWatcomWMakeGenerator::NewFactory());
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 1a5fea1e33..47dc0c96e5 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -1161,7 +1161,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args)
       return cmcmd::ExecuteLinkScript(args);
     }
 
-#ifndef CMAKE_BOOTSTRAP
+#if !defined(CMAKE_BOOTSTRAP) || defined(CMAKE_BOOTSTRAP_NINJA)
     // Internal CMake ninja dependency scanning support.
     if (args[1] == "cmake_ninja_depends") {
       return cmcmd_cmake_ninja_depends(args.begin() + 2, args.end());
diff --git a/Tests/BootstrapTest.cmake b/Tests/BootstrapTest.cmake
index 07a65bfd6f..137de78bc1 100644
--- a/Tests/BootstrapTest.cmake
+++ b/Tests/BootstrapTest.cmake
@@ -1,12 +1,15 @@
 file(MAKE_DIRECTORY "${bin_dir}")
 include(ProcessorCount)
 ProcessorCount(nproc)
+if(generator MATCHES "Ninja")
+  set(ninja_arg --generator=Ninja)
+endif()
 if(NOT nproc EQUAL 0)
   set(parallel_arg --parallel=${nproc})
 endif()
-message(STATUS "running bootstrap: ${bootstrap} ${parallel_arg}")
+message(STATUS "running bootstrap: ${bootstrap} ${ninja_arg} ${parallel_arg}")
 execute_process(
-  COMMAND ${bootstrap} ${parallel_arg}
+  COMMAND ${bootstrap} ${ninja_arg} ${parallel_arg}
   WORKING_DIRECTORY "${bin_dir}"
   RESULT_VARIABLE result
   )
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 4a774dd392..e4e09faf84 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -3240,6 +3240,7 @@ ${CMake_SOURCE_DIR}/Utilities/Release/push.bash --dir dev -- '${CMake_BUILD_NIGH
       COMMAND ${CMAKE_CMAKE_COMMAND}
         -D "bootstrap=${bootstrap}"
         -D "bin_dir=${CMake_BINARY_DIR}/Tests/BootstrapTest"
+        -D "generator=${CMAKE_GENERATOR}"
         -P ${CMAKE_CURRENT_SOURCE_DIR}/BootstrapTest.cmake
       )
     list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/BootstrapTest")
diff --git a/bootstrap b/bootstrap
index 2ef0fbbf11..eabe06b5fb 100755
--- a/bootstrap
+++ b/bootstrap
@@ -236,6 +236,7 @@ cmake_xdgdata_dir_default="`cmake_install_dest_default XDGDATA ${cmake_xdgdata_d
 CMAKE_KNOWN_C_COMPILERS="cc gcc clang xlc icc tcc"
 CMAKE_KNOWN_CXX_COMPILERS="aCC xlC CC g++ clang++ c++ icc como "
 CMAKE_KNOWN_MAKE_PROCESSORS="gmake make"
+CMAKE_KNOWN_NINJA_PROCESSORS="ninja-build ninja"
 
 CMAKE_PROBLEMATIC_FILES="\
   CMakeCache.txt \
@@ -309,8 +310,6 @@ CMAKE_CXX_SOURCES="\
   cmCustomCommandLines \
   cmDefinePropertyCommand \
   cmDefinitions \
-  cmDepends \
-  cmDependsC \
   cmDocumentationFormatter \
   cmEnableLanguageCommand \
   cmEnableTestingCommand \
@@ -361,7 +360,6 @@ CMAKE_CXX_SOURCES="\
   cmGetTestPropertyCommand \
   cmGlobalCommonGenerator \
   cmGlobalGenerator \
-  cmGlobalUnixMakefileGenerator3 \
   cmGlobVerificationManager \
   cmHexFileConverter \
   cmIfCommand \
@@ -392,15 +390,10 @@ CMAKE_CXX_SOURCES="\
   cmListFileCache \
   cmLocalCommonGenerator \
   cmLocalGenerator \
-  cmLocalUnixMakefileGenerator3 \
   cmMSVC60LinkLineComputer \
   cmMacroCommand \
   cmMakeDirectoryCommand \
   cmMakefile \
-  cmMakefileExecutableTargetGenerator \
-  cmMakefileLibraryTargetGenerator \
-  cmMakefileTargetGenerator \
-  cmMakefileUtilityTargetGenerator \
   cmMarkAsAdvancedCommand \
   cmMathCommand \
   cmMessageCommand \
@@ -607,6 +600,8 @@ Configuration:
   --verbose               display more information
   --parallel=n            bootstrap cmake in parallel, where n is
                           number of nodes [1]
+  --generator=<generator> generator to use (MSYS Makefiles, Unix Makefiles,
+                          or Ninja)
   --enable-ccache         Enable ccache when building cmake
   --init=FILE             load FILE as script to populate cache
   --system-libs           use all system-installed third-party libraries
@@ -637,6 +632,8 @@ Configuration:
   --no-system-libuv       use cmake-provided libuv library (default)
 
   --bootstrap-system-libuv use system-installed libuv library for bootstrap
+  --bootstrap-system-jsoncpp use system-installed jsoncpp library for bootstrap
+  --bootstrap-system-librhash use system-installed librhash library for bootstrap
 
   --qt-gui                build the Qt-based GUI (requires Qt >= 4.2)
   --no-qt-gui             do not build the Qt-based GUI (default)
@@ -689,16 +686,23 @@ cmake_error()
   exit ${res}
 }
 
+cmake_generate_file_tmp ()
+{
+  OUTFILE="$1"
+  TMPFILE="$2"
+  if "${_diff}" "$TMPFILE" "$OUTFILE" > /dev/null 2> /dev/null ; then
+    rm -f "$TMPFILE"
+  else
+    mv -f "$TMPFILE" "$OUTFILE"
+  fi
+}
+
 cmake_generate_file ()
 {
   OUTFILE="$1"
   CONTENT="$2"
   echo "$CONTENT" > "$OUTFILE.tmp"
-  if "${_diff}" "$OUTFILE.tmp" "$OUTFILE" > /dev/null 2> /dev/null ; then
-    rm -f "$OUTFILE.tmp"
-  else
-    mv -f "$OUTFILE.tmp" "$OUTFILE"
-  fi
+  cmake_generate_file_tmp "$OUTFILE" "$OUTFILE.tmp"
 }
 
 # Replace KWSYS_NAMESPACE with cmsys
@@ -760,8 +764,18 @@ cmake_report ()
   echo "$*" >> ${FILE}
 }
 
-# Escape spaces in strings
-cmake_escape ()
+# Escape spaces in strings for artifacts
+cmake_escape_artifact ()
+{
+  if test "${cmake_bootstrap_generator}" = "Ninja"; then
+    echo $1 | sed "s/ /$ /g"
+  else
+    echo $1 | sed "s/ /\\\\ /g"
+  fi
+}
+
+# Escape spaces in strings for shell
+cmake_escape_shell ()
 {
   echo $1 | sed "s/ /\\\\ /g"
 }
@@ -861,11 +875,14 @@ cmake_parallel_make=
 cmake_ccache_enabled=
 cmake_prefix_dir="${cmake_default_prefix}"
 bootstrap_system_libuv=
+bootstrap_system_jsoncpp=
+bootstrap_system_librhash=
 while test $# != 0; do
   case "$1" in
   --prefix=*) dir=`cmake_arg "$1"`
               cmake_prefix_dir=`cmake_fix_slashes "$dir"` ;;
   --parallel=*) cmake_parallel_make=`cmake_arg "$1"` ;;
+  --generator=*) cmake_bootstrap_generator=`cmake_arg "$1"` ;;
   --bindir=*) cmake_bin_dir=`cmake_arg "$1"` ;;
   --datadir=*) cmake_data_dir=`cmake_arg "$1"` ;;
   --docdir=*) cmake_doc_dir=`cmake_arg "$1"` ;;
@@ -881,6 +898,8 @@ while test $# != 0; do
     lib=`cmake_arg "$1" "--no-system-"`
     cmake_bootstrap_system_libs="${cmake_bootstrap_system_libs} -DCMAKE_USE_SYSTEM_LIBRARY_`cmake_toupper $lib`=0" ;;
   --bootstrap-system-libuv) bootstrap_system_libuv="1" ;;
+  --bootstrap-system-jsoncpp) bootstrap_system_jsoncpp="1" ;;
+  --bootstrap-system-librhash) bootstrap_system_librhash="1" ;;
   --qt-gui) cmake_bootstrap_qt_gui="1" ;;
   --no-qt-gui) cmake_bootstrap_qt_gui="0" ;;
   --qt-qmake=*) cmake_bootstrap_qt_qmake=`cmake_arg "$1"` ;;
@@ -905,6 +924,13 @@ while test $# != 0; do
   shift
 done
 
+# Make sure the generator is valid
+if test "${cmake_bootstrap_generator}" != "MSYS Makefiles" -a \
+    "${cmake_bootstrap_generator}" != "Unix Makefiles" -a \
+    "${cmake_bootstrap_generator}" != "Ninja"; then
+  cmake_error 10 "Invalid generator: ${cmake_bootstrap_generator}"
+fi
+
 # If verbose, display some information about bootstrap
 if test -n "${cmake_verbose}"; then
   echo "---------------------------------------------"
@@ -912,6 +938,7 @@ if test -n "${cmake_verbose}"; then
   echo "Binary directory: ${cmake_binary_dir}"
   echo "Prefix directory: ${cmake_prefix_dir}"
   echo "System:           ${cmake_system}"
+  echo "Generator:        ${cmake_bootstrap_generator}"
   if test "x${cmake_parallel_make}" != "x"; then
     echo "Doing parallel make: ${cmake_parallel_make}"
   fi
@@ -980,6 +1007,58 @@ cmake_c_flags=${CFLAGS}
 cmake_cxx_flags=${CXXFLAGS}
 cmake_ld_flags=${LDFLAGS}
 
+# Add generator-specific files
+if test "${cmake_bootstrap_generator}" = "Ninja"; then
+  CMAKE_CXX_SOURCES="${CMAKE_CXX_SOURCES} \
+    cmCryptoHash \
+    cmFortranParserImpl \
+    cmGlobalNinjaGenerator \
+    cmLocalNinjaGenerator \
+    cmNinjaLinkLineComputer \
+    cmNinjaLinkLineDeviceComputer \
+    cmNinjaNormalTargetGenerator \
+    cmNinjaTargetGenerator \
+    cmNinjaUtilityTargetGenerator \
+    "
+
+  LexerParser_CXX_SOURCES="${LexerParser_CXX_SOURCES} \
+    cmFortranLexer \
+    cmFortranParser \
+    "
+
+  JSONCPP_CXX_SOURCES="\
+    src/lib_json/json_reader.cpp \
+    src/lib_json/json_value.cpp \
+    src/lib_json/json_writer.cpp \
+    "
+
+  LIBRHASH_C_SOURCES="\
+    librhash/algorithms.c \
+    librhash/byte_order.c \
+    librhash/hex.c \
+    librhash/md5.c \
+    librhash/rhash.c \
+    librhash/sha1.c \
+    librhash/sha256.c \
+    librhash/sha3.c \
+    librhash/sha512.c \
+    "
+else
+  CMAKE_CXX_SOURCES="${CMAKE_CXX_SOURCES} \
+    cmDepends \
+    cmDependsC \
+    cmGlobalUnixMakefileGenerator3 \
+    cmLocalUnixMakefileGenerator3 \
+    cmMakefileExecutableTargetGenerator \
+    cmMakefileLibraryTargetGenerator \
+    cmMakefileTargetGenerator \
+    cmMakefileUtilityTargetGenerator \
+    "
+
+  JSONCPP_CXX_SOURCES=
+  LIBRHASH_C_SOURCES=
+fi
+
 # Add Cygwin-specific flags
 if ${cmake_system_cygwin}; then
   cmake_ld_flags="${LDFLAGS} -Wl,--enable-auto-import"
@@ -1288,6 +1367,8 @@ cmake_make_flags=
 # If MAKE is set, use that for make processor, otherwise use list of known make
 if test -n "${MAKE}"; then
   cmake_make_processors="${MAKE}"
+elif test "${cmake_bootstrap_generator}" = "Ninja"; then
+  cmake_make_processors="${CMAKE_KNOWN_NINJA_PROCESSORS}"
 else
   cmake_make_processors="${CMAKE_KNOWN_MAKE_PROCESSORS}"
 fi
@@ -1296,10 +1377,18 @@ TMPFILE="`cmake_tmp_file`_dir"
 rm -rf "${cmake_bootstrap_dir}/${TMPFILE}"
 mkdir "${cmake_bootstrap_dir}/${TMPFILE}"
 cd "${cmake_bootstrap_dir}/${TMPFILE}"
-echo '
+if test "${cmake_bootstrap_generator}" = "Ninja"; then
+  echo '
+rule cc
+  command = "'"${cmake_c_compiler}"'" '"${cmake_ld_flags} ${cmake_c_flags}"' -o $out $in
+build test: cc test.c
+'>"build.ninja"
+else
+  echo '
 test: test.c
 	"'"${cmake_c_compiler}"'" '"${cmake_ld_flags} ${cmake_c_flags}"' -o test test.c
 '>"Makefile"
+fi
 echo '
 #include <stdio.h>
 int main(){ printf("1%c", (char)0x0a); return 0; }
@@ -1326,15 +1415,20 @@ if test "x${cmake_original_make_flags}" != "x${cmake_make_flags}"; then
 fi
 cd "${cmake_bootstrap_dir}"
 
+if test "${cmake_bootstrap_generator}" = "Ninja"; then
+  mf_str=Ninja
+else
+  mf_str=Makefile
+fi
 if test -z "${cmake_make_processor}"; then
-  cmake_error 8 "Cannot find appropriate Makefile processor on this system.
+  cmake_error 8 "Cannot find appropriate ${mf_str} processor on this system.
 Please specify one using environment variable MAKE."
 fi
 rm -rf "${cmake_bootstrap_dir}/${TMPFILE}"
-echo "Makefile processor on this system is: ${cmake_make_processor}"
+echo "${mf_str} processor on this system is: ${cmake_make_processor}"
 if test "x${cmake_full_make_flags}" != "x${cmake_make_flags}"; then
   echo "---------------------------------------------"
-  echo "Makefile processor ${cmake_make_processor} does not support parallel build"
+  echo "${mf_str} processor ${cmake_make_processor} does not support parallel build"
   echo "---------------------------------------------"
 fi
 
@@ -1431,6 +1525,10 @@ cmake_compiler_settings_comment="/*
  * ${KWSYS_CXX_SOURCES} ${KWSYS_C_SOURCES}
  * libuv Sources:
  * ${LIBUV_C_SOURCES}
+ * jsoncpp Sources:
+ * ${JSONCPP_CXX_SOURCES}
+ * librhash Sources:
+ * ${LIBRHASH_C_SOURCES}
  */
 "
 
@@ -1458,6 +1556,12 @@ cmake_report cmConfigure.h${_tmp} "#define CMAKE_BIN_DIR \"/bootstrap-not-insall
 cmake_report cmConfigure.h${_tmp} "#define CMAKE_DATA_DIR \"/bootstrap-not-insalled\""
 cmake_report cmConfigure.h${_tmp} "#define CM_FALLTHROUGH"
 
+if test "${cmake_bootstrap_generator}" = "Ninja"; then
+  cmake_report cmConfigure.h${_tmp} "#define CMAKE_BOOTSTRAP_NINJA"
+else
+  cmake_report cmConfigure.h${_tmp} "#define CMAKE_BOOTSTRAP_MAKEFILES"
+fi
+
 if ${cmake_system_mingw}; then
   cmake_report cmConfigure.h${_tmp} "#if defined(_WIN32) && !defined(NOMINMAX)"
   cmake_report cmConfigure.h${_tmp} "#  define NOMINMAX"
@@ -1474,6 +1578,7 @@ for h in Configure VersionConfig; do
 done
 
 # Prepare KWSYS
+cmsys_header_files="cmsys/Configure.h cmsys/Configure.hxx"
 cmake_kwsys_config_replace_string \
   "${cmake_source_dir}/Source/kwsys/Configure.hxx.in" \
   "${cmake_bootstrap_dir}/cmsys/Configure.hxx" \
@@ -1486,14 +1591,33 @@ cmake_kwsys_config_replace_string \
 for a in ${KWSYS_FILES}; do
   cmake_replace_string "${cmake_source_dir}/Source/kwsys/${a}.in" \
      "${cmake_bootstrap_dir}/cmsys/${a}" KWSYS_NAMESPACE cmsys
+  cmsys_header_files="${cmsys_header_files} cmsys/${a}"
 done
 
-cmake_generate_file "${cmake_bootstrap_dir}/cmThirdParty.h" ""
+echo "#ifndef cmThirdParty_h" > "${cmake_bootstrap_dir}/cmThirdParty.h.tmp"
+echo "#define cmThirdParty_h" >> "${cmake_bootstrap_dir}/cmThirdParty.h.tmp"
+if test "x${bootstrap_system_libuv}" != "x"; then
+  echo "#define CMAKE_USE_SYSTEM_LIBUV" >> "${cmake_bootstrap_dir}/cmThirdParty.h.tmp"
+fi
+if test "x${bootstrap_system_jsoncpp}" != "x"; then
+  echo "#define CMAKE_USE_SYSTEM_JSONCPP" >> "${cmake_bootstrap_dir}/cmThirdParty.h.tmp"
+fi
+if test "x${bootstrap_system_librhash}" != "x"; then
+  echo "#define CMAKE_USE_SYSTEM_LIBRHASH" >> "${cmake_bootstrap_dir}/cmThirdParty.h.tmp"
+fi
+echo "#endif" >> "${cmake_bootstrap_dir}/cmThirdParty.h.tmp"
+cmake_generate_file_tmp "${cmake_bootstrap_dir}/cmThirdParty.h" "${cmake_bootstrap_dir}/cmThirdParty.h.tmp"
 
 # Generate Makefile
-dep="cmConfigure.h cmsys/*.hxx cmsys/*.h `cmake_escape \"${cmake_source_dir}\"`/Source/*.hxx `cmake_escape \"${cmake_source_dir}\"`/Source/*.h"
+dep="cmConfigure.h ${cmsys_header_files}"
+for h in "${cmake_source_dir}"/Source/*.hxx; do
+  dep="${dep} `cmake_escape_artifact \"${h}\"`"
+done
+for h in "${cmake_source_dir}"/Source/*.h; do
+  dep="${dep} `cmake_escape_artifact \"${h}\"`"
+done
 for h in ${CMAKE_STD_CXX_HEADERS}; do
-  dep="${dep} `cmake_escape \"${cmake_source_dir}\"`/Utilities/std/cm/${h}"
+  dep="${dep} `cmake_escape_artifact \"${cmake_source_dir}\"`/Utilities/std/cm/${h}"
 done
 objs=""
 for a in ${CMAKE_CXX_SOURCES} ${CMAKE_C_SOURCES} ${CMAKE_STD_CXX_SOURCES} ${LexerParser_CXX_SOURCES} ${LexerParser_C_SOURCES} ${KWSYS_CXX_SOURCES} ${KWSYS_C_SOURCES}; do
@@ -1504,6 +1628,18 @@ if test "x${bootstrap_system_libuv}" = "x"; then
     objs="${objs} uv-`cmake_obj ${a}`"
   done
 fi
+if test "${cmake_bootstrap_generator}" = "Ninja"; then
+  if test "x${bootstrap_system_jsoncpp}" = "x"; then
+    for a in ${JSONCPP_CXX_SOURCES}; do
+      objs="${objs} jsoncpp-`cmake_obj ${a}`"
+    done
+  fi
+  if test "x${bootstrap_system_librhash}" = "x"; then
+    for a in ${LIBRHASH_C_SOURCES}; do
+      objs="${objs} rhash-`cmake_obj ${a}`"
+    done
+  fi
+fi
 
 libs=""
 
@@ -1542,19 +1678,44 @@ else
   esac
 fi
 if test "x${bootstrap_system_libuv}" = "x"; then
-  uv_c_flags="${uv_c_flags} `cmake_escape "-I${cmake_source_dir}/Utilities/cmlibuv/include"`"
+  uv_c_flags="${uv_c_flags} `cmake_escape_shell "-I${cmake_source_dir}/Utilities/cmlibuv/include"`"
   if ${cmake_system_mingw}; then
-    uv_c_flags="${uv_c_flags} `cmake_escape "-I${cmake_source_dir}/Utilities/cmlibuv/src/win"`"
+    uv_c_flags="${uv_c_flags} `cmake_escape_shell "-I${cmake_source_dir}/Utilities/cmlibuv/src/win"`"
   else
-    uv_c_flags="${uv_c_flags} `cmake_escape "-I${cmake_source_dir}/Utilities/cmlibuv/src/unix"`"
+    uv_c_flags="${uv_c_flags} `cmake_escape_shell "-I${cmake_source_dir}/Utilities/cmlibuv/src/unix"`"
   fi
-  uv_c_flags="${uv_c_flags} `cmake_escape "-I${cmake_source_dir}/Utilities/cmlibuv/src"`"
+  uv_c_flags="${uv_c_flags} `cmake_escape_shell "-I${cmake_source_dir}/Utilities/cmlibuv/src"`"
 else
   if test `which pkg-config`; then
-    uv_c_flags="${uv_c_flags} `pkg-config --cflags libuv`"
+    use_uv_flags="`pkg-config --cflags libuv`"
+    cmake_c_flags="${cmake_c_flags} ${use_uv_flags}"
+    cmake_cxx_flags="${cmake_cxx_flags} ${use_uv_flags}"
   fi
   libs="${libs} -luv"
 fi
+
+if test "${cmake_bootstrap_generator}" = "Ninja"; then
+  jsoncpp_cxx_flags=
+  if test "x${bootstrap_system_jsoncpp}" = "x"; then
+    jsoncpp_cxx_flags="${jsoncpp_cxx_flags} `cmake_escape_shell "-I${cmake_source_dir}/Utilities/cmjsoncpp/include"`"
+  else
+    if test `which pkg-config`; then
+      use_jsoncpp_flags="`pkg-config --cflags jsoncpp`"
+      cmake_cxx_flags="${cmake_cxx_flags} ${use_jsoncpp_flags}"
+    fi
+    libs="${libs} -ljsoncpp"
+  fi
+
+  if test "x${bootstrap_system_librhash}" != "x"; then
+    if test `which pkg-config`; then
+      use_librhash_flags="`pkg-config --cflags librhash`"
+      cmake_c_flags="${cmake_c_flags} ${use_librhash_flags}"
+      cmake_cxx_flags="${cmake_cxx_flags} ${use_librhash_flags}"
+    fi
+    libs="${libs} -lrhash"
+  fi
+fi
+
 if test "x${cmake_ansi_cxx_flags}" != "x"; then
   cmake_cxx_flags="${cmake_ansi_cxx_flags} ${cmake_cxx_flags}"
 fi
@@ -1567,6 +1728,31 @@ if test "x${cmake_cxx_flags}" != "x"; then
   cmake_cxx_flags="${cmake_cxx_flags} "
 fi
 
+write_source_rule() {
+  lang="$1"
+  obj="$2"
+  src="$3"
+  src_flags="$4"
+
+  if test "${lang}" = "c"; then
+    ninja_rule=cc
+    compiler="${cmake_c_compiler}"
+    flags="${cmake_c_flags}"
+  elif test "${lang}" = "cxx"; then
+    ninja_rule=cxx
+    compiler="${cmake_cxx_compiler}"
+    flags="${cmake_cxx_flags}"
+  fi
+
+  if test "${cmake_bootstrap_generator}" = "Ninja"; then
+    echo "build ${obj} : ${ninja_rule} ${src} | ${dep}" >> "${cmake_bootstrap_dir}/build.ninja"
+    echo "  srcflags = ${src_flags}" >> "${cmake_bootstrap_dir}/build.ninja"
+  else
+    echo "${obj} : ${src} ${dep}" >> "${cmake_bootstrap_dir}/Makefile"
+    echo "	${compiler} ${flags} ${src_flags} -c ${src} -o ${obj}" >> "${cmake_bootstrap_dir}/Makefile"
+  fi
+}
+
 cmake_c_flags_String="-DKWSYS_STRING_C"
 if ${cmake_system_mingw}; then
   cmake_c_flags_EncodingC="-DKWSYS_ENCODING_DEFAULT_CODEPAGE=CP_ACP"
@@ -1582,71 +1768,102 @@ cmake_cxx_flags_SystemTools="
 "
 cmake_c_flags="${cmake_c_flags} \
   -DCMAKE_BOOTSTRAP \
-  -I`cmake_escape \"${cmake_bootstrap_dir}\"` \
-  -I`cmake_escape \"${cmake_source_dir}/Source\"` \
-  -I`cmake_escape \"${cmake_source_dir}/Source/LexerParser\"` \
-  -I`cmake_escape \"${cmake_source_dir}/Utilities\"`"
+  -I`cmake_escape_shell \"${cmake_bootstrap_dir}\"` \
+  -I`cmake_escape_shell \"${cmake_source_dir}/Source\"` \
+  -I`cmake_escape_shell \"${cmake_source_dir}/Source/LexerParser\"` \
+  -I`cmake_escape_shell \"${cmake_source_dir}/Utilities\"`"
 cmake_cxx_flags="${cmake_cxx_flags} \
   -DCMAKE_BOOTSTRAP \
   ${cmake_have_cxx_features} \
-  -I`cmake_escape \"${cmake_bootstrap_dir}\"` \
-  -I`cmake_escape \"${cmake_source_dir}/Source\"` \
-  -I`cmake_escape \"${cmake_source_dir}/Source/LexerParser\"` \
-  -I`cmake_escape \"${cmake_source_dir}/Utilities/std\"` \
-  -I`cmake_escape \"${cmake_source_dir}/Utilities\"`"
-echo "cmake: ${objs}" > "${cmake_bootstrap_dir}/Makefile"
-echo "	${cmake_cxx_compiler} ${cmake_ld_flags} ${cmake_cxx_flags} ${objs} ${libs} -o cmake" >> "${cmake_bootstrap_dir}/Makefile"
+  -I`cmake_escape_shell \"${cmake_bootstrap_dir}\"` \
+  -I`cmake_escape_shell \"${cmake_source_dir}/Source\"` \
+  -I`cmake_escape_shell \"${cmake_source_dir}/Source/LexerParser\"` \
+  -I`cmake_escape_shell \"${cmake_source_dir}/Utilities/std\"` \
+  -I`cmake_escape_shell \"${cmake_source_dir}/Utilities\"`"
+if test "${cmake_bootstrap_generator}" = "Ninja"; then
+  echo "cc = ${cmake_c_compiler}" > "${cmake_bootstrap_dir}/build.ninja"
+  echo "cxx = ${cmake_cxx_compiler}" >> "${cmake_bootstrap_dir}/build.ninja"
+  echo "cflags = ${cmake_c_flags}" >> "${cmake_bootstrap_dir}/build.ninja"
+  echo "cxxflags = ${cmake_cxx_flags}" >> "${cmake_bootstrap_dir}/build.ninja"
+  echo "ldflags = ${cmake_ld_flags}" >> "${cmake_bootstrap_dir}/build.ninja"
+  echo "rule cc" >> "${cmake_bootstrap_dir}/build.ninja"
+  echo "  command = \$cc \$cflags \$srcflags -c \$in -o \$out" >> "${cmake_bootstrap_dir}/build.ninja"
+  echo "rule cxx" >> "${cmake_bootstrap_dir}/build.ninja"
+  echo "  command = \$cxx \$cxxflags \$srcflags -c \$in -o \$out" >> "${cmake_bootstrap_dir}/build.ninja"
+  echo "rule link" >> "${cmake_bootstrap_dir}/build.ninja"
+  echo "  command = \$cxx \$ldflags \$cxxflags \$in \$libs -o \$out" >> "${cmake_bootstrap_dir}/build.ninja"
+  echo "build cmake: link ${objs}" >> "${cmake_bootstrap_dir}/build.ninja"
+  echo "  libs = ${libs}" >> "${cmake_bootstrap_dir}/build.ninja"
+else
+  echo "cmake: ${objs}" > "${cmake_bootstrap_dir}/Makefile"
+  echo "	${cmake_cxx_compiler} ${cmake_ld_flags} ${cmake_cxx_flags} ${objs} ${libs} -o cmake" >> "${cmake_bootstrap_dir}/Makefile"
+fi
 for a in ${CMAKE_CXX_SOURCES}; do
-  src=`cmake_escape "${cmake_source_dir}/Source/${a}.cxx"`
+  src=`cmake_escape_artifact "${cmake_source_dir}/Source/${a}.cxx"`
   src_flags=`eval echo \\${cmake_cxx_flags_\${a}}`
-  echo "${a}.o : ${src} ${dep}" >> "${cmake_bootstrap_dir}/Makefile"
-  echo "	${cmake_cxx_compiler} ${cmake_cxx_flags} ${src_flags} -c ${src} -o ${a}.o" >> "${cmake_bootstrap_dir}/Makefile"
+  write_source_rule "cxx" "${a}.o" "${src}" "${src_flags}"
 done
 for a in ${CMAKE_C_SOURCES}; do
-  src=`cmake_escape "${cmake_source_dir}/Source/${a}.c"`
-  echo "${a}.o : ${src} ${dep}" >> "${cmake_bootstrap_dir}/Makefile"
-  echo "	${cmake_c_compiler} ${cmake_c_flags} -c ${src} -o ${a}.o" >> "${cmake_bootstrap_dir}/Makefile"
+  src=`cmake_escape_artifact "${cmake_source_dir}/Source/${a}.c"`
+  write_source_rule "c" "${a}.o" "${src}" ""
 done
 for a in ${CMAKE_STD_CXX_SOURCES}; do
-  src=`cmake_escape "${cmake_source_dir}/Utilities/std/cm/bits/${a}.cxx"`
+  src=`cmake_escape_artifact "${cmake_source_dir}/Utilities/std/cm/bits/${a}.cxx"`
   src_flags=`eval echo \\${cmake_cxx_flags_\${a}}`
-  echo "${a}.o : ${src} ${dep}" >> "${cmake_bootstrap_dir}/Makefile"
-  echo "	${cmake_cxx_compiler} ${cmake_cxx_flags} ${src_flags} -c ${src} -o ${a}.o" >> "${cmake_bootstrap_dir}/Makefile"
+  write_source_rule "cxx" "${a}.o" "${src}" "${src_flags}"
 done
 for a in ${LexerParser_CXX_SOURCES}; do
-  src=`cmake_escape "${cmake_source_dir}/Source/LexerParser/${a}.cxx"`
+  src=`cmake_escape_artifact "${cmake_source_dir}/Source/LexerParser/${a}.cxx"`
   src_flags=`eval echo \\${cmake_cxx_flags_\${a}}`
-  echo "${a}.o : ${src} ${dep}" >> "${cmake_bootstrap_dir}/Makefile"
-  echo "	${cmake_cxx_compiler} ${cmake_cxx_flags} ${src_flags} -c ${src} -o ${a}.o" >> "${cmake_bootstrap_dir}/Makefile"
+  write_source_rule "cxx" "${a}.o" "${src}" "${src_flags}"
 done
 for a in ${LexerParser_C_SOURCES}; do
-  src=`cmake_escape "${cmake_source_dir}/Source/LexerParser/${a}.c"`
-  echo "${a}.o : ${src} ${dep}" >> "${cmake_bootstrap_dir}/Makefile"
-  echo "	${cmake_c_compiler} ${cmake_c_flags} -c ${src} -o ${a}.o" >> "${cmake_bootstrap_dir}/Makefile"
+  src=`cmake_escape_artifact "${cmake_source_dir}/Source/LexerParser/${a}.c"`
+  write_source_rule "c" "${a}.o" "${src}" ""
 done
 for a in ${KWSYS_C_SOURCES}; do
-  src=`cmake_escape "${cmake_source_dir}/Source/kwsys/${a}.c"`
-  src_flags=`eval echo \\${cmake_c_flags_\${a}}`
-  echo "${a}.o : ${src} ${dep}" >> "${cmake_bootstrap_dir}/Makefile"
-  echo "	${cmake_c_compiler} ${cmake_c_flags} -DKWSYS_NAMESPACE=cmsys ${src_flags} -c ${src} -o ${a}.o" >> "${cmake_bootstrap_dir}/Makefile"
+  src=`cmake_escape_artifact "${cmake_source_dir}/Source/kwsys/${a}.c"`
+  src_flags="`eval echo \\${cmake_c_flags_\${a}}` -DKWSYS_NAMESPACE=cmsys"
+  write_source_rule "c" "${a}.o" "${src}" "${src_flags}"
 done
 for a in ${KWSYS_CXX_SOURCES}; do
-  src=`cmake_escape "${cmake_source_dir}/Source/kwsys/${a}.cxx"`
-  src_flags=`eval echo \\${cmake_cxx_flags_\${a}}`
-  echo "${a}.o : ${src} ${dep}" >> "${cmake_bootstrap_dir}/Makefile"
-  echo "	${cmake_cxx_compiler} ${cmake_cxx_flags} -DKWSYS_NAMESPACE=cmsys ${src_flags} -c ${src} -o ${a}.o" >> "${cmake_bootstrap_dir}/Makefile"
+  src=`cmake_escape_artifact "${cmake_source_dir}/Source/kwsys/${a}.cxx"`
+  src_flags="`eval echo \\${cmake_cxx_flags_\${a}}` -DKWSYS_NAMESPACE=cmsys"
+  write_source_rule "cxx" "${a}.o" "${src}" "${src_flags}"
 done
 if test "x${bootstrap_system_libuv}" = "x"; then
   for a in ${LIBUV_C_SOURCES}; do
-    src=`cmake_escape "${cmake_source_dir}/Utilities/cmlibuv/${a}"`
-    echo "uv-`cmake_obj ${a}` : ${src} ${dep}" >> "${cmake_bootstrap_dir}/Makefile"
-    echo "	${cmake_c_compiler} ${cmake_c_flags} ${uv_c_flags} -c ${src} -o uv-`cmake_obj ${a}`" >> "${cmake_bootstrap_dir}/Makefile"
+    src=`cmake_escape_artifact "${cmake_source_dir}/Utilities/cmlibuv/${a}"`
+    write_source_rule "c" "uv-`cmake_obj ${a}`" "${src}" "${uv_c_flags}"
   done
 fi
-echo '
+if test "${cmake_bootstrap_generator}" = "Ninja"; then
+  if test "x${bootstrap_system_jsoncpp}" = "x"; then
+    for a in ${JSONCPP_CXX_SOURCES}; do
+      src=`cmake_escape_artifact "${cmake_source_dir}/Utilities/cmjsoncpp/${a}"`
+      write_source_rule "cxx" "jsoncpp-`cmake_obj ${a}`" "${src}" "${jsoncpp_cxx_flags}"
+    done
+  fi
+  if test "x${bootstrap_system_librhash}" = "x"; then
+    for a in ${LIBRHASH_C_SOURCES}; do
+      src=`cmake_escape_artifact "${cmake_source_dir}/Utilities/cmlibrhash/${a}"`
+      write_source_rule "c" "rhash-`cmake_obj ${a}`" "${src}" ""
+    done
+  fi
+fi
+if test "${cmake_bootstrap_generator}" = "Ninja"; then
+  echo "
+rule rebuild_cache
+  command = cd \"${cmake_binary_dir}\" && \"${cmake_source_dir}/bootstrap\" --generator=\"${cmake_bootstrap_generator}\"
+  generator = 1
+build build.ninja : rebuild_cache
+" >> "${cmake_bootstrap_dir}/build.ninja"
+else
+  echo "
 rebuild_cache:
-	cd "${cmake_binary_dir}" && "${cmake_source_dir}/bootstrap"
-' >> "${cmake_bootstrap_dir}/Makefile"
+	cd \"${cmake_binary_dir}\" && \"${cmake_source_dir}/bootstrap\" --generator=\"${cmake_bootstrap_generator}\"
+" >> "${cmake_bootstrap_dir}/Makefile"
+fi
 
 # Write our default settings to Bootstrap${_cmk}/InitialCacheFlags.cmake.
 echo '
@@ -1715,10 +1932,15 @@ fi
 echo "---------------------------------------------"
 
 # Run make to build bootstrap cmake
+if test "${cmake_bootstrap_generator}" = "Ninja"; then
+  ninja_v=-v
+else
+  ninja_v=
+fi
 if test "x${cmake_parallel_make}" != "x"; then
-  ${cmake_make_processor} ${cmake_make_flags}
+  ${cmake_make_processor} ${cmake_make_flags} ${ninja_v}
 else
-  ${cmake_make_processor}
+  ${cmake_make_processor} ${ninja_v}
 fi
 RES=$?
 if test "${RES}" -ne "0"; then
-- 
GitLab