Manually setting `CMAKE_MAKE_PROGRAM` before calling `project()`

Assuming the generator is Ninja and there is no system-wide installation of ninja (i.e. not in PATH), consider the following code:

# Doing work to download/install a pinned ninja version in here.
set(CMAKE_MAKE_PROGRAM "/path/to/ninja" CACHE FILEPATH "Path to ninja binary" FORCE)

project(project_name LANGUAGES C CXX)

Right now this works because the generator information is not used until the project() invocation - specifically the set_languages() part - and setting CMAKE_MAKE_PROGRAM will cause the generator initialization to skip looking for a binary in PATH.

Is this expected behavior? Is it something that I can keep relying on? Put another way, in the future, might CMake decide to set up the generator earlier, say, before the main CMakeLists.txt is parsed? AFAICT, this behavior is not documented anywhere right now. Should it be?

I wouldn’t say it is guaranteed to remain safe into the future, but it is unlikely to become unsafe. I would say that you shouldn’t put FORCE there though, it stops the developer from providing their own path to the build tool. FWIW, I wouldn’t try to set CMAKE_MAKE_PROGRAM directly in the project at all. It is meant to be something the user is responsible for if they are not putting the build tool on the PATH. If you’re using CMake presets, there may be an argument to set CMAKE_MAKE_PROGRAM there.

1 Like

Thanks for getting back to me.

The idea here is to make the build more hermetic and reproducible by pinning the generator version dependency, hence overriding the environment information. I take it a better way to do so would be to install the prebuilt separately and provide it to CMake via CMAKE_MAKE_PROGRAM.

Yes, that’s what I would recommend. The user should be in control of providing that CMAKE_MAKE_PROGRAM variable, but putting it in a CMake preset would satisfy that (users can always override a preset with a -D command-line option).