Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I manually use CMake's cpp file dependency-scanner in my cmake code?

I am trying to add a custom target with CMake that executes one command for each given .cpp file. The command should only be re-executed when the source file itself or one of the included source files changes. AFAIK to achieve this I need a list of all the included files and add them to the DEPENDS option of the add_custom_command() calls that belong to my custom target.

So is there a built-in way to get that list of included files?

I know about the IMPLICIT_DEPENDS option of the add_custom_command() function but it only works for Makefile generators. I would like to make this work for all generators.

Thank you for your time

Edit:

As requested I will post some cmake code to show what I want to achieve. I want to add a custom target, that runs clang-tidy on all the given .cpp files. When incrementally building the custom target the clang-tidy commands should be re-run whenever a .cpp file or one of its directly or indirectly included header files is changed. Just like re-runs of the compiler are handled.

# ----------------------------------------------------------------------------------------
# mainTargetName The name of the target that shall be analyzed
# files A list of all the main targets .cpp files
#
function( addStaticAnalysisTarget mainTargetName files )

    set(targetName runStaticAnalysis_${mainTargetName})
    set(command "clang-tidy-4.0 -checks=* -p ${CMAKE_BINARY_DIR}")

    foreach( file ${files}  )

        get_filename_component( baseName ${file} NAME_WE)
        set(stampFile ${CMAKE_CURRENT_BINARY_DIR}/analyze_${baseName}.stamp )
        set(fullFile ${CMAKE_CURRENT_SOURCE_DIR}/${file})
        set(commandWithFile "${command} ${fullFile}")
        separate_arguments_for_platform( commandList ${commandWithFile})

        add_custom_command(
            OUTPUT ${stampFile}
            DEPENDS "${fullFile}"
            IMPLICIT_DEPENDS CXX "${fullFile}"
            COMMAND ${commandList}
            COMMAND cmake -E touch "${stampFile}"       # without creating a file as a touch-stone the command will always be re-run.
            WORKING_DIRECTORY ${CPPCODEBASE_ROOT_DIR}
            COMMENT "${commandWithFile}"
            VERBATIM
        )

        list(APPEND stampFiles ${stampFile})

    endforeach()
    set_source_files_properties(${stampFiles} PROPERTIES GENERATED TRUE)   # make the stamp files known to cmake as generated files.

    add_custom_target(
        ${targetName}
        DEPENDS ${stampFiles}
    )

endfunction()

The problem with that is, that it does not seem to work. When I change included files clang-tidy is not re-run for the affected files. I used the "Unix Makefile" generator for this example so it should work at least with make. Any hints why it doesn't?

My hopes where that I could achieve the desired behavior for all generators by somehow getting the file-dependencies at cmake time and then adding them to the ''''DEPENDS'''' list. But the dependency scanning must be done each time the command is run, so it can not be done at cmake time. This means that the scanning must be implemented by cmake which it currently is not.

A guy with similar problems: https://gitlab.kitware.com/cmake/cmake/issues/16830

Edit 2: I think the problem that the IMPLICIT_DEPENDS option was not working was because I did not use correct filenames. I changed that in the code snipped, but I have not yet tested if it works in the project.

like image 859
Knitschi Avatar asked Nov 08 '22 23:11

Knitschi


1 Answers

I think the answer to my question is ...

No, you can not use cmakes dependency scanner in the cmake code.

That makes sense, because this problem can not be solved at cmake time, because the dependencies of a .cpp file may change without cmake being re-run. The problem must be solved within cmake itself at make time. This is done when using the IMPLICIT_DEPENDS option.

Also, I tried to solve a Problem that I did not really have, because at this point I can only run clang-tidy on linux anyways. However, clang-tidy may become available on windows as well and then I may have the problem again.

To sum the comments up:

  • Tambre stated that CMake is not a compiler and therefore can not do that. I think this is wrong. According to this article, CMake can parse cpp include dependencies because make has no such dependency searcher itself. That was news to me, but I mostly live on Windows so I am not that familiar with make. It could also be possible that in the meantime make was extended to do its own dependency searching. Also this explains why the IMPLICIT_DEPENDS option is only available for make.

  • Florian pointed out that it is not necessary to create an own custom target for running clang-tidy. Instead, one can use the CXX_CLANG_TIDY target property to run clang-tidy for each file after compiling it. This means however, that static-analysis can not be separated from the build which could lead to inacceptable buildtimes.

  • There is the cmake -E cmake_depends command line, that could be used to retrieve dependencies at cmake time. But as stated above, I erroneously thought that I needed the dependencies at cmake time, while I needed them at runtime.

  • The IMPLICIT_DEPENDS options did not work because I had an error in my cmake code.

like image 107
Knitschi Avatar answered Nov 14 '22 23:11

Knitschi