0

I am trying to build a correct CMake structure for a simple project with several nested submodules. Similarly to this post, I am facing a situation where the main executable and one of the submodules both depend on another submodule:

executable_A/
  CMakeListst.txt
  library_B/
    CMakeLists.txt
    library_C/
      CMakeLists.txt
  library_C/
    CMakeLists.txt

Multiple builts of the same target would then result in a cmake error:

add_library cannot create target "library_C" because another target with the
  same name already exists.  The existing target is an interface library
  created in source directory ".....".
  See documentation for policy CMP0002 for more details.

The issue had been closed with the following solution, that consists in cheking if the concerned target had already been built before building it again:

# When include 'C' subproject
if(NOT TARGET library_C)
    add_subdirectory(C)
endif()

I agree with one of the commenters of the original posts in thinking that it is not a satisfactory solution in every case: in the (unlikely) case of executable_A and library_B depending on different versions of library_C, a mismatch would occur. Is there a way, using submodules, of avoiding this scenario ? Is it possible, for example, to "rename" the library_C target built from library_B to library_C_B, so that no naming conflicts occur ?

Louis
  • 83
  • 6
  • If the lib is your own adding a variable `set(MYLIBC_TARGET_NAME library_c CACHE STRING "library c target name")` which can be overwritten before `add_subdirectory` via `set(... CACHE ... FORCE)`. Other than that I don't see this being part of a single cmake project. You could of couse build the lib as separate project and import it, but usually find modules/package configuration scripts are not written in a way that allows to import targets via version-specific names, so you may need to provide your own find module. – fabian Oct 11 '22 at 16:30

1 Answers1

0

Seems a good use case for CMake interface libraries:

An interface library is a CMake construct that doesn't produce any build artifacts itself but provides dependencies to other targets. So you can define the dependencies once and share them across multiple targets without conflicting names.

In library_C/CMakeLists.txt, you define an interface library:

# library_C/CMakeLists.txt
add_library(library_C INTERFACE) target_include_directories(library_C INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})

In library_B/CMakeLists.txt, add the library_C submodule as a dependency:

# library_B/CMakeLists.txt
add_subdirectory(library_C)
add_library(library_B ...)
target_link_libraries(library_B library_C)

This way, the library_C target becomes an interface library that only specifies include directories but doesn't create any build artifacts. When library_B depends on library_C, it will use the interface provided by library_C without conflicting names.

This way, you can have multiple dependencies on library_C without the need to rename the library. Each target can independently link to library_C and use the appropriate version of the submodule. Hope it helps you!

Lincoln
  • 53
  • 6