I have a project where we have multiple threading libraries: Threading_Linux, Threading_Baremetal, etc. They all implement the same threading interfaces (function declarations and C++ interfaces), declared in it’s own INTERFACE
Threading library. In turn, our business logic libraries (or other higher level libraries) will only link to Threading, instead of a specific platform Threading implementation. Then, when our application is assembled it will look something like below.
# Threading
add_library(Threading INTERFACE)
target_sources(Threading INTERFACE IThreading.h)
target_include_directories(Threading INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
# Threading_Linux
add_library(Threading_Linux)
target_sources(Threading_Linux PRIVATE Threading_Linux.h Threading_Linux.cpp)
target_include_directories(Threading_Linux PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(Threading_Linux PUBLIC Threading)
# BusinessLogic_Foo
add_library(BusinessLogic_Foo)
target_sources(BusinessLogic_Foo PRIVATE Foo.h Foo.cpp)
target_include_directories(BusinessLogic_Foo PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(BusinessLogic_Foo PRIVATE Threading) # Only the interfaces are leveraged
# App
add_executable(App)
target_source(App PRIVATE main.cpp)
target_link_libraries(App
PRIVATE
BusinessLogic_Foo
Threading_Linux
)
I believe link order does become important here such that Threading_Linux needs to be last (as described here.
Is this common practice? Does it violate CMake practices to provide a target (BusinessLogic_Foo) that itself does not have the complete definitions and doesn’t explicitly specify where to find the definition? Would there be a different way to do this? It is beneficial in cross platform systems or if we wanted to inject a fake threading library for testing BusinessLogic_Foo.