Most correct way to deal with a header that configures a source library?

Hi all. I had a question about what the most correct way to approach a source code arrangement that I encounter now and again, and how to deal with it in cmake.

I am trying to self-educate on CMake after having a fair amount of success with it for embedded (microcontroller) development after switching to CLion from vscode. So, maybe this is an obvious beginner’s stumble.

In this context, I frequently have source libraries that are configured by a header file.
In this case: The FreeRTOS kernel has a FreeRTOSConfig.h that is broadly included, and sets the RTOS heap size (plus the availability of a bunch of features).

Given that this is for MCU, the entire application is statically linked and is one monolithic binary.

The organizational issue that I am not sure how to tackle is:
Is a configuration header a part of the “application” code? Or the “library” code?

This is one approach I have had some success with is to make the config its own “interface”:

add_library(FreeRTOS_Config INTERFACE)
add_custom_target(FreeRTOS_Config.headers SOURCES Inc/FreeRTOSConfig.h)
target_include_directories(FreeRTOS_Config INTERFACE ${PROJECT_SOURCE_DIR}/Inc)
target_link_libraries(FreeRTOS_Config INTERFACE FreeRTOS_kernel)

And separately provide the kernel as a library, e.g.

#### FreeRTOS Kernel ####
# Note: the CMSIS RTOS layer is bundled in this library
add_library( FreeRTOS_kernel STATIC
        Middlewares/Third_Party/FreeRTOS/Source/include/croutine.h
        Middlewares/Third_Party/FreeRTOS/Source/include/deprecated_definitions.h
        # etc
 )
target_include_directories( FreeRTOS_kernel PUBLIC
        Middlewares/Third_Party/FreeRTOS/Source/include
        #etc
 )

Ultimately, the issue that got me tripped up here is:
I later declare several executables from one code base (main app, unit testing variant, etc). When I set a target_compile_option on one of those executables, e.g.
target_compile_definitions( app.elf PUBLIC -DDEBUG )
I find that that preprocessor definition is not present when the FreeRTOS_kernel library is built on its own.

As far as I can figure, the header file is effectively logically part of the application (and thus the executable, AND multiple executables may use different variations of the config header), but that now means that the library would depend on the app, which does not seem correct.

Any insights here? Man, I should have learned “real software engineering” somewhere along the way …

Correct. Usages of a library changing the library itself is not something CMake supports (or is likely ever to). It just makes resolving “what is this library” a hard question when it morphs based on how it is used.

I would make a FreeRTOS_config target which brings in the header and is where such -DDEBUG flags gets attached. Anything which cares links to this and the flags come along for the ride. There are probably other ways. A few embedded developers are on this Discourse, but they’ll have to weigh in.