I’ve created a GitHub repo to show a minimal reproducible example as requested by @craig.scott in the other thread:
Basically the intent is to have a way to be in control of the version of Ninja my developers on my team use.
And ideally not have them have to download/set Ninja themselves. I want the experience as seemless as possible. Currently this type of workflow works fine since we just have our cmake modules inside our project. The problem arises in separating the cmake code in it’s own GitHub and downloading it using fetchcontent.
C:\coolguy> cmake -S . -B build_ninja -G "Ninja"
CMake Error: CMake was unable to find a build program corresponding to "Ninja". CMAKE_MAKE_PROGRAM is not set. You probably need to select a different build tool.
-- Configuring incomplete, errors occurred!
See also "C:/coolguy/build_ninja/_deps/ninja_issue-subbuild/CMakeFiles/CMakeOutput.log".
CMake Error at C:/Program Files/CMake/share/cmake-3.19/Modules/FetchContent.cmake:977 (message):
CMake step for ninja_issue failed: 1
Call Stack (most recent call first):
C:/Program Files/CMake/share/cmake-3.19/Modules/FetchContent.cmake:1111:EVAL:2 (__FetchContent_directPopulate)
C:/Program Files/CMake/share/cmake-3.19/Modules/FetchContent.cmake:1111 (cmake_language)
C:/Program Files/CMake/share/cmake-3.19/Modules/FetchContent.cmake:1154 (FetchContent_Populate)
CMakeLists.txt:13 (FetchContent_MakeAvailable)
-- Configuring incomplete, errors occurred!
C:\coolguy>
So FetchContent is doing its own logic that requires ninja. I don’t know it well enough to say whether that loop can be broken, but it would seem kind of fundamental.
FetchContent needs whatever CMAKE_MAKE_PROGRAM points at to exist, since it uses that tool to do the content population. It seems like in your case you already have a version of Ninja installed, you just want to download a more recent one and use that. This is quite an unusual case and not typically an arrangement I’d recommend. On Windows, I imagine you’d run into problems if you tried to replace the existing tool that is being used to run the sub-build. Saving the updated binary somewhere else and trying to switch the main project to this new location after the configuration processing has already started seems risky.
Maybe the simpler solution is to just have some kind of separate script your devs can run to go and grab the latest Ninja. They should run that script outside of any project processing.
I think writing a CMake script which downloads ninja an places it somewhere would be best. See how CMake does it for CI (in powershell, but CMake code is just less verbose). You can then do:
cmake_minimum_required(VERSION X.Y)
if (NOT EXISTS "${CMAKE_SOURCE_DIR}/.build-tools/ninja.exe")
execute_process(COMMAND "${CMAKE_COMMAND}" -P "${CMAKE_SOURCE_DIR}/.build-tools/get-ninja.cmake")
endif ()
if (NOT CMAKE_MAKE_COMMAND AND CMAKE_GENERATOR MATCHES "Ninja")
set(CMAKE_MAKE_COMMAND "${CMAKE_SOURCE_DIR}/.build-tools/ninja.exe" CACHE FILEPATH "")
endif ()
project(myproject)
I’d just stuff it in a submodule if you really want the hassle of a submodule for a single CMake script and 8 lines of boilerplate. If you already have modules, sounds fine to me .
Basically: bootstrapping is hard; everything needs to start somewhere. You’re digging close to the bottom of this well .
Not trying to resurrect an old thread, but leaving the below comment after ending up here while following links of a recent discussion.
There was work I did for FetchContent which avoided using a sub-build, but I had to revert it after it broke some existing behavior. I still harbour a desire to bring that change back in a form that avoids the previous problems. The performance gains on Windows especially make that highly desirable. As a nice side benefit, it would remove the above-mentioned problem and allow the original pattern discussed in this post to work (download the Ninja build tool via FetchContent before the first project() call).
I don’t know if or when I’ll get a chance to revisit that work for FetchContent, but it is still very much on my radar.