I have a C++ CMake project with 3 targets:
- An Interface Library target
MyProjectInterfaces(defines some interfaces in hpp files) - Library
MyProjectFoo(implements 1/2 of the interfaces in MyProjectInterfaces) - Library
MyProjectBar(implements the other 1/2 of interfaces in MyProjectInterfaces)
Downstreams projects that consume my library may want to implement the MyProjectInterfaces interfaces themselves, or use the Foo implementations, or the Bar implementations, or both.
I want to add some compile features/options/definitions to all of the targets in my project while minimizing code duplication. I know of two ways to do this.
METHOD 1: The easiest way is to add them to MyProjectInterfaces with INTERFACE scope:
set(DEBUG_COMPILE_OPTIONS
-Wall -Werror
)
set(RELEASE_COMPILE_OPTIONS
)
target_compile_features(MyProjectInterfaces INTERFACE
cxx_std_17
)
target_compile_definitions(MyProjectInterfaces INTERFACE
SDK_VERSION_MAJOR=${CMAKE_PROJECT_VERSION_MAJOR}
SDK_VERSION_MINOR=${CMAKE_PROJECT_VERSION_MINOR}
SDK_VERSION_PATCH=${CMAKE_PROJECT_VERSION_PATCH}
)
target_compile_options(MyProjectInterfaces INTERFACE
$<$:${DEBUG_COMPILE_OPTIONS}>
$<$:${RELEASE_COMPILE_OPTIONS}>
)
METHOD 2: Alternatively I can change the scope to PRIVATE, wrap the target_compile_XXX calls in a macro/function, and call it for each target.
macro(set_options myTarget)
target_compile_features(${myTarget} PRIVATE
cxx_std_17
)
target_compile_definitions(${myTarget} PRIVATE
SDK_VERSION_MAJOR=${CMAKE_PROJECT_VERSION_MAJOR}
SDK_VERSION_MINOR=${CMAKE_PROJECT_VERSION_MINOR}
SDK_VERSION_PATCH=${CMAKE_PROJECT_VERSION_PATCH}
)
target_compile_options(${myTarget} PRIVATE
$<$:${DEBUG_COMPILE_OPTIONS}>
$<$:${RELEASE_COMPILE_OPTIONS}>
)
endmacro()
# This probably won't work or be necessary because its an interface library target?
# set_options(MyProjectInterface)
# Set compile options on actual compiled libraries
set_options(MyProjectFoo)
set_options(MyProjectBar)
As far as I'm aware both methods propagate all the definitions/options I want to each target in my project. However, METHOD 1 will also propagate these options/definitions to consuming projects. Is that desirable?
There's lots of documentation on the internet on how to pass the PRIVATE/PUBLIC/INTERFACE arguments into target_compile_XXX(...), but I have been able to find very little on how/when to choose between them.