Add refactored CMake example

This commit is contained in:
Petr Hrdina
2025-07-15 07:41:45 +02:00
commit f35345ab0a
13 changed files with 163 additions and 0 deletions

13
CMakeLists.txt Normal file
View File

@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 3.20)
project("Refactoring")
set_property(GLOBAL PROPERTY CXX_STANDARD 23)
# Build modules
add_subdirectory("modules/ModuleA")
add_subdirectory("modules/ModuleB")
add_subdirectory("modules/ModuleC")
# Build app
add_subdirectory("app")

72
README.md Normal file
View File

@ -0,0 +1,72 @@
# Refactoring project
## How to build
Build the project by running following commands:
```
cmake -B build
cmake --build build
```
## Static libraries
The project uses static libraries for the modules. The reassoning behind this is that the main purpose of this refactoring is to modularize the code base. Static linking does not change how the app is compiled or installed. This keeps things simple for now. But for future improvements modules can be linked dynamically to allow of updating individual modules without recompilation if the ABI does not change.
## Directory structure
The current directory structure looks like this.
```
refactoring
├── app
│   ├── CMakeLists.txt
│   └── src
│   └── main.cpp
├── CMakeLists.txt
├── modules
│   ├── ModuleA
│   │   ├── CMakeLists.txt
│   │   ├── include
│   │   │   └── moduleA
│   │   │   └── ClassA.h
│   │   └── src
│   │   └── ClassA.cpp
│   ├── ModuleB
│   │   ├── CMakeLists.txt
│   │   ├── include
│   │   │   └── moduleB
│   │   │   └── ClassB.h
│   │   └── src
│   │   └── ClassB.cpp
│   └── ModuleC
│   ├── CMakeLists.txt
│   ├── include
│   │   └── moduleC
│   │   └── ClassC.h
│   └── src
│   └── ClassC.cpp
└── README.md
16 directories, 13 files
```
This is mostly straightforward - app and modules are separated. Each module has its own directory in which CMakeLists.txt specifies how to should be built.
### Structure of module include directory
Only maybe unexpected thing is that every module include directory contains another directory e.g. `ModuleA/include/moduleA/ClassA.h`. This is to prevent conflicts when including files with same name from different modules. It also allows be visible from which module the included file in the app is from.
[app source file](app/src/main.cpp):
```
// app/main.cpp
`#include "moduleA/ClassA.h"`
```
If there are many modules a programmer of the app does not get lost where did the class come from. This makes it easy to locate the file without the need for searching.
In the module itself it most inner directory is included so that we don't need to specify the module.
[module source file](modules/ModuleA/src/ClassA.cpp):
```
// ModuleA/src/ClassA.cpp
#include "ClassA.h"
```

8
app/CMakeLists.txt Normal file
View File

@ -0,0 +1,8 @@
set(MY_EXE "app")
add_executable(${MY_EXE} "src/main.cpp")
target_link_libraries(${MY_EXE} "moduleA" "moduleB" "moduleC")
# no need to include directories, because they are included automatically
# thanks to exposing the directories using PUBLIC

10
app/src/main.cpp Normal file
View File

@ -0,0 +1,10 @@
#include "moduleA/ClassA.h"
#include "moduleB/ClassB.h"
#include "moduleC/ClassC.h"
int main(int argc, char *argv[])
{
ClassA::hello();
ClassB::hello();
ClassC::hello();
}

View File

@ -0,0 +1,7 @@
set(MY_LIB "moduleA")
add_library(${MY_LIB} STATIC "src/ClassA.cpp")
target_include_directories(${MY_LIB} PRIVATE "include/moduleA")
target_include_directories(${MY_LIB} PUBLIC "include")

View File

@ -0,0 +1,9 @@
#ifndef CLASS_A_
#define CLASS_A_
class ClassA {
public:
static void hello();
};
#endif

View File

@ -0,0 +1,4 @@
#include "ClassA.h"
#include <iostream>
void ClassA::hello() { std::cout << "Hello from A" << std::endl; }

View File

@ -0,0 +1,7 @@
set(MY_LIB "moduleB")
add_library(${MY_LIB} STATIC "src/ClassB.cpp")
target_include_directories(${MY_LIB} PRIVATE "include/moduleB")
target_include_directories(${MY_LIB} PUBLIC "include")

View File

@ -0,0 +1,9 @@
#ifndef CLASS_B_
#define CLASS_B_
class ClassB {
public:
static void hello();
};
#endif

View File

@ -0,0 +1,4 @@
#include "ClassB.h"
#include <iostream>
void ClassB::hello() { std::cout << "Hello from B" << std::endl; }

View File

@ -0,0 +1,7 @@
set(MY_LIB "moduleC")
add_library(${MY_LIB} STATIC "src/ClassC.cpp")
target_include_directories(${MY_LIB} PRIVATE "include/moduleC")
target_include_directories(${MY_LIB} PUBLIC "include")

View File

@ -0,0 +1,9 @@
#ifndef CLASS_C_
#define CLASS_C_
class ClassC {
public:
static void hello();
};
#endif

View File

@ -0,0 +1,4 @@
#include "ClassC.h"
#include <iostream>
void ClassC::hello() { std::cout << "Hello from C" << std::endl; }