3

I have a C++ project with the following structure:

CMakeLists.txt
code/
  libClient/
     CMakeLists.txt
     include/
        LibClient/
          lib_client.h
     src/
        lib_client.cpp
  libServer/
     CMakeLists.txt
     include/
        LibServer/
          lib_server.h
     src/
        lib_server.cpp
  libSDK/
     include/
       CMakeLists.txt
       LibSDK/
         lib.h

My root CMakeLists.txt has the following content:

cmake_minimum_required(VERSION 3.0)

project(libExample)


set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)

add_subdirectory(code/libClient)
add_subdirectory(code/libServer)
add_subdirectory(code/libSDK)

Now, I would like to build the libs for the server and for the client as .a files. The lib_client.cpp includes the header files with

#include <LibClient/lib_client.h>

Up to here, it is all clear for me, but the header file lib_client.h includes the lib.h which is located at /code/libSDK/include/LibSDK/lib.h with

#ifndef LIBCLIENT_H
#define LIBCLIENT_H

#include <string>
#include <LibSDK/lib.h>

To make this work, I wrote the following content in the CMakelists.txt for the ClientLib:

project(LIBCLIENT)

add_library(
    Client_lib STATIC
    src/lib_client.cpp
        include/LibClient/lib_client.h
    )

target_include_directories(egoClient_lib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_include_directories(egoClient_lib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../libSDK/include")   ###this line I think should be different.

My question is now, is it possible to avoid this line with the hard coded path? This lib.h is also used (included) in other header files in this project.

The CMakelists.txt for this lib.h has up to now only the content:

cmake_minimum_required(VERSION 3.0)

project(LIBSDK)

I thought about using the CMake find_package() method and write a Find<package>.cmake file, but I do not see any advantages of this because inside this file I also have to write the paths?

Thank you very much in advance.

Kevin
  • 16,549
  • 8
  • 60
  • 74
Morgijl
  • 31
  • 1

2 Answers2

3

If Client_lib uses SDK_lib, you'll want to use the following in Client_lib's CMakeLists.txt:

target_link_libraries(Client_lib SDK_lib)

This will tell CMake that Client_lib uses SDK_lib. It will also automatically make the PUBLIC or INTERFACE include paths configured on SDK_lib (with target_include_directories in SDK_lib's CMakeLists.txt) available for Client_lib.

Mike.nl
  • 86
  • 2
  • First of all, thanks for the fast reply. It is working now, after adding the lines target_include_directories(Client_lib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") target_include_directories(Server_lib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") into the CMakeLists.txt of lib.h But I would like to understand what the suggested line target_link_libraries(Client_lib SDK_lib) would do, because the lib.h should not be compiled to a lib, only the server and the client. Greetings. – Morgijl Oct 20 '19 at 11:46
  • So `lib.h` *is* part of a library, called `SDK_lib`. This is a so-called [INTERFACE](https://cmake.org/cmake/help/latest/command/add_library.html#interface-libraries) library since it does not have any source files to compile into a `.a` file. But any `PUBLIC` (or `INTERFACE`) include paths set on such a target (or certain other properties) do propagate via `target_link_libraries`. – Mike.nl Oct 21 '19 at 07:40
0

Firstly, if your libClient and libServer depend on libSDK, you should rearrange your top-level CMake to look like the below. Also, based on your example project structure, your add_subdirectory() for the SDK should be code/libSDK/include:

cmake_minimum_required(VERSION 3.0)

project(libExample)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)

add_subdirectory(code/libSDK/include)
add_subdirectory(code/libClient)
add_subdirectory(code/libServer)

You want to be sure to gather information about you SDK first, before traversing to the client and server directories.


Secondly, if you do not intend to build libSDK into a library, but simply use its headers, you can just define a new variable in your libSDK CMake file to specify the location of the headers:

project(LIBSDK)

set(SDK_INCLUDE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "My SDK headers directory.")

Now, with a cached variable from the libSDK directory, we can use it in the other CMake files:

project(LIBCLIENT)

add_library(Client_lib STATIC
    src/lib_client.cpp
)

target_include_directories(Client_lib PUBLIC 
    "${CMAKE_CURRENT_SOURCE_DIR}/include"
    "${SDK_INCLUDE_DIRECTORY}"
)

EDIT: As commented, to avoid the use of cache variables, you can also set the include directories variable with PARENT_SCOPE to make the variable accessible from your client and server CMake files:

project(LIBSDK)

set(SDK_INCLUDE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE)
Kevin
  • 16,549
  • 8
  • 60
  • 74
  • Using cached variables to achieve this is generallly discouraged in modern CMake. It's better to define an [INTERFACE](https://cmake.org/cmake/help/latest/command/add_library.html#interface-libraries) library for `SDK_Lib` and set the include path on that target (see [my comment](https://stackoverflow.com/questions/58471946/cmake-include-same-header-file-for-different-libs/58472100#comment103295188_58472100) above). – Mike.nl Oct 21 '19 at 07:42
  • @Mike.nl Added an alternative to using the cached variable. Agreed that it is better practice to define an interface library for this SDK, but the OP described that `lib.h` should *not* be pulled in as part of a library. Without a full understanding of the OP's use of the SDK, I tried to keep my explanation as simple as possible. – Kevin Oct 21 '19 at 11:46