Search code examples
c++cmakedirectory-structure

How should I organize my directory structure when using CMake with C++ inheritance?


Currently I have a directory structure that looks like the following

.
├── CMakeLists.txt
├── Base
│   ├── CMakeLists.txt
│   ├── include
│   │   └── base.h
│   └── src
│       └── base.cpp
├── Derived
│   ├── CMakeLists.txt
│   ├── include
│   │   └── derived.h
│   └── src
│       └── derived.cpp
└── src
    └── main.cpp

and the CMakeLists.txt files looking like

./CMakeLists.txt

cmake_minimum_required(VERSION 3.1)

set(CMAKE_CXX_STANDARD 11)

project(MyProj)

add_subdirectory(Base)
add_subdirectory(Derived)

add_executable(main src/main.cpp)
target_link_libraries(main Base)
target_link_libraries(main Derived)

./Base/CMakeLists.txt

add_library(Base STATIC src/base.cpp)
target_include_directories(Base PUBLIC include)

./Derived/CMakeLists.txt

add_library(Derived STATIC src/derived.cpp)
target_include_directories(Derived PUBLIC include)
target_link_libraries(Derived Base)

I want to know if this is an appropriate way to structure a CMake project when using inheritance in C++. If there is a more idiomatic way to structure this, I am open to suggestions.


Solution

  • If your intention is to build two libraries, and an executable, then that is what your structure achieves. I would however recommend thinking why you are doing that, and perhaps consider whether it would be simpler to instead have both classes in a single library.

    If I keep extending this, say make another class that inherits from Derived, then I have to make a new CMakeLists.txt file then link and include against these files. I don't have a problem doing this, but it does not seem very maintainable for larger projects

    No, you don't have to make a new CMakeLists.txt unless you add a new target. You don't necessarily need more than a single target for a project.

    A target (be it executable or a library) is not limited to having only one translation unit.

    My personal preference for small project is three (or two) targets: A library containing all functionality, a main executable with int main() that does nothing except invoke the library (if the project is an executable rather than just the library), and a test executable with int main() from a test framework. The library can optionally be split to smaller pieces if it has parts that are reusable in other projects.


    set(CMAKE_CXX_STANDARD 11)
    

    prefer target specific properties instead:

    set_target_properties(
        Base PROPERTIES
        CXX_STANDARD 11
    
        # use unless you also support older standards
        CXX_STANDARD_REQUIRED ON
    )
    

    The dependees will inherit the property, but you can set it explicitly in each for potentially lesser chance of breakage in case you later decide to not use the base library.