Hi all, I have a question about setting usage requirements which depend on platform or compiler. Assume I have a C++ library Foo
such that:
- When consumers link against it on Windows, they must define
FOO_WINDOWS
. - When the consumer is built using GCC or Clang,
-fpersmissive
must be used.
(The above macro/flag are just examples, the question holds for arbitrary macro/option usage requirements).
I want to express these as usage requirements on Foo
. My question is, what are the [dis]advantages of using variable-conditioned settings vs. generator expressions? Basically, should I do this:
if(WIN32)
target_compile_definitions(Foo INTERFACE FOO_WINDOWS)
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES GNU|Clang)
target_compile_options(Foo INTERFACE -fpermissive)
endif()
or this:
target_compile_definitions(Foo INTERFACE $<$<PLATFORM_ID:Windows>:FOO_WINDOWS>)
target_compile_options(Foo INTERFACE $<$<OR:$<CXX_COMPILER_ID:GNU>,$<CXX_COMPILER_ID:Clang>>:-fpermissive>)
My intuition is to use the former (variable-based) approach, since it’s easier to read and I expect it to be faster as well, as it will only be evaluated once, not once per build configuration. (This could add up if dozens of such libraries are involved, each with its own slightly different set of usage requirements).
I understand the advantage of the genex-based approach in situations such as using CUDA, where different compilers can get their hands on the same file. However, when such special cases are not involved and the buildsystem follows CMake’s normal limitation of “one platform, one toolchain”, is there any advantage to one or the other approach?
Also, does the answer change if I were not defining Foo
as part of the build, but writing a package config file for it which could be consumed by the outside world?