The dmf-get tool is a package manager for DMOD (Dynamic Modules) that enables downloading and managing DMF packages from manifest files. It was designed to support the DMOD ecosystem by providing a simple, flexible way to distribute and install modules.
The implementation consists of three main components:
A standalone static library that handles parsing of .dmm (DMOD Manifest) files.
Location: lib/dmod_manifest/
Key Features:
- Parses manifest files from strings, files, or URLs
- Supports comments (
#) and blank lines - Handles module entries with optional versions (
module@version url) - Processes
$includedirectives for recursive manifest inclusion - Variable substitution for
<tools_name>and<arch_name> - Pluggable download function via function pointer
- Clean, documented C API
Design Decisions:
- Made as a static library for reusability in other projects
- Download function is passed as a function pointer to allow easy replacement
- Uses linked list for storing entries (simple, no memory fragmentation)
- Comprehensive error reporting via
Dmod_Manifest_GetError()
A standalone static library that handles parsing of .dmd (DMOD Dependencies) files.
Location: lib/dmod_dependencies/
Key Features:
- Parses dependency lists with version constraints
- Supports
$includeand$fromdirectives - Version constraint matching
- Clean, documented C API
A standalone static library that handles parsing of .dmr (DMOD Resource) files.
Location: lib/dmod_resource/
Key Features:
- Parses resource installation mappings
- Environment variable substitution (
${VAR}) - Special variables:
${destination},${module} - Path validation for security
- Clean, documented C API
The user-facing tool that uses the manifest library to download packages.
Location: tools/system/dmf-get/
Key Features:
- Download modules by name and optional version
- Support for HTTP/HTTPS downloads via libcurl
- Environment variable configuration
- Command-line argument parsing
- Automatic directory creation
- Best-match version selection
- Resource installation from DMR files
- Mini mode for minimal installations
The manifest format supports:
# Comments start with #
module_name@version url
module_name url
$include url_to_another_manifest
Two variables are automatically substituted in URLs:
<tools_name>- Direct replacement from config (e.g.,arch/armv7/cortex-m7)<arch_name>- Derived from tools_name:- Removes
arch/prefix if present - Replaces
/with- - Example:
arch/armv7/cortex-m7→armv7-cortex-m7
- Removes
DMOD_TOOLS_NAME- Tools name for variable substitutionDMOD_DMF_DIR- Default output directory for DMF filesDMOD_DMFC_DIR- Default output directory for DMFC filesDMOD_MANIFEST- Default manifest path or URL
When searching for a module:
- Exact version match is preferred
- If no exact match, returns first available version
- If no version specified, returns first entry for that module
Location: tests/lib/tests_dmod_manifest.cpp
Coverage:
- Initialization with/without tools name
- Empty manifest and comments-only
- Simple and versioned entries
- Multiple entries parsing
- Variable substitution (tools_name, arch_name, both)
- Include directive (success and failure)
- Entry finding (by name, by version, not found)
- Error handling (null content, out of bounds, invalid lines)
All tests use Google Test framework and pass successfully.
Location: tests/integration/test_dmf_get.sh
Coverage:
- Help output
- Version output
- Manifest parsing
- Missing module detection
- Variable substitution in manifest
All tests pass successfully.
Added to .github/workflows/ci.yml:
- Install libcurl-dev dependency
- Run manifest library unit tests
- Run dmf-get integration tests
- CMake 3.18+
- C compiler (GCC/Clang compatible)
- libcurl development package (
libcurl4-openssl-dev)
- libcurl (for HTTP/HTTPS downloads)
# Basic download
dmf-get mymodule
# Same as above, using 'install' subcommand (compatible with other package managers)
dmf-get install mymodule
# Specific version
dmf-get mymodule@1.0
# Custom manifest
dmf-get -m https://registry.example.com/manifest.dmm mymodule
# Custom output directory
dmf-get -o /custom/path mymodule
# With tools name for substitution
dmf-get -t arch/armv7/cortex-m7 mymodule
# Mini mode - install only DMF/DMFC files (skip docs, examples, etc.)
dmf-get --mini mymodule
# Download from dependencies file
dmf-get -d project-deps.dmd
# Mini mode with dependencies file
dmf-get --mini -d project-deps.dmdWhen a module package (zip file) contains a .dmr (DMOD Resource File), dmf-get automatically processes it to install additional resources like documentation, headers, examples, and licenses.
When extracting a zip package, dmf-get looks for <module_name>.dmr in the root of the zip. If found, it:
- Parses the resource mappings
- Substitutes environment variables
- Installs each resource to its specified destination
DMR files use the format: key=source_path => destination_path
Example mymodule.dmr:
# Main module file
dmf=./mymodule.dmf => ${DMOD_DMF_DIR}/${module}.dmf
# Documentation
docs=./docs => ${destination}/${module}/docs
# Headers
inc=./include => ${destination}/${module}/include
# License
license=./LICENSE => ${destination}/${module}/LICENSE
Three special variables are available:
${destination}- Installation destination (from-oflag orDMOD_DMF_DIR)${module}- Module name being installed${DMOD_DMF_DIR}- DMF directory from environment
Any environment variable can also be used: ${HOME}, ${USER}, etc.
All resources from the DMR file are installed:
dmf-get mymoduleInstalls:
- DMF/DMFC files
- Documentation
- Headers
- Examples
- Licenses
- All other resources
Only DMF and DMFC resources are installed (skips docs, headers, etc.):
dmf-get --mini mymoduleInstalls:
- DMF/DMFC files only
Use mini mode for:
- Production deployments
- Saving disk space
- Faster installation
- Containerized environments
DMR path validation:
- Rejects paths with shell metacharacters (quotes, semicolons, pipes, etc.)
- Prevents command injection attacks
- Blocks unsafe path patterns
For more details, see DMR File Format documentation.
dmf-get [options] [install] <module_name>[@version]module_name- Name of the module to download@version- Optional version specification- Exact:
@1.0 - Range:
@>=1.0,@<=2.0,@>=1.0<=2.0
- Exact:
-d, --dependencies <path>- Path or URL to dependencies (.dmd) file-m, --manifest <path>- Path or URL to manifest file (default: searches common locations)
-o, --output-dir <path>- Output directory for downloaded modules (default:./dmforDMOD_DMF_DIR)
-t, --tools-name <name>- Tools name for variable substitution (e.g.,arch/armv7/cortex-m7)-a, --arch-name <name>- Architecture name for variable substitution (e.g.,armv7-cortex-m7)--cpu-name <name>- CPU name for variable substitution (e.g.,stm32f746ngh6)--cpu-family <name>- CPU family for variable substitution (e.g.,stm32f7)--type <dmf|dmfc>- Prefer dmf or dmfc file type
--mini- Install only DMF/DMFC files (skip docs, headers, examples, etc.)--no-dependencies- Don't download module dependencies--ignore-missing- Ignore missing dependencies and continue--skip-arch-check- Skip architecture compatibility check--skip-dmod-ver-check- Skip DMOD version compatibility check
-h, --help- Show help message-v, --version- Show version information--verbose- Enable verbose logging
DMOD_TOOLS_NAME- Default tools name (e.g.,arch/x86_64)DMOD_DMF_DIR- Default DMF output directoryDMOD_DMFC_DIR- Default DMFC output directoryDMOD_MANIFEST- Default manifest path or URL
# Download latest version
dmf-get mymodule
# Download specific version
dmf-get mymodule@1.0
# Mini mode (only module files)
dmf-get --mini mymodule
# Custom manifest and output directory
dmf-get -m https://registry.example.com/manifest.dmm -o /opt/modules mymodule
# Architecture-specific download
dmf-get -a armv7-cortex-m7 mymodule
# CPU-specific download
dmf-get --cpu-name stm32f746ngh6 --cpu-family stm32f7 uart
# Download from dependencies file
dmf-get -d project-deps.dmd
# Mini mode with dependencies
dmf-get --mini -d project-deps.dmd
# Skip compatibility checks
dmf-get --skip-arch-check --skip-dmod-ver-check mymodule-
Dependency Resolution
- Parse module metadata from DMF files
- Recursive dependency tree resolution
- Circular dependency detection
- Automatic download of dependencies
-
Caching
- Local cache of downloaded modules
- Version-based cache keys
- Cache cleanup utilities
-
Security
- Checksum verification
- Digital signature support
- Trust store for publishers
-
User Experience
- Progress bars for downloads
- Parallel downloads for dependencies
- Better error messages with suggestions
- Dry-run mode
-
Archive Support
- Automatic extraction of .zip, .tar.gz files
- Support for DMP packages
The manifest parser is a static library because:
- It might be useful in other tools (e.g., IDE plugins, CI tools)
- It has no dependencies on DMOD's runtime (pure C, portable)
- Easy to test in isolation
- Can be used in both SYSTEM and MODULE builds
The download function is passed as a pointer to allow:
- Easy testing (mock downloads in tests)
- Future replacement (different HTTP libraries, custom protocols)
- Network customization (proxies, authentication, retries)
- No hard dependency on specific network library
Current implementation:
- Uses libcurl with SSL/TLS support
- 30-second timeout for downloads
- Follows redirects (limited)
- Basic error checking
Future improvements needed:
- Certificate verification settings
- Checksum/signature verification
- More robust error handling
- Rate limiting
# Configure for SYSTEM mode with tools enabled
cmake -DDMOD_MODE=DMOD_SYSTEM -DDMOD_BUILD_TOOLS=ON -B build -S .
# Build
cmake --build build/
# Run tests
./build/tests/tests_dmod_manifest
./tests/integration/test_dmf_get.sh build- Update
dmod_manifest.hif adding library features - Implement in
dmod_manifest.c - Add tests in
tests_dmod_manifest.cpp - Update tool in
tools/system/dmf-get/main.cif needed - Update integration tests
- Update documentation
Issue: "Could NOT find CURL"
- Solution: Install libcurl-dev:
apt-get install libcurl4-openssl-dev
Issue: "Module not found"
- Check manifest file is valid
- Verify module name and version
- Check environment variables
Issue: "Failed to download"
- Check network connectivity
- Verify URL is accessible
- Check firewall/proxy settings
- DMOD Main README:
/README.md - Tool README:
/tools/system/dmf-get/README.md - Library Headers:
- Manifest Parser:
/lib/dmod_manifest/dmod_manifest.h - Dependencies Parser:
/lib/dmod_dependencies/dmod_dependencies.h - Resource Parser:
/lib/dmod_resource/dmod_resource.h
- Manifest Parser:
- File Format Documentation:
- DMR File Format - Resource installation mappings
- DMD File Format - Dependencies specification
- DMM File Format - Module manifest format
- Integration Tests:
/tests/integration/test_dmf_get.sh