3

I have the following Structure of my Project:

    ├── CMakeLists.txt
    ├── libA
    │   ├── CMakeLists.txt
    │   ├── include
    │   │   └── libA
    │   │       └── my_liba.h
    │   ├── src
    │   │   └── my_liba.cpp
    │   └── test
    ├── libB
    │   ├── CMakeLists.txt
    │   ├── include
    │   │   └── libB
    │   │       └── my_libb.h
    │   ├── src
    │   │   └── my_libb.cpp
    │   └── test
    └── runner
        ├── CMakeLists.txt
        └── src
            └── main.cpp

I would like to achieve the following:

  • Be able to build libA and libB and Runner seperately
  • Be able to build all together.

For the dependency: libB depends on libA and Runner needs libB. How do i have to configure libB and Runner?

These are the current CMakeLists.txt Files:

libA/CMakeLists.txt:

cmake_minimum_required(VERSION 3.14)
project (MyLibA)

add_library(${PROJECT_NAME} src/my_liba.cpp)
add_library(Example::LibA ALIAS ${PROJECT_NAME})

target_include_directories( ${PROJECT_NAME}
    PUBLIC ${PROJECT_SOURCE_DIR}/include
)

libB/CMakeLists.txt:

cmake_minimum_required(VERSION 3.14)
project (MyLibB)

add_library(${PROJECT_NAME} src/my_libb.cpp)
add_library(Example::LibB ALIAS ${PROJECT_NAME})

target_link_libraries(${PROJECT_NAME} PRIVATE Example::LibA)

target_include_directories( ${PROJECT_NAME}
    PUBLIC ${PROJECT_SOURCE_DIR}/include
)

Runner/CMakeLists.txt

project(runner)

add_executable(${PROJECT_NAME} src/main.cpp)

target_link_libraries(${PROJECT_NAME}
    Example::LibB
)

CMakeLists.txt:

cmake_minimum_required(VERSION 3.14)

project(Example)

add_subdirectory(libA)
add_subdirectory(libB)
add_subdirectory(runner)

With the current configuration i can build everything out of the lib directory. I could also build libA from inside the libA Directory. But i could not build libB or runner from there folders, which was to be expected, since they do not know where to find the dependencies.

How do i have to change my CMakeFiles to get this to work?

Kevin
  • 785
  • 2
  • 10
  • 32
  • Why do you want to run `make` from subdirectories? Just run `make ` from the root of the build dir. – arrowd Mar 12 '21 at 09:29
  • I want to be able to build the `libA` and `libB` also as standalone libraries. – Kevin Mar 12 '21 at 11:16
  • When you are building libB from its folder, how exactly do you want it to find libA? Would libA be already installed on the system, or do you want libB to also build libA? – yemre Mar 12 '21 at 22:42
  • @yemre thats the point where i do not know what is the best solution or if there is a best practice in cmake – Kevin Mar 13 '21 at 12:33

2 Answers2

0

If you want to be able to build libB using only the libB build script you need a way of making libB able to find the libA dependency.

From your question I assume that you actually want to build libA as part of the libB building process (you don't want to install libA before starting the libB build.

This looks weird, but you could do this in libB/CMakeLists.txt:

add_subdirectory(../libA)

The problem is that doing this will break the root build script. This can be fixed by checking if the libA target already exists:

if (NOT TARGET libA)
    add_subdirectory(../libA)
endif (NOT TARGET libA)

In this way, you either have a libA target because the root build script added the libA subdirectory, or you add it yourself.

add_subdirectory(../libA) looks weird to me, and probably some people with more CMake experience will consider it bad style, but I don't see another option here, given your setup. Other things may break if you do this, see this question.

As a side note, you may want to add some dependencies between your targets:

add_dependencies(libB libA)

In this way, when you build libB, if libA is not built, a libA build will be triggered before the libB build starts.

icebp
  • 1,608
  • 1
  • 14
  • 24
  • would it be also a alternative to define a variable with the directory of the libA? So that it is possible to set the variable during the build? – Kevin Mar 14 '21 at 19:08
  • Yes. For example passing `-DPATH_TO_LIBA=some/path.here` will set the variable `PATH_TO_LIBA` to `some/path/here`. You can check if it was set with `if`: `if (PATH_TO_LIBA)`. – icebp Mar 14 '21 at 19:20
  • It then works like the answer from @fabian i guess – Kevin Mar 14 '21 at 19:42
  • Yes. My answer assumes that you need the root build script as is, but his simplifies things. – icebp Mar 14 '21 at 19:58
0

add_subdirectory allows you to pass any directory. If you don't pass a subdirectory though, you need to pass a second parameter specifying the binary directory use for this "subtree" of the sources. of course you need to make sure not to create circles.

This allows you to add the source directories of the projects a target depends on resulting in the following inclusions of source dirs:

  • libB/CMakeLists.txt includes libA
  • runner/CMakeLists.txt includes libB
  • CMakeLists.txt either includes only runner or is removed entirely (you could simply use runner as source dir instead)

A convenient location to use for the binary dirs would be subdirectories of the binary dir.

Changes to your CMakeLists.txt files

libA/CMakeLists.txt

remains unmodifies

libB/CMakeLists.txt

Create a directory to use as source dir and add the add_subdirectory

set(LIB_A_BINARY_DIR "${CMAKE_BINARY_DIR}/subproject_build_dirs/libA")
file(MAKE_DIRECTORY ${LIB_A_BINARY_DIR})
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../libA" ${LIB_A_BINARY_DIR})

runner/CMakeLists.txt

Similar to the changes above, but also add cmake_minimum_required to avoid cmake from producing warnings, if you want to use runner as the source dir.

cmake_minimum_required(VERSION 3.14)

set(LIB_B_BINARY_DIR "${CMAKE_BINARY_DIR}/subproject_build_dirs/libB")
file(MAKE_DIRECTORY ${LIB_B_BINARY_DIR})
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../libB" ${LIB_B_BINARY_DIR})

CMakeLists.txt

If you want to keep this file instead of using runner/CMakeLists.txt directly it should be changed to the following

cmake_minimum_required(VERSION 3.14)

project(Example)

add_subdirectory(runner)
fabian
  • 80,457
  • 12
  • 86
  • 114