Search code examples
gcccmake

How can I add a command-line options file to CMake compiler flags?


GCC allows for having command-line options passed by a file by @file syntax. Using this the file should be added as prerequisite (aka dependency) to the target.

I'm not finding any reference in CMake docs about argument files, suggesting it's not supported. Or perhaps just takes a little bit more plumbing, e.g. cat file|xargs? Or some way telling CMake explicitly that the file is a prerequisite? I mean "Prerequisite" according to GNU Make terminology. If file contents change I have to rebuild. AKA dependency.

Which is it? And how does it work?


Solution

  • You should just be able to use target_compile_options() or CXX_<LANG>_FLAGS like you normally would.

    Since the flags available for different compilers are usually different, you probably will have one for each compiler you support, in which case you can wrap your target_compile_options() calls with if() blocks based on CMAKE_CXX_COMPILER_ID or the MSVC variable, or use the CXX_COMPILER_ID or X_COMPILER_ID generator expressions to use the right file (if you have multiple files for multiple compilers) for the right compiler.

    However, I've also noticed before when trying this that using file flags like this doesn't automatically add the file as a dependency to the target (the CMake won't add a rule for the target to rebuild if that file changes), so you might need to do that manually like this:

    # wrap this in a function taking `target` as an argument.
    get_target_property(sources ${target} SOURCES)
    set_property(SOURCE ${sources}
      # DIRECTORY "${PROJECT_SOURCE_DIR}" "${PROJECT_BINARY_DIR}"
      TARGET_DIRECTORY ${target}
      APPEND PROPERTY OBJECT_DEPENDS "${PROJECT_SOURCE_DIR}/path/to/flags/file.txt"
    )
    

    The above snippet courtesy of a user in this GitHub issue. It uses the OBJECT_DEPENDS source file property to make every source file of a target depend on the compiler options file. I (and the author of that code snippet) would classify it as a workaround, since it only works for Generators that support OBJECT_DEPENDS. From the CMake docs:

    Specifies a semicolon-separated list of full-paths to files on which any object files compiled from this source file depend. On Makefile Generators and the Ninja generator an object file will be recompiled if any of the named files is newer than it. Visual Studio Generators and the Xcode generator cannot implement such compilation dependencies.

    I'm not sure at what level of the toolchain it would be best to request that such automatic dependency-tracking functionality be added. According some of the Ninja buildsystem maintainers in the above linked GitHub issue, (if my noob brain is understanding the words they're saying correctly :P), it's something that could be handled by compilers when they generate depfiles given a compile comand for a source file. I'm currently too scared to ask compiler maintainers if that's the case. If you're interested in digging onto the part that CMake plays in orchestrating other tools to get dependency tracking for things like header files and the creation of dependency-tracking files ("depfiles"), you can go to your CMake installation's Modules folder and grep for CMAKE_DEPFILE_FLAGS_. Then use "find in files" at https://github.dev/Kitware/CMake. (update: I ended up raising this as a feature-request at the CMake layer: Automatically treat command-line options files (@file) as dependencies of the object file compiled with that option).

    Notes: Visual Studio / MSVC's compiler calls these "command files", gcc doesn't seem to have a particular name for them, and clang calls these "configuration files". They all support similar @file syntax. I'm not sure what the history is with that, but many compilers aim to have levels of compatibility (similar interface to) with GCC.

    That's all. If you're bored and want to read a bit about how CMake does header dependency detection (which is loosely related here on the topic of depfiles), see this other post of mine.