0

I'm writing a CMakeLists.txt for a project of mine, and I need to add (under certain conditions which don't matter here) a compiler flag to $CMAKE_CXX_FLAGS (and it doesn't matter that it's C++, it could C, or Fortran or what-not). Now, I can do it this way:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_FLAG_HERE}")

or, to be more modern:

string(APPEND CMAKE_CXX_FLAGS " ${EXTRA_FLAG_HERE}")

but if the flag is already in there, I don't want to add it twice. Now, I could do

if(NOT string(FIND CMAKE_CXX_FLAGS "${EXTRA_FLAG_HERE}")
    string(APPEND CMAKE_CXX_FLAGS " ${EXTRA_FLAG_HERE}")
endif()

Edit: but as @Fred points out, this won't actually avoid duplicates if that flag is introduced by CMake otherwise than through $CMAKE_CXX_FLAGS.

I was hoping there's something "built-in" which adds a flag while assuring no duplication (including being more robust against occurrences of ${EXTRA_FLAG} which within the argument of another flag, e.g. in a -D flag).

So, what do I do?

einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • Which compiler flag? – Cinder Biscuits Dec 26 '18 at 21:18
  • @CinderBiscuits: Not `--std` or one of those things you set with a special CMake variable. – einpoklum Dec 26 '18 at 21:46
  • 2
    Any reason you're avoiding `target_compile_options`? The modern approach to CMake is to model your requirements via properties, which can be scoped, and avoid variables. – Cinder Biscuits Dec 26 '18 at 21:57
  • 1
    You could add an INTERFACE with the given property added under your conditions, and link it to the given targets. In this way, the properties are propagated without having to manage a list of flags. – Cinder Biscuits Dec 26 '18 at 22:03
  • In fact, you may even be able to do it using `target_compile_options` and generator expressions, but with the vagueness given, no one could say. – Cinder Biscuits Dec 26 '18 at 22:07
  • @CinderBiscuits: Let's say I want this to apply throughout my file. Also - can you make your comments into an answer with an example? – einpoklum Dec 26 '18 at 22:10
  • @einpoklum There are plenty examples available on how to use generator expressions. https://stackoverflow.com/questions/46206495/cmake-generator-expressions – fdk1342 Dec 27 '18 at 04:10
  • 1
    @einpoklum There is no built in way to prevent a flag being added twice. Your method won't work if it is a flag that is automatically added by `CMake` as a default flag. – fdk1342 Dec 27 '18 at 04:18
  • You're looking for `if (NOT CMAKE_CXX_FLAGS MATCHES "${EXTRA_FLAG_HERE}")`. But I would in general caution against hard-coding flags into your CMakeLists.txt. It's usually wrong unless every possible build environment is tightly controlled (e.g. warning flags are notorious for being moving targets and `-Werror` is basically guaranteed to bite you). – Alex Reinking Jul 01 '21 at 07:22
  • @AlexReinking: Perhaps make that an answer? Also, you say that "it's usually wrong", but - there's no alternative. I have to set flags somehow, right? So if I use CMake, I set them via cmake. Of course flags might be compiler-dependent and you have to check for that. – einpoklum Jul 01 '21 at 07:27
  • Any time I see a flag in a CMakeLists.txt, rather than a toolchain or preset, alarm bells go off. There are sort of two options with flags (and I'm happy to discuss this with you in chat, btw): either the build _cannot produce a correct binary_ without the flag or _it can_. In the former case, care must be taken to ensure the proposed flag will be applied _exactly_ to the correct set of compilers. In the latter case, the flags should be moved out. – Alex Reinking Jul 01 '21 at 07:31

1 Answers1

1

There are many sources of flags in CMake, not all of which are exposed to the CMakeLists.txt author (e.g. the /SUBSYSTEM:... flags on MSVC).

Some sources, like the target properties are automatically de-duplicated, so there's no need to worry there. In the case of linker flags, de-duplication can actually be an issue, so there's a special syntax for preserving a flag when calling target_link_options: prefix FLAG with SHELL: as in target_link_options(tgt PRIVATE "SHELL:FLAG").

On the other hand, if you want to avoid adding a flag to CMAKE_<LANG>_FLAGS[_<CONFIG>], then you can just do a regex check before adding a flag; for example:

if (NOT CMAKE_CXX_FLAGS MATCHES "-flag")
  string(APPEND CMAKE_CXX_FLAGS " -flag")
endif ()

But unfortunately, there's just no general way to inspect every flag CMake will add to a target's command line during configure time (due to lazily evaluated generator expressions, if for no other reason).

Alex Reinking
  • 16,724
  • 5
  • 52
  • 86