Search code examples
c++cmakeexternal-project

CMake: Build and install locally stored submodule


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:


Solution

  • 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.