blob: 87e9ec14692f4c14df0d4a8ab268d878e2c51c07 [file] [view] [edit]
# Calculator example
This simple command-line calculator example illustrates how to use Dart Dynamic
Modules. Please refer to the package [readme](../README.md) for details about
what Dynamic Modules are, their limitations, typical steps to use them, and how
this example maps to those steps.
The code in this folder is a simple calculator command line interface that lets
users extend it with new operations beyond those built-in.
We recommend exploring the example in this order:
* Check out `dynamic_interface.yaml` and `common/common.dart`. These define the
API surface area. That is, the interface exposed to dynamic modules to define
new operations, as well as the API to register them.
* Then, see `host/main.dart`. This defines the main REPL and provides one
built-in operation (the addition operation).
* Then, check the files under the `modules/` subfolder. Each file defines a
dynamic module that provides new operations for the calculator following the
API surface area defined earlier.
* Finally look at the `run.sh` script to see how the pieces come together.
The `run.sh` script contains a lot of steps and details:
* First, it shows how to build Dart SDK artifacts with support for Dart Dynamic
Modules once you have a proper Dart SDK checkout. A change with how we
normally build Dart is the use of the `--dart-dynamic-modules` build flag.
* Second, it shows how to use the dynamic interface to build various artifacts:
* The unoptimized kernel of the app: an input needed later when compiling
bytecode.
* The optimized AOT kernel of the app: an input to the next step.
* The optimized AOT snapshot of the app: the app that we will be running.
* The bytecode for each dynamic module.
Traditionally compilation of an AOT app is done in a single command (e.g. `dart
compile exe`), but we had to split the underlying logic into multiple steps
(building kernel and snapshots separately). In part, this is because we haven't
added the plumbing to provide the dynamic interface through the regular
commands. But another reason is that we need additional artifacts to anchor the
compilation of dynamic modules later (like the unoptimized kernel), which are
not usually materialized when using the regular commands.
Bytecode files are copied over to a data directory, this is an over simplistic
way to represent the delivery of a dynamic module to an app (rather than using
the network or some other mechanism).
We haven't implemented provenance validation in the package yet, so the
validation step described in the documentation is not represented in the example
yet. We will update it in the future once the corresponding API is added.