Skip to content

CMake Module Structure

Santiago Bernardino edited this page Nov 21, 2024 · 2 revisions

The codebase is structured in a CMake Module manner, every part of the engine is compiled as a library and all modules are linked against the main function.

Creating a new module:

  1. Create a new subfolder in the engine (preferably named module_name)
  2. Add a CMakeLists.txt and declare the library (Tip: there are shortcuts to declare a module quickly)
add_library(Module)
module_default_init(Module)
  1. Create a private and public folders. Private folders are meant to include source files and private headers, while headers belong in the public folder and they will be "includeable" in every module that depends on your module.

  2. Add dependencies. If your module depends on another module or external library for includes, you must add them via normal CMake Syntax (Note: Try to keep dependencies PRIVATE, review how the PUBLIC and PRIVATE keywords work in CMake)

target_link_libraries(Utility
        PRIVATE Tracy::TracyClient
        PUBLIC spdlog::spdlog 
        PUBLIC glm::glm
)
# spdlog and glm will be visible for every module that links to Utility, but not Tracy
  1. Link to the module in engine/CMakeLists.txt:
# ENGINE MODULES

message(STATUS "### Linking Engine Modules:")
target_add_module(Engine core Core)
target_add_module(Engine utility Utility)
target_add_module(Engine application Application)
target_add_module(Engine *module_folder* *ModuleName*) # <--- Added Module

Engine Modules

In C++, If your module wants to include more than free functions and datatypes, you must derive from ModuleInterface and implement functions to initialize, shutdown and update your module.

class ModuleInterface
{
public:
    ModuleInterface() = default;
    virtual ~ModuleInterface() = default;

    NON_COPYABLE(ModuleInterface);
    NON_MOVABLE(ModuleInterface);

private:
    // Return the desired tick order for this module
    virtual ModuleTickOrder Init(Engine& engine) = 0;

    // Ticking order is decided based on the returned value from Init
    virtual void Tick(Engine& engine) = 0;

    // Modules are shutdown in the order they are initialized
    virtual void Shutdown(Engine& engine) = 0;
};

If your module declares a new class deriving from ModuleInterface, You must register it in main.cpp:

int main(int argc, char* argv[])
{
    MainEngine instance;

    instance
        .AddModule<ApplicationModule>()
        .AddModule<MyNewModule>(); // <--- Added Module

    return instance.Run();
}

Unit Tests

Since unit tests might require access to private folders in a module, Unit tests are placed on a per module basis inside a dedicated tests folder, much like the private and public folders. Unit tests are not required for a module to compile successfully and tests are also only compiled for the unit test executable:

image

This should be enough to get you started, if you have any problems please post them in the discord. Happy coding!

Clone this wiki locally