This script automates the creation of new DMOD modules from templates, reducing manual configuration and ensuring consistency across modules.
The new-module.sh script creates a new DMOD module with all the files a real
module repo is expected to have:
CMakeLists.txt/Makefile- build configuration (CMake fetchesdmodviaFetchContentfrom GitHub by default)src/<module_name>.c- source file with template codeinclude/<module_name>.h- public header (library modules only)docs/README.md,docs/api-reference.md- documentation skeletontests/CMakeLists.txt,tests/<module_name>_test.c- admod_add_test()skeletonmanifest.dmm- DMOD manifest entry<module_name>.dmr- DMOD resource file (library modules only)README.md- module documentation, including a "Project Structure" section.gitignorescripts/sync-claude.sh- copy of the Claude Code skills sync script (see below)- Optional: GitHub Actions workflow (
.github/workflows/ci.yml) - Optional: Bitbucket pipeline (
bitbucket-pipelines.yml) - Optional: a hardware port module (
<module_name>_port, via--port)
The setup-linux-env.sh script configures a native Linux host in the same way as Docker/Dockerfile.env.
It installs:
- Required apt packages (including
gcc,g++,make,openocd,gcovr,git,jq,zip,unzip) - Choco scripts from
https://raw.githubusercontent.com/JohnAmadis/choco-scripts/refs/heads/master/install-choco-scripts.sh - ARM GNU toolchain
10.3-2021.10into/tools/gcc-arm-none-eabi - CMake
3.31.3into/usr - PATH integration via
/etc/profile.d/dmod-tools.shand~/.bashrc - DMOD tool output variables
DMOD_DMF_DIR=/tools/dmfandDMOD_DMFC_DIR=/tools/dmfc
Usage:
./scripts/setup-linux-env.shOptional flags:
--tools-dir PATH--arm-version VERSION--cmake-version VERSION--skip-choco-scripts--skip-profile-setup
./scripts/new-module.sh --name MODULE_NAME --type TYPE --path PATH [OPTIONS]--name NAME- Name of the module (used for file names and module identification)--type TYPE- Type of module to create:library- A library module that can be used by other modulesapplication- An application module with a main entry point
--path PATH- Path to the folder where the module should be created. It may already exist - e.g. a repo you just created on GitHub and cloned locally, containing onlyREADME.md/LICENSE. Individual files that already exist there are left untouched (a warning is printed for each); only files that don't exist yet are written. Use--forceto overwrite.
--author AUTHOR- Author name (default: "John Doe")--license LICENSE- License name (default: "MIT")--dmod-dir DIR- Path to a local dmod checkout. When set, the generatedCMakeLists.txtis pinned to it (viaFETCHCONTENT_SOURCE_DIR_DMOD) instead of fetchingdmod'sdevelopbranch from GitHub, and it is also used as the source for the Claude Code skills sync. When omitted, the generated module fetchesdmodfrom GitHub on first configure - this is what every real module repo in the ecosystem does.--github- Generate GitHub Actions workflow configuration--bitbucket- Generate Bitbucket pipeline configuration--dif- Add DIF (DMOD Interface) support (library modules only)--mal- Add MAL (Module Abstraction Layer) support--port- Add a hardware port module<module_name>_port(library modules only) - the split-core/port pattern used bydmuart/dmfmc--port-arch NAME- Architecture for the generated port skeleton (default:stm32f7). Requires--port.--force- Overwrite files that already exist at--pathinstead of skipping them--skip-claude-sync- Don't runscripts/sync-claude.shat the end of generation--help- Show help message
./scripts/new-module.sh \
--name mylib \
--type library \
--path ./modules/mylib./scripts/new-module.sh \
--name myapp \
--type application \
--path ./modules/myapp \
--author "Jane Smith"./scripts/new-module.sh \
--name mylib \
--type library \
--path ./modules/mylib \
--dif \
--github./scripts/new-module.sh \
--name mydriver \
--type library \
--path ./modules/mydriver \
--port \
--port-arch stm32f7Useful for local development or CI, where you want to build against the
checked-out dmod instead of develop on GitHub:
./scripts/new-module.sh \
--name my_module \
--type application \
--path /path/to/my_module \
--dmod-dir /path/to/dmod \
--author "Your Name" \
--github \
--bitbucketA library module provides functions and APIs that can be used by other modules. It includes:
dmod_preinit()- Optional pre-initialization functiondmod_init()- Initialization functiondmod_deinit()- De-initialization function- A public header at
include/<module_name>.h - A
<module_name>.dmrresource file (enables release packaging)
Library modules can optionally implement:
- DIF (DMOD Interface) - 1:N interface, discovered dynamically at runtime
- MAL (Module Abstraction Layer) - 1:1 pluggable interface implementation
- A hardware port (
--port) - split into<module_name>(core) and<module_name>_port(architecture-specific), selected viaDMOD_CPU_FAMILY
An application module provides a standalone application with a main entry point. It includes:
dmod_preinit()- Optional pre-initialization functionmain()- Main application entry point
Application modules can optionally implement:
- MAL (Module Abstraction Layer) - pluggable interface implementation
No .dmr is generated for application modules by default, matching the
dmell precedent (an application's release packaging is usually handled
alongside its sibling command/library modules, not standalone).
scripts/sync-claude.sh copies .claude/skills/ from the dmod repository
into the current repository. It is copied into every module generated by
new-module.sh and run once, explicitly, at the end of generation (unless
--skip-claude-sync is passed) - the result is meant to be reviewed and
committed like any other generated file, not silently regenerated by a build
step.
Run it again any time you want to pick up newer skills:
./scripts/sync-claude.sh # clone dmod@develop
./scripts/sync-claude.sh --dmod-dir /path/to/dmod # use a local checkout
./scripts/sync-claude.sh --ref v1.2.0 # pin to a tag/branchIt only touches .claude/skills/ - it never overwrites .claude/settings.json,
hooks, or skills you added locally under a different name.
Run this before working with Claude Code in a module repo generated from
this template, so the dmod-ecosystem skill (architecture map, build
system, driver+port pattern) is available.
cd /path/to/module
mkdir -p build
cd build
cmake ..
cmake --build .The generated DMF file will be in build/dmf/<module_name>.dmf.
cd /path/to/module
make DMOD_MODE=DMOD_MODULE- The script validates all input parameters and provides helpful error messages
- Module names should follow C identifier rules (alphanumeric and underscores)
- The script prevents overwriting existing directories
- DIF interfaces and hardware ports are only supported for library modules
- Generated modules include
.gitignoreto exclude build artifacts
This is expected when --path points at a directory that already had some
files in it (e.g. README.md/LICENSE from GitHub's repo creation flow) -
those files are intentionally left untouched. If you want the template's
version instead, pass --force, or delete/rename the specific file first.
Ensure you're running the script from the DMOD repository root or that the script can locate the .github/templates directory.
If you encounter build errors:
- Verify network access to GitHub (CMake fetches
dmodviaFetchContentby default) or pass--dmod-dirto a local checkout - Ensure
DMOD_MODEis set toDMOD_MODULEwhen building with Make - For a local
dmodcheckout, verify the--dmod-dirpath is correct