1

There are numerous similar questions on Stack Overflow, but none come near to answering my question.

I have a C++ library built using CMake:

mylib
| - CMakeLists.txt
| - src/
|   | - m.h
|   | - m.cpp
| - include/
|   | - mylib/
|   |   | - a.h
|   |   | - something/
|   |   |   | - some.h
| - cmake/
|   - mylibConfig.cmake.in
|   - mylibConfigVersion.cmake.in

I then create another library or executable which includes the aforementioned library:

myapp
| - CMakeLists.txt
| - src/
|   | - main.cpp
| - include/
|   | - myapp/
|   |   | - b.h
| - libs
|   | - mylib

And would like to use mylib within myapp like so. Please take notice how mylib headers are included in a directory like format:

#include <mylib/a.h>
#include <mylib/something/some.h>

mylib should be built when building myapp so that the following works without any other build steps:

$ cd myapp/build
$ cmake ..
$ make

Here is a list of some of the Stack Overflow posts I have reviewed. I have attempted each, and they simply do not work:

patyx
  • 324
  • 1
  • 3
  • 17
  • It seems that those other questions are about *external* projects while your project has internal library (that is it is inside of directory tree of app project) so I guess `add_subdirectory` should be sufficient. I personally would object such a project organization though. – user7860670 Mar 13 '19 at 20:54
  • 1
    I'm a big fan of `cmake --build .` rather than `make`, it's more portable. – Tzalumen Mar 13 '19 at 21:19

2 Answers2

2

Assuming in the project described, only header files in the mylib/include directory are to be considered public:

The top-level CMakeLists.txt for mylib needs to contain:

cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
project(mylib VERSION 0.1 LANGUAGES CXX)

add_library(${MyLibName} ${MyLib_SOURCES})

target_include_directories(${MyLibName}
    PUBLIC
        $<INSTALL_INTERFACE:include>
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
)

This ensures that projects including mylib will only have access to files in the include/ directory. Files in include/ can be used like #include <myfile.h> and files in include/mylib (the general convention) can be used like #include <mylib/myfile.h>.

The top-level CMakeLists.txt for myapp should include:

cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
project(myapp VERSION 0.1 LANGUAGES CXX)

add_subdirectory(libs/mylib)

add_executable(${MyAppName} ${MyApp_SOURCES})
target_link_libraries(${MyAppName} ${MyLibName}

The use of add_subdirectory ensures that mylib will be built before myapp and target_link_libraries adds mylib to the executable.

As mentioned by Tzalumen, make sure you take a look at the CMake tutorials and prefer the use of cmake --build . instead of make.

patyx
  • 324
  • 1
  • 3
  • 17
0

So, I actually do this in one of my projects.

First, the library needs to be built with ADD_LIBRARY(), but I'm assuming you do that. Something like

ADD_LIBRARY (${MyLibName} ${SOURCES}) in the library's CMakeLists.txt

That adds the library into cmake's list of libraries.

Second, you add the library to your project with

target_link_libraries (${PROJECT_NAME} ${MyLibName}) in the executable's CMakeLists.txt, the same one where you have your add_executable (${PROJECT_NAME} ${SOURCES})

That will set up the dependency chain to force MyLibName to explicitly build before PROJECT_NAME.

Tzalumen
  • 652
  • 3
  • 16
  • I want the entire process to be done at once. I do not want to CMake and build the `mylib` separately from `myapp`. The project is required to be 110% self-contained. – patyx Mar 13 '19 at 21:35
  • When I say it does it first, I refer to the compilation order of a single build. My project builds off one config call and one build call. – Tzalumen Mar 13 '19 at 22:46
  • I have a script that does this. Specifically, it makes a `_build` directory, `cd`s into it, calls `cmake ..`, then calls `cmake --build .`, I just sit back and wait for the compilation to finish. – Tzalumen Mar 13 '19 at 22:49
  • @paddycakes I'm sorry if I haven't been completely clear, this answer is the standard, correct way to build a library and add it to your project, I learned it directly from the cmake documentation. – Tzalumen Mar 14 '19 at 19:56
  • I have worked through the tutorials, but I was looking for further elaboration on each line's purpose. I figured out my issue was not properly adding the include directories to `mylib` with `target_include_directories`.I've added an all encompassing answer. – patyx Mar 19 '19 at 18:34