Symlinks on macOS can result in "error: still dirty after 100 tries" when using Ninja


I’ve noticed the following behaviour: when using symbolic links on macOS (11.4 in my case), with CMake 3.20.5 and Ninja 1.10.2 (from homebrew), building can result in “ninja: error: manifest ‘’ still dirty after 100 tries”.

I’ve reduced the issue to the following script to replicate easily. It seems related to physical vs logical path, but I wouldn’t know whether it’s an issue on CMake’s or Ninja’s side. This doesn’t seem to be an issue with Makefiles in case it matters.

#!/usr/bin/env bash

set -eux

rm -rf "project" "build"
mkdir -p "project" "build"

cat >project/CMakeLists.txt <<EOF
cmake_minimum_required(VERSION 3.20)

option(USE_ASAN "Use ASAN" OFF)

add_executable(foo main.cpp)

  message(WARNING "Enable ASan")
  target_compile_options(foo PRIVATE "-fsanitize=address" "-fno-omit-frame-pointer")
  target_link_options(foo PRIVATE "-fsanitize=address")

cat <<EOF >project/main.cpp
int main(int, char const* const*) { return 0; }

# cmake -G "Unix Makefiles" -B "$(pwd)/build" -S "$(pwd)/project"
# No bug with Makefiles.

cmake -G Ninja -B "$(pwd)/build" -S "$(pwd)/project"
cd build
cmake --build .
cmake . -DUSE_ASAN=ON
cmake --build .

cd ../project
ln -s "$(pwd)/../build" build
cd build
cd $(pwd -P) # IMPORTANT
cmake . -DUSE_ASAN=OFF
cmake --build .

# All fine so far!

cd ../project/build
# no cd $(pwd -P) this time.
cmake . -DUSE_ASAN=ON
cmake --build .
# Last build command fails with:
# ninja: error: manifest '' still dirty after 100 tries

It seems running CMake from a logical path different than the physical path corrupts the cache somehow: some variables refer to the logical path. It may be possible to restore the cache to a valid state once this has happened, but I haven’t figured it out.

Happy to provide additional information if needed. Hopefully someone else has a better idea of what’s happening here.

PS: this looks to be a different issue than Infinite re-run loop with CMake 3.5.1 and Ninja 1.10.0 .

This is known. The tracking issue is here. Basically, CMake tries to preserve $PWD if possible for some HPC use cases. Unfortunately, the use case was made at a deep level and has proven a long thread to pull out. If you’re using symlinks for build trees, I recommend using a single way of accessing this path rather than expecting any name of the directory to work equivalently. cd "$(pwd -P)" is probably the best way to do it.

1 Like

Thanks for the link, and glad this is known. Looks involved indeed.

Maybe one day there’ll be a flag to chose the behaviour, or some other kind of solution. I guess I could write a small wrapper for this purpose, but it would need to be generic enough to integrate into my various workflows (shell, IDE integration, etc…). Anyway, I think I’ll avoid symlinks for the time being, it feels not worth the hassle for my needs.

It can’t be a flag because it’s not something someone is going to know how to use properly. The trigger is that $PWD is a different name for pwd and causes CMake to use $PWD as an equivalent name. I use symlinks all the time, but I use realpath to avoid the translation map.

I am having the same issue on Mac OS but without any symlink.
Could this be related?


Unlikely. More information would be helpful to diagnose it. Please open a new discussion thread.

I was trying to create a sample that recreates this issue but somehow it does not happen anymore after rebooting Mac…

Thanks for your answers,