Ninja: Compilation of generated Windows Resource .rc file has incorrect dependencies
add_custom_command with the Ninja generator on Windows to invoke mc.exe on an .mc file, to generate an .rc file, to create a resource DLL.
When making changes to the example.mc file, rebuilding only invokes mc.exe, but dependencies that use the generated example.rc file are not rebuilt until I invoke ninja a second time:
> ninja [0.014s 1/1] Generating example.rc, example.hpp, example_MSG00001.bin MC: Compiling D:/repro/example.mc > ninja [0.027s 1/2] Building RC object CMakeFiles\example.dir\example.rc.res Microsoft (R) Windows (R) Resource Compiler Version 10.0.10011.16384 Copyright (C) Microsoft Corporation. All rights reserved. [0.084s 2/2] Linking CXX shared module example.dll
The resulting build.ninja contains this dependency chain:
build example.dll: CXX_MODULE_LIBRARY_LINKER__example CMakeFiles\example.dir\example.rc.res build CMakeFiles\example.dir\example.rc.res: RC_COMPILER__example D$:\repro\build\example.rc || cmake_object_order_depends_target_example build D$:\repro\build\example.rc: CUSTOM_COMMAND cmake_object_order_depends_target_example COMMAND = cmd.exe /c restat = 1 build cmake_object_order_depends_target_example: phony || example.hpp example.rc example_MSG00001.bin build example.rc example.hpp example_MSG00001.bin: CUSTOM_COMMAND ..\example.mc COMMAND = cmd.exe /C "cd /D D:\repro\build && "C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\x64\mc.exe" -b -e hpp -h D:/repro/build -r D:/repro/build D:/repro/example.mc" DESC = Generating example.rc, example.hpp, example_MSG00001.bin restat = 1
I think that D$:\repro\build\example.rc depending on the actual example.rc file in order-only
is the problem, since that tells ninja not to rebuild D$:\repro\build\example.rc if example.rc changes.
IIRC ninja does not try to figure out that two distinct paths refer to the same file (otherwise,
this would produce an error about multiple build statements producing the same file),
so ninja does not discover that D$:\repro\build\example.rc has changed until the next run.
restat = 1 also doesn't help in this case, since it only causes a restat if the command runs.
If CMake instead emitted a phony like this:
build D$:\repro\build\example.rc: phony example.rc
Then targets depending on D$:\repro\build\example.rc would have a real dependency on example.rc,
and would be rebuilt when it changes.
Also, phony build statements don't appear in the build log, unlike the empty CUSTOM_COMMAND which shows up as