Delay in operation of file(GENERATE ...

This little bit of code:

file(GENERATE
     OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/empty_pch.cxx
     CONTENT "/* empty file */")
target_sources(CommonPCH_Lib PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/empty_pch.cxx)

… works perfectly using CMake 3.18.0 in Windows, but using 3.16.2 on Linux it fails:

  Cannot find source file:

    ~/dev//linux/empty_pch.cxx

  Tried extensions .c .C .c++ .cc .cpp .cxx .cu .m .M .mm .h .hh .h++ .hm
  .hpp .hxx .in .txx

If I keep a close eye on the binary directory during configuration, the file appears in the directory about a second after the error message is fired.

Is file(GENERATE … ) meant to be instantaneous, or is there some extra qualifier I can put on it to show the dependency and ensure it’s appeared before trying to add it to the target?

The output of file(GENERATE) is a bit unusual in that, unlike other file() commands, it returns before writing the file. The file is only written out during the generation phase, which is after CMake has processed all the CMakeLists.txt file in the project. That would explain the delay you saw.

I’m intrigued by the path printed for that file. It has an unexpanded ~ at the front and a repeated //, both of which I thought should not be possible in the value of CMAKE_CURRENT_BINARY_DIR, but I can’t be certain. Can you provide a complete, minimal project and the command lines you used to trigger the problem on Linux?

Ah, you got me; I’d doctored the actual path so that I didn’t reveal the name of my project.

The two files attached will reproduce the problem, though in the CMakeLists.txt file you’d need to put the path your own Qt5 installation. I invoke CMake by going to a subdirectory and typing:

cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug

I tried an even simpler example, which didn’t use Qt, and just tried to generate a PCH using C++ standard library headers, but that didn’t reproduce the problem - the file seemed to get generated in time.

For what it’s worth, the thing I’m trying to achieve here is to generate a library that does nothing except to compile a precompiled header for the Qt libraries I want to use. In CMake 3.16, the file(GENERATE …) step isn’t actually necessary, because automoc generates an empty mocs_compilation.cpp file which is all that the compiler needs. As of 3.18, though (which I now use on Windows), the order of events has changed and automoc isn’t run until later, so it’s necessary to generate an empty .cpp file manually. See https://gitlab.kitware.com/cmake/cmake/-/issues/20968 for all the gory details.

CMakeLists.txt (1016 Bytes) CommonPCH.h (299 Bytes)

You could try using the new file(CONFIGURE) command (in 3.18+). It creates the file at configure time, instead of generation time, which is similar to configure_file() and file(WRITE).

All right, this seems to get the job done on both platforms:

if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.18.0") 
    file(CONFIGURE
         OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/empty_pch.cxx
         CONTENT "/* empty file */")
    target_sources(CommonPCH_Lib PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/empty_pch.cxx)
endif()

Since it is an essentially empty file with fixed content, file(WRITE) could be used rather than file(CONFIGURE). The former works for any CMake version.

Good point. In this case it makes little difference, though, since for versions < 3.18.0 it’s not necessary anyway; I can just rely on automoc to generate the empty .cpp file that I need.