Command line interface
DDD has no daemon, no editor plug-in and no state of its own: everything it does happens while a project is being built or delivered, so it is a plain command line tool that reads json files, writes files or a report, and exits. That is what makes it usable from wherever the build already lives - a makefile, a cmake project (see Build integration), a batch file on an engineer’s machine, or a ci job that never sees a terminal.
The same discipline governs the output. The findings - everything the tool has to say about
a project - are written to standard error, one line per finding followed by a summary, while
what a command actually produces (a listing, the dumped dictionary, a json schema, the list
of source files, completion candidates) goes to standard output. The two never mix, so
nothing has to be filtered out of a redirection: ddd dump project.ddd.json >
baseline.json archives the dictionary and nothing else, even on a run that had something to
say about it.
For a job that files findings rather than reads them, seven commands understand
--format json: check, compare, generate, list, dump, sources and
checks. That leaves out schema, cmake-dir and templates-dir, whose output is
machine readable already. In json the diagnostics become part of the document the
command prints, next to whatever else it has to report:
$ ddd generate examples/demo/demo.ddd.json -o build/gen -t examples/templates --format json
{
"diagnostics": [],
"summary": {
"error": 0,
"warning": 0,
"info": 0
},
"generated": [
{
"path": "build/gen/ddd_globals.c",
"status": "created"
},
{
"path": "build/gen/ddd_globals.h",
"status": "created"
},
...
{
"path": "build/gen/DemoDevice.a2l",
"status": "created"
}
]
}
The one exception is ddd dump, whose standard output is itself the payload: there the json
diagnostics go to standard error, so that both formats leave the dictionary alone.
The exit code is the same everywhere, which lets a build system treat DDD like a compiler:
code |
meaning |
|---|---|
|
the command did what it was asked and found nothing worth reporting. |
|
findings: at least one diagnostic of severity |
|
the invocation itself was wrong: an unknown command or option, a required option left out, an unknown check identifier or severity, an attempt to relax a check that cannot be relaxed, an output directory that cannot be written into. The project was never examined, so the absence of findings means nothing here. |
The commands
command |
purpose |
|---|---|
|
run every consistency check on a project or on a single component; with |
|
report whether the candidate delivery can stand in for the baseline. Either side may be an archived dictionary or a project description. |
|
check the project and, if it is consistent, write the c sources and the a2l file into
|
|
print the table of variables with their kind, datatype, unit, shape, initial value with its physical reading, producer and consumers - the quickest answer to “who writes this?”. |
|
print the resolved data dictionary, the contract every backend consumes. This is what
gets archived next to a delivery and handed to |
|
print the json schema of |
|
list every description file the project is built out of, for the dependency list of a build system. |
|
run the language server, speaking the Language Server Protocol on stdin and stdout, so an editor reports the checks while a description file is being written; see Editor integration. |
|
record which project description a build runs DDD on and under which severity policy,
the |
|
list every check with its identifier, its default severity and whether it can be relaxed. |
|
print the directory holding |
|
print the directory holding the example c templates, to copy into a project as a
starting point for its own. They are an example and not a default: no run of
|
FILE is a project description or a single component description in every command that
takes one. A component checks, lists, dumps and generates on its own, which is what lets a
supplier verify a component long before an integrator ever sees it.
The -t of generate has no default at all: an invocation that leaves it out is refused
rather than falling back to templates of DDD’s own.
$ ddd generate examples/demo/demo.ddd.json -o build/gen
usage: ddd generate [-h] [-W CHECK=SEVERITY] [--strict] [--format {text,json}]
-o OUTPUT_DIR -t TEMPLATE_DIR [--const-inputs] [--no-a2l]
[--byte-order {little,big}] [--address-map ADDRESS_MAP]
[--dry-run] [--force]
project
ddd generate: error: the following arguments are required: -t/--template-dir
A default would have to be somebody’s house style, and a project that inherited one without choosing it would find out which one only by reading the generated code; Templates makes that case at length. The a2l is unaffected, since its structure is ASAM’s rather than the project’s: the a2l backend is internal and there is no template directory to give it.
cmake-dir and templates-dir exist for a related reason. Neither the cmake module nor
the example templates have a fixed path once DDD is installed - a wheel, an editable install
and a source checkout put them in three different places - so a project asks the tool it is
actually running where they are instead of hard-coding a guess:
$ ddd templates-dir
/home/you/ddd/examples/templates
How both directories are used from a CMakeLists.txt is in Build integration.
Severity options
check, compare, generate, list and dump all reach the same analysis, so
they all take the same two options for deciding how loud a finding is: -W CHECK=SEVERITY
(repeatable, also spelled --severity) sets one check to error, warning, info
or ignore, and --strict reports every warning as an error.
The reason the policy lives on the command line rather than in the description files is that the same finding means different things in different places. A component checked on its own has no counterpart: the components producing its inputs are by definition not part of the file, and nobody reads its outputs yet, so the two checks about the other side of the interface have to be switched off - while everything DDD can decide from the file alone still applies.
$ ddd check examples/demo/components/controller.ddd.json
examples/demo/components/controller.ddd.json#component.interface[0]: error[missing-producer]: 'ValueA' is read by component 'Controller' but no component declares it as output
examples/demo/components/controller.ddd.json#component.interface[1]: error[missing-producer]: 'ValueB' is read by component 'Controller' but no component declares it as output
examples/demo/components/controller.ddd.json#component.interface[2]: warning[unused-output]: 'ValueE' is written by component 'Controller' but read by nobody
examples/demo/components/controller.ddd.json#component.interface[3]: warning[unused-output]: 'ValueF' is written by component 'Controller' but read by nobody
examples/demo/components/controller.ddd.json#component.interface[4]: warning[unused-output]: 'StateA' is written by component 'Controller' but read by nobody
examples/demo/components/controller.ddd.json#component.interface[5]: warning[unused-output]: 'ValueG' is written by component 'Controller' but read by nobody
examples/demo/components/controller.ddd.json#component.interface[8]: warning[unused-output]: 'AxisA' is written by component 'Controller' but read by nobody
2 errors, 5 warnings
$ ddd check examples/demo/components/controller.ddd.json -W missing-producer=ignore -W unused-output=ignore
ok: 12 variables in 1 component are consistent
A check identifier or a severity that DDD does not know is a usage error rather than a silent no-op, because the opposite behaviour would let a typo in a ci script disable a check for years without anybody noticing:
$ ddd check examples/demo/demo.ddd.json -W no-such-check=ignore
ddd: unknown check 'no-such-check'
$ ddd check examples/demo/demo.ddd.json -W unused-output=nope
ddd: unknown severity 'nope' for check 'unused-output', expected one of error, warning, info, ignore
Both exit with 2. Five checks cannot be relaxed at all - file-not-found,
json-syntax, file-kind, schema and include-cycle - because a file that cannot
be read has nothing further to say, and a run that carried on regardless would report the
absence of findings about a project it never saw. ddd checks marks those (fixed), and
an attempt to override one is refused rather than ignored:
$ ddd check examples/demo/demo.ddd.json -W schema=ignore
ddd: the severity of check 'schema' cannot be changed
--strict is the other end of the same dial: it turns every warning into an error, which is
what a delivery build wants, while the daily build of the same project stays readable. The
full list of checks, with the reasoning behind each default severity, is in
Consistency checks.
The sources of a project
A project description does not name its components on the command line; it pulls them in
through includes, possibly through wildcards, and possibly through further project files.
A build system that made the generated code depend on the project file alone would therefore
be wrong in the ordinary case: editing a component would change nothing the build can see, and
the image would happily link yesterday’s globals and ship yesterday’s a2l.
ddd sources closes that gap. It prints one absolute path per line: the project file
itself and every description it includes however deeply:
$ ddd sources examples/demo/demo.ddd.json
/home/you/ddd/examples/demo/components/controller.ddd.json
/home/you/ddd/examples/demo/components/sensor_hub.ddd.json
/home/you/ddd/examples/demo/components/user_interface.ddd.json
/home/you/ddd/examples/demo/demo.ddd.json
/home/you/ddd/examples/demo/subsystems/logging/event_logger.ddd.json
/home/you/ddd/examples/demo/subsystems/logging/logging.ddd.json
The paths are absolute and always written with forward slashes, on Windows as well, so the list can be pasted into a makefile, a ninja file or a cmake dependency list without being translated first, and a file reached over two different include paths appears once.
The command is deliberately more tolerant than the others: a project whose interfaces disagree
still has a well defined set of source files, and a build system asking what to watch deserves
an answer even while the project does not check out. Only a file that cannot be read at all is
fatal. This is what cmake/Ddd.cmake uses to make a hand written project description watch
its own components, described in Build integration.
With --format json the same list arrives as the sources array of a json document, next
to the diagnostics and their summary, exactly as the other commands report them.
Reference
The reference below is generated from the argument parser of the tool itself, so an option that is added, renamed or removed cannot leave its documentation behind.
ddd
Data dictionary for the global variables of a component based embedded software project.
usage: ddd [-h] [-v]
{check,compare,generate,list,dump,lsp,build-info,schema,sources,checks,cmake-dir,templates-dir}
...
- -h, --help
show this help message and exit
- -v, --version
show program’s version number and exit
ddd build-info
Writes the project description a build runs DDD on, and the severity policy it applies, into a small json file. A build system calls this at configure time so that an editor can report what the build reports. The project description is recorded rather than read: with CMake it is often generated later in the same configure run, out of the link graph.
usage: ddd build-info [-h] -o OUTPUT [--image IMAGE] [-W CHECK=SEVERITY]
[--strict]
project
- project
project or component description file
- -h, --help
show this help message and exit
- -o <output>, --output <output>
file to write the result to
- --image <image>
name of the build target this belongs to
- -W <check=severity>, --severity <check=severity>
severity override the build applies; repeatable
- --strict
the build reports warnings as errors
ddd check
usage: ddd check [-h] [-W CHECK=SEVERITY] [--strict] [--format {text,json}]
[--baseline BASELINE]
project
- project
project or component description file
- -h, --help
show this help message and exit
- -W <check=severity>, --severity <check=severity>
change the severity of a check (error, warning, info, ignore); repeatable
- --strict
report warnings as errors
- --format {text,json}
output format
- --baseline <baseline>
also verify that the project can still replace this published dictionary
ddd checks
usage: ddd checks [-h] [--format {text,json}]
- -h, --help
show this help message and exit
- --format {text,json}
output format
ddd cmake-dir
usage: ddd cmake-dir [-h]
- -h, --help
show this help message and exit
ddd compare
Compares two data dictionaries, or two project descriptions, or one of each. The question is directional: can CANDIDATE stand in for BASELINE?
usage: ddd compare [-h] [-W CHECK=SEVERITY] [--strict] [--format {text,json}]
baseline candidate
- baseline
the published dictionary or project
- candidate
the delivery to judge
- -h, --help
show this help message and exit
- -W <check=severity>, --severity <check=severity>
change the severity of a check (error, warning, info, ignore); repeatable
- --strict
report warnings as errors
- --format {text,json}
output format
ddd dump
usage: ddd dump [-h] [-W CHECK=SEVERITY] [--strict] [--format {text,json}]
project
- project
project or component description file
- -h, --help
show this help message and exit
- -W <check=severity>, --severity <check=severity>
change the severity of a check (error, warning, info, ignore); repeatable
- --strict
report warnings as errors
- --format {text,json}
output format
ddd generate
usage: ddd generate [-h] [-W CHECK=SEVERITY] [--strict] [--format {text,json}]
-o OUTPUT_DIR -t TEMPLATE_DIR [--const-inputs] [--no-a2l]
[--byte-order {little,big}] [--address-map ADDRESS_MAP]
[--dry-run] [--force]
project
- project
project or component description file
- -h, --help
show this help message and exit
- -W <check=severity>, --severity <check=severity>
change the severity of a check (error, warning, info, ignore); repeatable
- --strict
report warnings as errors
- --format {text,json}
output format
- -o <output_dir>, --output-dir <output_dir>
directory the generated files are written to
- -t <template_dir>, --template-dir <template_dir>
directory holding the jinja2 templates of the c sources. Every file in it ending in .jinja2 is rendered to a file named like the template without that extension, so ddd_globals.c.jinja2 produces ddd_globals.c; a name starting with an underscore is a helper that renders nothing on its own, and a name containing {component} is rendered once per component. ‘ddd templates-dir’ prints a set of example templates to copy from
- --const-inputs
declare input variables const in the consumer headers
- --no-a2l
do not write an a2l file
- --byte-order {little,big}
byte order reported in the a2l file, default: little
- --address-map <address_map>
json file mapping variable names to their address in the target, for the a2l file
- --dry-run
report what would be written, write nothing
- --force
generate even if the consistency check fails
ddd list
usage: ddd list [-h] [-W CHECK=SEVERITY] [--strict] [--format {text,json}]
project
- project
project or component description file
- -h, --help
show this help message and exit
- -W <check=severity>, --severity <check=severity>
change the severity of a check (error, warning, info, ignore); repeatable
- --strict
report warnings as errors
- --format {text,json}
output format
ddd lsp
Speaks the Language Server Protocol on stdin and stdout. It reports the consistency checks while a description file is being written, which a json schema cannot do: whether an axis names a declared axis, whether exactly one component produces a name, whether two components agree on a unit. Which project a file belongs to is read from the ‘ddd-build.json’ that ddd_generate writes, so the editor and the build apply the same severities.
usage: ddd lsp [-h] [-b DIR]
- -h, --help
show this help message and exit
- -b <dir>, --build-directory <dir>
directory holding a build of this project; repeatable. Without it the usual build directory names next to the workspace are searched
ddd schema
Prints the json schema of one file format, or writes every schema into a directory with ‘all’. Committing those files and pointing the ‘$schema’ key of each description at the matching one is what gives an editor completion, hover documentation and validation while a description file is being written.
usage: ddd schema [-h] [-o OUTPUT]
{component,constants,dictionary,project,sections,types,units,all}
- kind
- -h, --help
show this help message and exit
- -o <output>, --output <output>
write to this file instead of stdout; with ‘all’ it is the directory the schemas are written into, each named ‘ddd_<kind>.schema.json’
ddd sources
Prints one absolute path per line: the project file and every file it includes however deeply. A build system needs exactly this to know when the generated files are out of date, because a project pulls its components in through ‘includes’ and none of them is named on the command line.
usage: ddd sources [-h] [--format {text,json}] project
- project
project or component description file
- -h, --help
show this help message and exit
- --format {text,json}
output format
ddd templates-dir
The c sources are rendered from templates the project provides, so that their house style is the project’s own. The templates printed here are a working set to copy into a project and change, not a default: nothing falls back to them.
usage: ddd templates-dir [-h]
- -h, --help
show this help message and exit