Manually simulating target namespaces for building multi-architecture repos

This is an issue which I have since several years now and which always kept preventing me from transitioning to cmake for a larger STM32 project. I never found a reasonable solution so far, until I recently found a semi-acceptable work around, actually a very straight forward one.

The structure looks like this

shared
 | LibA
 | LibB
 | ... (about 30 libraries)
stm32f7xx
 | BoardA
 | BoardB
stm32f4xx
 | BoardC

I have everything set up and running, but I need to comment in/out the corresponding definitions

# only build stm32f7xx targets
set(MCU STM32F765xx)
add_definitions(-DSTM32F765xx)

# only build stm32f4xx targets
#set(MCU STM32F407xx)
#add_definitions(-DSTM32F407xx)

add_subdirectory(shared)
add_subdirectory(stm32f7xx)
add_subdirectory(stm32f4xx)

The BoardX projects are wrapped in a conditional clause to only build when the proper MCU is configured. So this way I can use make BoardA BoardB but not make BoardC.

I’ve tried a lot but I couldn’t find a proper way to build the shared directory twice without getting target name collisions. I tried around a lot with ExternalProject_Add, but I couldn’t get it to work. I tried using execute_process to call a secondary cmake instance, which I don’t like very much.

I think the only cmake feature which might help would be Project-level namespaces as proposed in #22687.
So the only workaround I found so far is manually simulating namespaces, but it is a bit tedious. It effectively looks like this in EVERY project in any subdirectory, except the top level one.

project(${NS}LibA)
...
## dependencies
target_link_libraries(${PROJECT_NAME} ${NS}LibB)
...
add_library(${NS}Lib::LibA ALIAS ${PROJECT_NAME})

and then using it like this

set(NS STM32F4xx)
set(STM32_FAMILY STM32F4xx)
add_subdirectory(shared shared_stm32f4xx)

add_subdirectory(BoardA)

set(NS STM32F7xx)
set(STM32_FAMILY STM32F7xx)
add_subdirectory(shared shared_stm32f7xx)

add_subdirectory(BoardB)

This way I can just type

$ make BoardA BoardC
[ 33%] Built target STM32F4xxLibB
[ 66%] Built target STM32F4xxLibA
[100%] Built target BoardA
[ 33%] Built target STM32F7xxLibB
[ 66%] Built target STM32F7xxLibA
[100%] Built target BoardC

After month of procrastination because of this issue, I think I found an acceptable solution, although it requires to modify all CMakeLists it is something which can even be done automatically via Search&Replace. What do you think, any better suggestions how I could have solved this problem?

I really hope one day we get target namespaces, without knowning the details of the cmake code it looks to be something which would not require tremendous changes, but I know the devil is always in the detail.

IMHO you should use different build directories for each build.

Your way only works because the compiler binary happens to be the same.

You could use presets to make the build flavor easily selectable.

Thanks for your comment. I haven’t worked with presets so far, but after having played around with it a bit I like it very much. But unfortunately the best I could get is

cmake --preset=f4 && cmake --build --preset=f4 --target BoardA
cmake --preset=f7 && cmake --build --preset=f7 --target BoardC

While being by far shorter and better than I expected I still would prefer a way to build all boards at once, especially as I really like the total build progress percentage output of cmake.

So if there is any way to combine multiple builds I would be highly interested.