generator expression, target_compile_features

Hi,
I am using an interface library with generator expressions to set specific options that can be consumed by several projects of mine.

As far as I can judge it works as expected, for example:

target_link_options(${target} INTERFACE
    $<$<OR:$<LINK_LANG_AND_ID:C,GNU>,$<LINK_LANG_AND_ID:CXX,GNU>>:-Wl,--no-undefined>
    $<$<OR:$<LINK_LANG_AND_ID:C,Clang>,$<LINK_LANG_AND_ID:CXX,Clang>>:-Wl,-undefined,error>
    )

and

target_compile_options(${target} INTERFACE
    -Werror=switch
    )

No, I would like to set the C standard for C projects and the C++ standard for C++ projects.

My intention has been to use target_compile_features for that approach.

    target_compile_features(${target} INTERFACE
        $<$<COMPILE_LANGUAGE:C>:c_std_17>
        )

    target_compile_features(${target} INTERFACE
        $<$<COMPILE_LANGUAGE:CXX>:cxx_std_17>
        )

But this does not work at least for CMake version 3.24.2.

I got this error:

  Error evaluating generator expression:

    $<COMPILE_LANGUAGE:C>

  $<COMPILE_LANGUAGE:...> may only be used to specify include directories,
  compile definitions, compile options, and to evaluate components of the
  file(GENERATE) command.

I can workaround the error using target_compile_options

    target_compile_options(${target} INTERFACE
        $<$<COMPILE_LANGUAGE:C>:-std=c17>
        )

    target_compile_options(${target} INTERFACE
        $<$<COMPILE_LANGUAGE:CXX>:-std=c++17>
        )

But I assume I will have to use also the compiler ID some time to handle different ways (arguments) to use the compiler specific way to set the standard.

Can you explain me why target_compile_features is not working or what I am doing wrong?

As the error message clearly explains: the generator expression $<COMPILE_LANGUGE> is not supported for features specification.

But, anyway, generator expressions are not needed in your example. So:

target_compile_features(${target} INTERFACE c_std_17 cxx_std_17)

is perfectly valid.

@marc.chevrier Thank you for your answer.
Sure this is what the error message describe, but it does not explain “why”.

  • target_compile_features allows the usage of generator expressions (https://cmake.org/cmake/help/latest/command/target_compile_features.html)
  • $<COMPILE_LANGUAGE:...> is allowed in generator expressions
  • the message states that it is allowed to be use for … compile options (no word about compile features)
  • I can “set the same result” using compile options instead of compile features

So my question is perhaps more about what is the reason for the limitation.

I did not test it in the following environment, but:
There are toolchains that provides a C compiler but not a C++ compiler. I fear forcing the compile feature cxx_std_17 for C only code / projects could result in a failure.

My intention has been to use the generator expressions for a library interface that set C stuff for C usage (compiler) and C++ stuff for C++ usage (compiler) only.

I don’t know why it is not supported for features. Maybe it’s just an oversight…

Maybe @brad.king has the answer.

Anyway, specifying features for a language not used by the project is OK.

IIRC, target_compile_features was added first. The feature names are already language-specific: c_* and cxx_* are independent. Later the $<COMPILE_LANGUAGE> genex was added to support per-language values in other usage requirements, but that is not needed for compile features, so it was not implemented for them. Internally, the set of compile features is computed in contexts that are not specific to any one language. Fixing that may require refactoring code paths to make a language always available when evaluating compile features, and doing so would just slow down generation because we’d have to compute them separately for each language. IMO that is not worth the trouble since we already support per-language compile features implicitly by their names.

Thank you both for your replies and insights.
I will change my interface library to what you suggested.
Thanks

I got a error in a “bigger” project using “your” approach that does not occur using target_compile_options and generator expressions.

To reproduce it, I generated some “constructed” pointless project that contains only a few files:

I got an error that looks like:

CMake Error in CMakeLists.txt:
  No known features for C compiler

  ""

  version .

It seems to be related that the “base” project that includes the other subdirectories is a project only using CXX as language.
I agree that perhaps a specific project should not include other sub directories and there should be an aggregator project, but is this really forbidden?

Whenever a language is enabled anywhere in a project, it needs to be enabled at the highest parent directory common to all directories that enable it. Unfortunately failure to meet this requirement is not well-diagnosed. There are cases besides compile features that fail without it.