cmake.check_cache deleted during generation when using cmake_file_api (Xcode)

We have recently added functionality to our build system that involves a call to cmake_file_api(QUERY API_VERSION 1 CODEMODEL 2).

Since adding this call we are seeing the following in the build output when triggering a build in Xcode after a glob mismatch failure in ZERO_CHECK (i.e. adding/removing a file to/from the project):

...
-- Configuring done (1.5s)
-- Generating done (0.6s)```
make: *** Deleting file `/XXXXXXXXXX/build/cmake/CMakeFiles/cmake.check_cache'
make: *** [/XXXXXXXXXX/build/cmake/CMakeFiles/cmake.check_cache] Interrupt: 2
...

The build is stopped by Xcode a couple of moments later, and we have to run cmake generation manually from the command line in order to get cmake.check_cache to be regenerated and get builds running from within Xcode again. Thereafter the build runs OK (until we trigger a GLOB mismatch, which gets us back to the aforementioned state).

Removing the cmake_file_api(QUERY API_VERSION 1 CODEMODEL 2) call ‘fixes’ this (but breaks our newly introduced mechanism that relies on it). In this case the cmake.check_cache file is there.

So what could possibly be deleting the cmake.check_cache file when the file API query is run and why?

Any help would be greatly appreciated.

The issue is caused because CMake writes reply files as a last step during its execution, i.e. after project generation.

When starting a build in Xcode the ZERO_CHECK target is built first. It’s purpose is to detect any change that could affect the generated project file. This includes changes to the CMake scripts and also possible changes in glob results. ZERO_CHECK is implemented partly in Make (for detecting source files changes) and partly in CMake (for detecting glob changes). It’s entry point is a Makefile, which defines the rule and marker file cmake.check_cache responsible for rerunning the source CMake script if a change is detected in one of the dependency.

What happens here is that a glob change triggers a CMake rerun. This first generates the new project then starts writing the reply files because the script has a cmake_file_api call. But meanwhile Xcode detects the change in the project file thus cancels the build which also interrupts ZERO_CHECK’s run script phase and with that all the child processes: make and CMake. Make has a built-in detection for interruptions to avoid leaving a corrupted state behind. During this clean-up sequence it deletes the target file of a failed or interrupted rule, cmake.check_cache in this case. That’s what indicated in the make: *** Deleting file '/XXXXXXXXXX/build/cmake/CMakeFiles/cmake.check_cache' message.

I don’t know how to avoid this besides of modifying the sequence in CMake’s source. As an alternative, but quite hacky, solution the CMake script could recursively rerun itself (after setting a conditional flag) using a separate build tree only for producing the reply files.

1 Like

I just wanted to add, that we noticed this behavior on faster machines only, which also reinforces our belief about what is mentioned in @spacecadet 's post.

Updating the pbxproj file as the final step of generation (after the reply to the file API query is written) would probably alleviate the problem (as @spacecadet alluded to when he mentioned "modifying the sequence in CMake’s source) .

For reference, CMake Issue 22605 discusses this race.

For completeness I also posted a feedback ticket to Apple on how Xcode could have a setting on custom scripts that would defer the project reload until the script runs to completion.

Feedback ticket is here: Feedback Assistant
(I’m not sure the ticket is visible publicly)
I don’t have high hopes on Apple implementing this though :frowning: