Generated files not found in symlink folder

Hi there, I am am new to CMake. I followed the below style to create a CMake project to generate source and build. It works fine when build in the real path. However, I also need to run the build in a symlink path. When I ran in that path, I saw the errors like this

WriteAuxiliaryFile /SYMBLINKPATH/out/xxx.build/Debug/xxx2.build/s=Script-xxxxxxxx.sh
 cd /REALPATH
bin/sh -c /SYMBLINKPATH/out/xxx.build/Debug/xxx2.build/s=Script-xxxxxxxx.sh 

CompileC /SYMBLINKPATH/out/xxx.build/Debug/xxx2.build/Objects-normal/x86_64/gen_xxx.o /REALPATH/gen/gen_xxx.cpp
cd /REALPATH
clang -x c++ -target x86_64-apple-macos11.1 .... -c /REALPATH/gen/gen_xxx.cpp -o /SYMBLINKPATH/out/xxx.build/Debug/xxx2.build/Objects-normal/x86_64/gen_xxx.o 
error: Build input file cannot be found: '/REALPATH/gen/gen_xxx.cpp'

It looks the generated file is not there yet, but I checked the folder, it has been generated. If I run the build second time, then works. Any item to fix it? Also If I add -T buildsystem=1, it works too.

Part of CMakeLists.txt:

# Create generated source and header files (e.g. for MIB, CFG and SOAP)
INCLUDE( ${CMAKE_SOURCE_DIR}/imt/generated.cmake )

# Include list of generated files to build the library
INCLUDE( ${CMAKE_CURRENT_BINARY_DIR}/generated/generated_srcs.cmake )

# Define a target shared object library
ADD_LIBRARY( mibfactory SHARED ${GENERATED_SRCS} )

# Add dependencies between library and generated files
ADD_DEPENDENCIES( mibfactory build_mib )

Part of imt/generated.cmake:

add_custom_command(
  OUTPUT  ${CMAKE_BINARY_DIR}/imt/build_mib
  COMMAND ruby imt.rb ${IMDL_XML} ${MIB_NS} ${ROOT}
  DEPENDS ${RUBY_FILES}
  DEPENDS ${MIB_RUBY_FILES}
  WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/imt
  VERBATIM
)

# Initially create generated files, if they don't yet exist
IF( NOT EXISTS ${CMAKE_BINARY_DIR}/build_mib )
  MESSAGE( "*** Create generated MIB files ***" )
  EXECUTE_PROCESS(
    COMMAND ruby imt.rb ${IMDL_XML} ${MIB_NS} ${ROOT}
    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/imt
  )
ENDIF()

Example for generated_srcs.cmake:

GENERATED_SRCS(
  file_hjkfdk.cpp
  file_kjwerui.cpp
  file_wqeierp.cpp
  ...
)

Hi! First, I fixed up some of the formatting in your post to make it easier to read (syntax highlighting and monospace fonts).

Some notes that I see:

  • When there is a symlink around, all commands within the build must refer to files which exist in that path by one and only one of the real name (preferred) or any of the symlink names. Many build tools just use path comparison to determine equivalency; asking the filesystem every time is a huge burden that is not normally done.
  • Running a custom command during configuration indicates that you probably have some kind of missing dependency specification. I would get rid of that if (NOT EXISTS) block for the MIB files and just let the build (the custom command) take care of it for you.

Thanks for format editing. It looks much better.

  1. I used
    get_filename_component( root “${CMAKE_CURRENT_LIST_DIR}” REALPATH ) to get root path with symlink resolved. All the following paths were derided based the root path to avoid confusion. However, as seen in the log, it still show symlink path in some place. Don’t know how to configure that to make all to use the real path.

  2. I removed the IF NOT EXISTS part, but make no difference. The point here the code runs well in some scenarios but failed in the scenario using symlink path.
    a. Run in real path, it worked no issue
    cd \REALPATH
    cmake -G Xcode … && cmake --build ./ --config Debug
    b. Run in symlink path, it failed
    cd \SYMLINKPATH
    cmake -G Xcode … && cmake --build ./ --config Debug
    error: Build input file cannot be found: ‘/REALPATH/gen/gen_xxx.cpp’
    c. Run in symlink path twice, it works.
    cd \SYMLINKPATH
    cmake -G Xcode … && cmake --build ./ --config Debug
    error: Build input file cannot be found: ‘/REALPATH/gen/gen_xxx.cpp’
    cmake --build ./ --config Debug
    Build succeed.

    d. Either in real or symlink path, use -T buildsystem=1, works no issue.
    cmake -G Xcode -T buildsystem=1 … && cmake --build ./ --config Debug

From the above observation, it looks the code generated after compiling when using symlink path even though I saw code generation scripts bin/sh -c /SYMBLINKPATH/out/xxx.build/Debug/xxx2.build/s=Script-xxxxxxxx.sh is called before CompileC. Note that parallel build is enabled by default.

I found the generated project.pbxproj always use symlink path. If I manually change it to real path, then the problem solved. Is there any way to configure cmake to generate xcode project file using real path instead of symlink path?

REALPATH behavior is tied up with this historical behavior which permeates everything. Basically some symlink names get “resolved” as the “real” name[1] and REALPATH.

In light of that behavior, the symlink stuff is either unlikely to work reliably or is going to be intermittent based on the internals. I’d just try to work without the symlink path if at all possible.

[1] This is to support setups where there are multiple login nodes into a cluster and each login node mounts the shared space at a unique path, but the /home/foo symlink is the only stable name. The use case got solved at way too deep of a level rather than as a targeted solution.

Found a solution seems work. Basically use symlink path everywhere.

  1. Use get_filename_component ( root “${CMAKE_CURRENT_LIST_DIR }” ABSOLUTE )
  2. set(CMAKE_XCODE_ATTRIBUTE_PROJECT_DIR ${root})
    Checked the generated Xcode project file, now all path changed to symlink path. Also tested to use Real path in a similar way, but not work. It has mixed paths in Xcode project file