This document describes the CMake functions provided by DMOD for module development.
Creates a DMOD executable module.
Parameters:
moduleName- Name of the moduleversion- Module version (e.g., "1.0", "2.3.1")sources...- List of source files
Example:
set(DMOD_MODULE_NAME my_app)
set(DMOD_MODULE_VERSION "1.0")
set(DMOD_AUTHOR_NAME "John Doe")
set(DMOD_STACK_SIZE 2048)
set(DMOD_PRIORITY 0)
dmod_add_executable(${DMOD_MODULE_NAME} ${DMOD_MODULE_VERSION}
main.c
app_logic.c
)Creates a DMOD library module.
Parameters:
moduleName- Name of the moduleversion- Module version (e.g., "1.0", "2.3.1")sources...- List of source files
Example:
set(DMOD_MODULE_NAME my_lib)
set(DMOD_MODULE_VERSION "2.0")
set(DMOD_AUTHOR_NAME "Jane Smith")
dmod_add_library(${DMOD_MODULE_NAME} ${DMOD_MODULE_VERSION}
library.c
utils.c
)If DMOD_DMR_PATH is set before calling dmod_add_library, a release package will be created in build/packages/ after the build completes:
build/
└── packages/
├── my_lib/
│ ├── my_lib.dmf
│ └── LICENSE.md
└── my_lib.zip
Creates a DMOD test module.
The test runner main() is provided automatically by the framework — do not
define main() in your test sources. Test steps are registered with the
DMOD_TEST_STEP() macro from dmod_test.h and are discovered and executed
automatically at runtime.
The exit code of the resulting binary equals the number of failed steps, making it suitable for use in CI pipelines.
Parameters:
moduleName- Name of the test moduleversion- Module version (e.g., "1.0")sources...- List of test source files (must not definemain())
Example:
set(DMOD_MODULE_NAME my_module_tests)
set(DMOD_MODULE_VERSION "1.0")
set(DMOD_AUTHOR_NAME "Jane Smith")
set(DMOD_STACK_SIZE 2048)
dmod_add_test(${DMOD_MODULE_NAME} ${DMOD_MODULE_VERSION}
test_feature_a.c
test_feature_b.c
)Test source example:
#include "dmod_test.h"
/* Optional lifecycle hooks */
void dmod_test_setup(void) { /* reset state */ }
void dmod_test_teardown(void) { /* cleanup */ }
DMOD_TEST_STEP(addition_works)
{
DMOD_TEST_EXPECT_EQ(1 + 1, 2);
}
DMOD_TEST_STEP(null_pointer_check)
{
void* ptr = get_something();
DMOD_TEST_EXPECT_NOT_NULL(ptr);
}Output example:
=== DMOD Test Runner ===
[ RUN ] addition_works
[ OK ] addition_works
[ RUN ] null_pointer_check
[ OK ] null_pointer_check
=== Results: 2/2 passed ===
Available assertion macros (from dmod_test.h):
| Macro | Description |
|---|---|
DMOD_TEST_EXPECT(cond) |
Fail if condition is false |
DMOD_TEST_EXPECT_TRUE(cond) |
Alias for DMOD_TEST_EXPECT |
DMOD_TEST_EXPECT_FALSE(cond) |
Fail if condition is true |
DMOD_TEST_EXPECT_EQ(a, b) |
Fail if a != b |
DMOD_TEST_EXPECT_NE(a, b) |
Fail if a == b |
DMOD_TEST_EXPECT_NULL(ptr) |
Fail if ptr != NULL |
DMOD_TEST_EXPECT_NOT_NULL(ptr) |
Fail if ptr == NULL |
DMOD_TEST_FAIL() |
Unconditionally fail |
DMOD_TEST_FAIL_MSG(msg, ...) |
Unconditionally fail with message |
Downloads headers for external DMOD modules and links them to your target. This function uses the dmf-get tool to download module headers at CMake configuration time and automatically adds them to the target's include directories.
Parameters:
targetName- Name of the target (must be created withdmod_add_executableordmod_add_libraryfirst)PRIVATE|PUBLIC|INTERFACE- Optional visibility scope (default: PRIVATE if not specified)PRIVATE- Headers available only to this targetPUBLIC- Headers available to this target and targets that link to itINTERFACE- Headers available only to targets that link to this target
modules...- List of module specifications with optional versions
Module Specification Format:
module_name- Download the latest version of the modulemodule_name@version- Download a specific version of the module (e.g.,dmlink@1.0)
Example:
# Create your module first
dmod_add_executable(${DMOD_MODULE_NAME} ${DMOD_MODULE_VERSION}
main.c
)
# Link external modules with default PRIVATE visibility
dmod_link_modules(${DMOD_MODULE_NAME}
dmlink@1.0 # Specific version
dmffs # Latest version
)
# Or specify visibility scope explicitly
dmod_link_modules(${DMOD_MODULE_NAME}
PUBLIC
driver@2.3 # Public headers (available to dependents)
PRIVATE
internal_lib # Private headers (only for this module)
)How It Works:
- Finds dmf-get tool: The function searches for the
dmf-getexecutable in${DMOD_TOOLS_BIN_DIR}or system PATH - Saves version requirements: Creates a version requirements file (e.g.,
<target_name>_version_requirements.txt) containing all module version specifications - Downloads headers: For each module, it executes
dmf-get headers <module_spec> -o <output_dir> - Passes configuration: Automatically passes
-t ${DMOD_TOOLS_NAME}if defined and-m ${DMOD_DMM_URL}if defined - Adds include directories: The downloaded headers (located at
${DMOD_DMF_DIR}/<module_name>/inc) are automatically added to the target's include directories with the specified visibility - Integration with todmd: When the module is built, the version requirements file is automatically passed to
todmdwhen generating the.dmddependencies file. This ensures that version constraints specified indmod_link_modulesare included in the generated.dmdfile.
Output Directory:
Headers are downloaded to: ${DMOD_DMF_DIR}/inc/<module_name>/include/
For example, for the dmini module, headers are located at: ${DMOD_DMF_DIR}/inc/dmini/include/dmini.h
The include directory added to the target is: ${DMOD_DMF_DIR}/inc/<module_name>/include, allowing you to use #include <module_header.h> directly.
By default, DMOD_DMF_DIR is set to ${CMAKE_BINARY_DIR}/dmf.
Requirements:
- The
dmf-gettool must be built and available (build with-DDMOD_BUILD_TOOLS=ON) - A valid manifest file must be accessible (either specified via environment variables or using the default registry)
- The modules must exist in the configured registry
Environment Variables (for dmf-get):
The dmf-get tool (used internally) respects the following environment variables:
DMOD_MANIFEST- Path or URL to the manifest fileDMOD_TOOLS_NAME- Tools name for platform-specific modulesDMOD_INC_DIR- Default include directory (overridden by the-oflag used by this function)
CMake Variables:
DMOD_DMF_DIR- CMake variable controlling the base directory for downloaded headers (default:${CMAKE_BINARY_DIR}/dmf)DMOD_TOOLS_BIN_DIR- CMake variable specifying where to find the dmf-get toolDMOD_TOOLS_NAME- CMake variable for tools configuration name (e.g., "arch/x86_64"). If defined, passed to dmf-get via-tflagDMOD_DMM_URL- CMake variable for manifest URL. If defined, passed to dmf-get via-mflag
Error Handling:
- If
dmf-getis not found, a warning is issued and the function returns without error - If a module download fails, a warning is issued and the function continues with remaining modules
- The build continues even if some headers cannot be downloaded
Notes:
- This function should be called after
dmod_add_executableordmod_add_library - Headers are downloaded during CMake configuration, not during build
- If you need to update headers, re-run CMake configuration
- The function only downloads headers (not the full module files)
- Visibility scopes work the same way as
target_include_directories
Downloads headers and a precompiled static library for "system modules" and statically links them into your target. Uses the dmf-get tool's headers and lib commands.
A "system module" (e.g. dmlist, dmosi-posix) is a DMOD module that is never turned into a loadable .dmf file - it is distributed as a static library (the lib resource in its .dmr, see dmf-get Tool and DMR File Format) meant to be built directly into a system-side binary: the loader itself, dmod-boot, or host tools/tests.
Parameters:
targetName- Name of the target to link into (must already exist)PRIVATE|PUBLIC|INTERFACE- Optional visibility scope (default: PRIVATE if not specified), same meaning as fordmod_link_modulesmodules...- List of module specifications with optional versions (module_nameormodule_name@version)
Example:
add_executable(dmod_loader main.c)
target_link_libraries(dmod_loader dmod pthread)
dmod_link_builtin(dmod_loader
dmlist
dmosi-posix
)How It Works:
- Finds
dmf-get, same asdmod_link_modules - For each module, runs
dmf-get headers <module_spec> -o ${DMOD_DMF_DIR}/incand adds the resulting${DMOD_DMF_DIR}/inc/<module_name>/includedirectory to the target's include directories - For each module, runs
dmf-get lib <module_spec> -o ${DMOD_DMF_DIR}/libto download the precompiled static library - Statically links
${DMOD_DMF_DIR}/lib/<module_name>/lib/lib<module_name_snake_case>.aintotargetName(hyphens in the module name are converted to underscores, e.g.dmosi-posix->libdmosi_posix.a, matching the module's own.dmr/CMake target naming)
These libraries define their DMOD API functions in a way that always marks them as "used" to the compiler/linker, so simply linking the archive is enough to make their Built-in API available - no explicit symbol references are needed at the call site.
Important: do not use this for regular DMOD modules created with dmod_add_executable/dmod_add_library - those must always link other modules dynamically via dmod_link_modules, since DMOD modules are loaded/unloaded independently at runtime and statically linking a dependency into one defeats that. dmod_link_builtin is only for system-side binaries that are not themselves loaded as .dmf files.
Creates a system tool executable.
Parameters:
toolName- Name of the toolsources...- List of source files
Example:
dmod_add_tool(my_tool
main.c
tool_logic.c
)Creates a Makefile for building a static library target. This is automatically called for library targets and is used for Make-based builds. Also calls dmod_set_current_allocator(targetName) (see below).
Defines DMOD_CURRENT_ALLOCATOR for targetName as a private compile definition, defaulting allocatorName to targetName itself. dmod_sal.h requires DMOD_CURRENT_ALLOCATOR to be defined on the system side (no DMOD_MODULE_NAME to fall back on there) so that Dmod_Malloc/Dmod_Realloc/Dmod_AlignedMalloc/Dmod_Free can attribute allocations to their owner, the same way they already do for modules.
create_library_makefile() and dmod_add_tool() call this automatically, so any target built through them (system libraries such as dmlist/dmvfs/dmheap, or a tool created with dmod_add_tool) gets a correctly named allocator for free. Call it directly for any other raw add_library/add_executable target that includes dmod_sal.h on the system side:
add_library(my_system_lib STATIC my_system_lib.c)
dmod_set_current_allocator(my_system_lib)Sets up DMOD libraries for external modules. Call this macro after project() in external module projects.
Example:
cmake_minimum_required(VERSION 3.18)
project(my_external_module)
# Include DMOD paths
set(DMOD_DIR "/path/to/dmod")
include(${DMOD_DIR}/paths.cmake)
# Setup DMOD for external module
dmod_setup_external_module()
# Now you can use DMOD functions
dmod_add_executable(my_module "1.0"
main.c
)The following variables should be set before calling dmod_add_executable or dmod_add_library:
DMOD_MODULE_NAME- Name of the moduleDMOD_MODULE_VERSION- Module version stringDMOD_AUTHOR_NAME- Author name
-
DMOD_STACK_SIZE- Stack size for the module (default: 1024) -
DMOD_PRIORITY- Module priority (default: 1) -
DMOD_MANUAL_LOAD- Manual load flag (default: OFF) -
DMOD_MAL_IMPLS- List of MAL (Module Abstraction Layer) interfaces implemented -
DMOD_DIF_IMPLS- List of DIF (Device Interface) implementations -
DMOD_COMPRESSION_METHOD- Compression method for DMFC files (default: "fastlz") -
DMOD_ASSETS_PATHS- List of directories with the sources of a module's assets (views, images, fonts). When set, they are converted intoDMOD_VIEWS_DIR(default:<build>/views) by thedmod_assetstarget, which the module depends on - with toolsdmf-getdownloads at configure time, only for the kinds of files found:*.dmvsviews -todmv-<name>.dmv;- images (
DMOD_IMAGE_EXTENSIONS, defaultpng jpg jpeg jpe jfif bmp qoi gif tif tiff svg) -todmviwith thedmimgdecoder of each extension (dmimg_png,dmimg_jpegfor.jpg, ...;DMOD_IMAGE_DECODERSoverrides the list) -<name>.dmvi, next to the views, so a view finds them by name. An optional<image>.ininext to an image (logo.png.ini) sets its conversion:format(auto,rgb565,rgb565a8,argb8888,i8,a8,a4),size(WIDTHxHEIGHT, scaled down to fit),compression(fastlz,none),dither(on/off),blur(pixels: a Gaussian blur of that standard deviation, after scaling),crop(X,Y,W,H: only that of it, after scaling and blurring - what a box shows),radius(pixels: its corners rounded aftercrop, transparent outside them - an image in a rounded box). Keys before any section apply to every output; each[section]is an output<section>.dmviof its own (e.g.[logo]and[logo-mask]from one image). - fonts (
DMOD_FONT_EXTENSIONS, defaultttf otf ttc) -todmvf-.dmvf, next to the views. A font needs its<font>.ini(Roboto-Regular.ttf.ini), as a font is made for one pixel size: each[section]is an output<section>.dmvfwith itssize(pixel size,4...127, required) and optionalchars(codepoint ranges, e.g.0x20-0x7E,0x104; default: printable ASCII, Latin-1, Latin Extended-A) andtracking(letter spacing added to every advance, in pixels, e.g.-2.4, like CSSletter-spacing). A font without an.iniis left out with a warning.
Two sources of one output name are a configuration error.
The directory is passed to
mkdmrpkgas--views-dir, so a.dmrcan use${views_dir}to put the assets into the package, e.g.views=./views => ${views_dir} [origin=${views_dir}](dmf-getinstalls them into a per-module directory). Other settings:DMOD_VIEWS_TOOLS_NAME(tools name used to fetch the tools, defaultarch/x86_64) andDMOD_LOADER(path todmod_loader, which runs them; searched in the tools dir andPATHby default).DMOD_FIXTURES_PATHSis the old name ofDMOD_ASSETS_PATHS: still read, with a warning, whenDMOD_ASSETS_PATHSis not set. -
DMOD_DMR_PATH- Path to the.dmrresource file. When set, a release package is created inbuild/packages/<moduleName>/and zipped tobuild/packages/<moduleName>.zipafter the build. Requires themkdmrpkgtool (build with-DDMOD_BUILD_TOOLS=ON).
- DMF-GET Tool Documentation - Package manager for DMOD modules
- Module Debugging - Debugging DMOD modules
- Memory Analysis - Analyzing module memory usage