Building and Packaging
A Daml application ships as one or more packages. Each package is built into a
DAR file, uploaded to a participant node, and identified on the ledger by its
package ID. DamlForge compiles .vy files into the Daml source of a package and
uses DPM to build the DAR, so everything DPM does still applies.
This page uses the project from the previous four modules: a main package with
the .vy contracts and a test package with Daml Script tests.
Commands
Section titled “Commands”| Command | What it does |
|---|---|
forge dar <project> -o <file.dar> |
Compiles every .vy file in the project, then runs dpm build |
forge daml <file-or-dir> -o <dir> |
Compiles .vy files to .daml without building a DAR |
forge stubs <file.dar> -o <dir> |
Writes .vy declarations for the templates and types in a DAR |
forge json <file.vy> |
Prints the parsed .vy file as JSON |
dpm build / dpm build --all |
Builds one package, or every package in multi-package.yaml |
dpm test |
Runs the Daml Script tests in the current package |
dpm damlc inspect-dar <file.dar> |
Lists the files in a DAR |
forge daml writes a JSON source map next to each .daml file. Directory input is
intentionally non-recursive; forge dar recursively compiles every .vy below the
project’s configured source directory.
What forge dar does
Section titled “What forge dar does”- Reads
daml.yaml. The project needsname,version,source, and a non-emptydependencieslist. Everydata-dependenciesentry must point to an existing file. - Compiles every
.vyfile undersource, including subdirectories, and writes a.damlfile next to each one. A file’s path gives its module name:daml/Finance/Coin.vybecomesmodule Finance.Coin. - Runs
dpm buildand writes the DAR. Without-o, the DAR goes to<project>/<name>-<version>.dar. DPM’s own default,.daml/dist/<name>-<version>.dar, is where other packages in a multi-package project look for it, so the examples pass that path to-o. - Maps
damlcerrors back to.vylines. Whendamlcreports an error in a generated file, DamlForge adds the.vyfile and line it came from.
The generated .daml files are ordinary Daml, so you can read them to see exactly
what was compiled.
Package configuration
Section titled “Package configuration”main/daml.yaml for the project used in these modules:
sdk-version: 3.5.2name: guide-mainsource: damlversion: 0.0.1dependencies: - daml-prim - daml-stdlibbuild-options: - --target=2.3 - -Wno-upgrade-interfacesThese settings change what DamlForge generates or accepts:
| Setting | Effect |
|---|---|
sdk-version |
3.5 enables contract keys and Serializable derivation; 3.4 doesn’t support keys |
--target=2.3 |
Required for contract keys (DF1234) |
--explicit-serializable=yes |
With SDK 3.5, data types derive Serializable |
-Wno-upgrade-interfaces |
Lets interfaces and their implementations share a package |
forge daml uses the nearest daml.yaml in the input’s directory or its parents.
Without one, it applies no SDK checks.
Multi-package projects
Section titled “Multi-package projects”dpm new creates two packages and a multi-package.yaml that lists them:
packages:- ./main- ./testThe test package depends on the DAR of the main package:
sdk-version: 3.5.2name: guide-testsource: damlversion: 0.0.1dependencies: - daml-prim - daml-stdlib - daml-scriptdata-dependencies: - ../main/.daml/dist/guide-main-0.0.1.darbuild-options: - --target=2.3A package that depends on a DAR built for LF 2.3 must target LF 2.3 or later too,
or damlc reports dependencies have incompatible LF versions.
Build the .vy package first, then the rest:
forge dar main -o main/.daml/dist/guide-main-0.0.1.dardpm build --allcd test && dpm testdpm build --all reuses the generated .daml files in main, so it only needs
forge dar to have run after the last .vy change.
dependencies and data-dependencies
Section titled “dependencies and data-dependencies”dependenciesis for the Daml libraries that come with the SDK:daml-prim,daml-stdlib, anddaml-script.data-dependenciesis for DARs: your own packages and third-party ones. Daml reads only the compiled Daml-LF from them, so they can come from a ledger or an older SDK.
Keep daml-script out of the packages you deploy. It’s for tests, and it isn’t
compatible across SDK versions.
Using other packages from .vy
Section titled “Using other packages from .vy”A .vy file can import from three places:
- Other
.vyfiles in the same package, by module name:from Coin import Coin. - The Daml standard library, through stubs that ship with DamlForge:
from DA.List import sort. The compiler adds the matching Daml import. - Splice packages, through bundled stubs:
from Splice.Amulet import Amulet. The project must also list the matching Splice DAR indata-dependencies, sodamlccan find the real definitions.
A .vy package can’t import templates from a DAR you built yourself. Stubs
generated into the source directory would be compiled into the package as new
modules instead of referring to the DAR. Keep .vy modules that use each other in
one package, and consume its DAR from Daml packages, such as the test package,
with data-dependencies.
Inspecting a DAR
Section titled “Inspecting a DAR”A DAR is a ZIP archive:
dpm damlc inspect-dar main/.daml/dist/guide-main-0.0.1.darIt contains:
- a
.dalffile for the package and for each dependency, holding the compiled Daml-LF that participants run; - the
.damlsource of each module, as generated by DamlForge (the.vyfiles aren’t included); .hiand.hieinterface files, used bydependenciesand IDEs;- a
META-INF/MANIFEST.MFthat names the main package.
--json prints the same information as JSON, including main_package_id. The
ledger identifies templates by package ID, module, and name, never by package name
or version. Any change to a package changes its ID and the IDs of the packages
that depend on it.
forge stubs turns a DAR back into .vy declarations, with choice bodies left as
pass. Use it to read the API of a package you depend on:
forge stubs main/.daml/dist/guide-main-0.0.1.dar -o stubs --module CoinIt needs the stubgen extra (pip install 'damlforge[stubgen]'), and reads DARs for
LF 2.1 to 2.3.
It accepts either a DAR file or a Daml project directory (the latter is built with DPM first):
forge stubs path/to/package.dar -o generated/forge stubs path/to/daml_project -o generated/ --dpm /path/to/dpmforge stubs path/to/package.dar --module Some.Module --module Other.ModuleThe --module option may be repeated and selects modules from the main package or
its dependencies. Unsupported declarations are skipped and reported by the command.
Deciding what goes in a package
Section titled “Deciding what goes in a package”- Separate tests from contracts. Tests depend on
daml-script, which shouldn’t be uploaded to a production ledger. That’s whydpm newcreates a separatetestpackage. - Separate public APIs from implementations. Interfaces that other teams
build on should change rarely, so they belong in their own package, as in the
Token Standard. With DamlForge, an interface and the templates that implement it
must currently share a
.vypackage (see above), so this split is only possible when the implementations are written in Daml. - Separate by business domain. Stakeholders can review and upload only the packages for the workflows they take part in.
Next steps
Section titled “Next steps”Variants goes deeper into sum types: payload styles, recursive
and generic variants, and how to test them. Compiler Errors
is the reference for every DF error code, and the
examples directory has larger projects, including Splice token
standard contracts.