Which is the best structure for a multi-dar project?

In many cases, we use several Daml packages within a project. There are several reasons for this, e.g. separating out test packages which we don’t want to upload to the ledger, more flexible dependency management, etc.

This approach poses a challenge though: As far as I understand, Daml doesn’t have the notion of “workspace”, which would be a collection of packages (like Rust for instance). In some cases, Daml Studio cannot find all the dependencies of a package if it cannot find the appropriate daml.yaml find in the root folder of the open VSCode window.

I can see two approaches in published reference applications.

Approach #1

One of them is the recently published Wallet Sample App. It has organized the Daml code in four packages like this, each package having its own daml.yaml file specifying its dependencies:

├── main
│   ├── Account
│   │   ├── account.dar
│   │   ├── daml
│   │   │   ├── Account.daml
│   │   │   └── Setup.daml
│   │   ├── daml.yaml
│   │   └── setup.dar
│   ├── Asset
│   │   ├── asset.dar
│   │   ├── daml
│   │   │   ├── Asset.daml
│   │   │   └── Test.daml
│   │   └── daml.yaml
│   ├── Tests
│   │   ├── daml
│   │   │   ├── Account
│   │   │   │   └── Test.daml
│   │   │   └── Asset
│   │   │       └── Test.daml
│   │   ├── daml.yaml
│   │   └── tests.dar
│   └── User
│       ├── daml
│       │   └── User.daml
│       ├── daml.yaml
│       └── user.dar

It has an additional daml.yaml file in the project root, containing:

sdk-version: 2.3.0
name: wallet-refapp
source: daml
init-script: Setup:setup

At first, when I cloned the project and started to look into it, in some modules there appeared an error message stating that the Daml Script module cannot be found. But after building the dars, and restarting VSCode, the error messages went away.

Why does it work after restarting VSCode? And also, what’s the function of the daml.yaml file in the project root?

Approach #2

I can see a different project structure in the daml-finance reference application.

The Daml code is organized like this:

├── package
│   ├── main
│   │   └── daml
│   │       ├── Daml.Finance.Asset
│   │       │   ├── README.md
│   │       │   ├── daml
│   │       │   │   └── Daml
│   │       │   │       └── Finance
│   │       │   │           └── Asset -> ../../../../../../../src/main/daml/Daml/Finance/Asset/
│   │       │   └── daml.yaml
│   │       ├── Daml.Finance.Bond
│   │       │   ├── README.md
│   │       │   ├── daml
│   │       │   │   └── Daml
│   │       │   │       └── Finance
│   │       │   │           └── Bond -> ../../../../../../../src/main/daml/Daml/Finance/Bond
│   │       │   └── daml.yaml
│   │       ├── Daml.Finance.Common
│   │       │   ├── README.md
│   │       │   ├── daml
│   │       │   │   └── Daml
│   │       │   │       └── Finance
│   │       │   │           └── Common -> ../../../../../../..//src/main/daml/Daml/Finance/Common
│   │       │   └── daml.yaml
│   │       ├── Daml.Finance.Derivative
│   │       │   ├── README.md
│   │       │   ├── daml
│   │       │   │   └── Daml
│   │       │   │       └── Finance
│   │       │   │           └── Derivative -> ../../../../../../../src/main/daml/Daml/Finance/Derivative/
│   │       │   └── daml.yaml
│   │       ├── Daml.Finance.Equity
│   │       │   ├── README.md
│   │       │   ├── daml
│   │       │   │   └── Daml
│   │       │   │       └── Finance
│   │       │   │           └── Equity -> ../../../../../../../src/main/daml/Daml/Finance/Equity
│   │       │   └── daml.yaml
│   │       ├── Daml.Finance.Interface.Asset
│   │       │   ├── README.md
│   │       │   ├── daml
│   │       │   │   └── Daml
│   │       │   │       └── Finance
│   │       │   │           └── Interface
│   │       │   │               └── Asset -> ../../../../../../../../src/main/daml/Daml/Finance/Interface/Asset/
│   │       │   └── daml.yaml
│   │       ├── Daml.Finance.Interface.Bond
│   │       │   ├── README.md
│   │       │   ├── daml
│   │       │   │   └── Daml
│   │       │   │       └── Finance
│   │       │   │           └── Interface
│   │       │   │               └── Bond -> ../../../../../../../../src/main/daml/Daml/Finance/Interface/Bond
│   │       │   └── daml.yaml
│   │       ├── Daml.Finance.Interface.Common
│   │       │   ├── README.md
│   │       │   ├── daml
│   │       │   │   └── Daml
│   │       │   │       └── Finance
│   │       │   │           └── Interface
│   │       │   │               └── Common -> ../../../../../../../../src/main/daml/Daml/Finance/Interface/Common/
│   │       │   └── daml.yaml
│   │       ├── Daml.Finance.Interface.Derivative
│   │       │   ├── README.md
│   │       │   ├── daml
│   │       │   │   └── Daml
│   │       │   │       └── Finance
│   │       │   │           └── Interface
│   │       │   │               └── Derivative -> ../../../../../../../../src/main/daml/Daml/Finance/Interface/Derivative/
│   │       │   └── daml.yaml
│   │       ├── Daml.Finance.Interface.Equity
│   │       │   ├── README.md
│   │       │   ├── daml
│   │       │   │   └── Daml
│   │       │   │       └── Finance
│   │       │   │           └── Interface
│   │       │   │               └── Equity -> ../../../../../../../../src/main/daml/Daml/Finance/Interface/Equity/
│   │       │   └── daml.yaml
│   │       ├── Daml.Finance.Interface.Lifecycle
│   │       │   ├── README.md
│   │       │   ├── daml
│   │       │   │   └── Daml
│   │       │   │       └── Finance
│   │       │   │           └── Interface
│   │       │   │               └── Lifecycle -> ../../../../../../../../src/main/daml/Daml/Finance/Interface/Lifecycle/
│   │       │   └── daml.yaml
│   │       ├── Daml.Finance.Interface.Settlement
│   │       │   ├── README.md
│   │       │   ├── daml
│   │       │   │   └── Daml
│   │       │   │       └── Finance
│   │       │   │           └── Interface
│   │       │   │               └── Settlement -> ../../../../../../../../src/main/daml/Daml/Finance/Interface/Settlement/
│   │       │   └── daml.yaml
│   │       ├── Daml.Finance.Lifecycle
│   │       │   ├── README.md
│   │       │   ├── daml
│   │       │   │   └── Daml
│   │       │   │       └── Finance
│   │       │   │           └── Lifecycle -> ../../../../../../../src/main/daml/Daml/Finance/Lifecycle/
│   │       │   └── daml.yaml
│   │       ├── Daml.Finance.RefData
│   │       │   ├── README.md
│   │       │   ├── daml
│   │       │   │   └── Daml
│   │       │   │       └── Finance
│   │       │   │           └── RefData -> ../../../../../../../src/main/daml/Daml/Finance/RefData/
│   │       │   └── daml.yaml
│   │       └── Daml.Finance.Settlement
│   │           ├── README.md
│   │           ├── daml
│   │           │   └── Daml
│   │           │       └── Finance
│   │           │           └── Settlement -> ../../../../../../../src/main/daml/Daml/Finance/Settlement/
│   │           └── daml.yaml
│   └── test
│       └── daml
│           ├── Daml.Finance.Asset.Test
│           │   ├── daml
│           │   │   └── Daml
│           │   │       └── Finance
│           │   │           └── Asset -> ../../../../../../../src/test/daml/Daml/Finance/Asset/
│           │   └── daml.yaml
│           ├── Daml.Finance.Bond.Test
│           │   ├── daml
│           │   │   └── Daml
│           │   │       └── Finance
│           │   │           └── Bond
│           │   │               └── Test -> ../../../../../../../../src/test/daml/Daml/Finance/Bond/Test
│           │   └── daml.yaml
│           ├── Daml.Finance.Common.Test
│           │   ├── daml
│           │   │   └── Daml
│           │   │       └── Finance
│           │   │           └── Common
│           │   │               └── Test -> ../../../../../../../../src/test/daml/Daml/Finance/Common/Test/
│           │   └── daml.yaml
│           ├── Daml.Finance.Derivative.Test
│           │   ├── daml
│           │   │   └── Daml
│           │   │       └── Finance
│           │   │           └── Derivative
│           │   │               └── Test -> ../../../../../../../../src/test/daml/Daml/Finance/Derivative/Test
│           │   └── daml.yaml
│           ├── Daml.Finance.Equity.Test
│           │   ├── daml
│           │   │   └── Daml
│           │   │       └── Finance
│           │   │           └── Equity
│           │   │               └── Test -> ../../../../../../../../src/test/daml/Daml/Finance/Equity/Test
│           │   └── daml.yaml
│           ├── Daml.Finance.RefData.Test
│           │   ├── daml
│           │   │   └── Daml
│           │   │       └── Finance
│           │   │           └── RefData
│           │   │               └── Test -> ../../../../../../../../src/test/daml/Daml/Finance/RefData/Test
│           │   └── daml.yaml
│           ├── Daml.Finance.Settlement.Test
│           │   ├── daml
│           │   │   └── Daml
│           │   │       └── Finance
│           │   │           └── Settlement
│           │   │               └── Test -> ../../../../../../../../src/test/daml/Daml/Finance/Settlement/Test/
│           │   └── daml.yaml
│           └── Daml.Finance.Test.Util
│               ├── daml
│               │   └── Daml
│               │       └── Finance
│               │           └── Test
│               │               └── Util -> ../../../../../../../../src/test/daml/Daml/Finance/Test/Util/
│               └── daml.yaml

...

└── src
    ├── main
    │   └── daml
    │       └── Daml
    │           └── Finance
    │               ├── Asset
    │               │   ├── Account.daml
    │               │   ├── Fungible.daml
    │               │   ├── Instrument.daml
    │               │   ├── NonFungible.daml
    │               │   └── NonTransferable.daml
    │               ├── Bond
    │               │   ├── FixedRate.daml
    │               │   ├── FloatingRate.daml
    │               │   ├── InflationLinked.daml
    │               │   ├── Util.daml
    │               │   └── ZeroCoupon.daml
    │               ├── Common
    │               │   ├── Date
    │               │   │   ├── Calendar.daml
    │               │   │   ├── DayCount.daml
    │               │   │   ├── RollConvention.daml
    │               │   │   └── Schedule.daml
    │               │   └── Util.daml
    │               ├── Derivative
    │               │   ├── Election.daml
    │               │   ├── Factory.daml
    │               │   └── Instrument.daml
    │               ├── Equity
    │               │   ├── Factory.daml
    │               │   └── Instrument.daml
    │               ├── Interface
    │               │   ├── Asset
    │               │   │   ├── Account.daml
    │               │   │   ├── Factory
    │               │   │   │   ├── Account.daml
    │               │   │   │   ├── Holding.daml
    │               │   │   │   └── Instrument.daml
    │               │   │   ├── Fungible.daml
    │               │   │   ├── Holding.daml
    │               │   │   ├── Instrument.daml
    │               │   │   ├── Lockable.daml
    │               │   │   ├── Transferable.daml
    │               │   │   ├── Types.daml
    │               │   │   └── Util.daml
    │               │   ├── Bond
    │               │   │   ├── FixedRate.daml
    │               │   │   ├── FloatingRate.daml
    │               │   │   ├── InflationLinked.daml
    │               │   │   └── ZeroCoupon.daml
    │               │   ├── Common
    │               │   │   ├── Classes.daml
    │               │   │   ├── Disclosure.daml
    │               │   │   ├── Types.daml
    │               │   │   └── Util.daml
    │               │   ├── Derivative
    │               │   │   ├── Election.daml
    │               │   │   ├── Factory.daml
    │               │   │   ├── HasClaims.daml
    │               │   │   ├── Types.daml
    │               │   │   └── Util
    │               │   │       ├── Claims
    │               │   │       │   └── Lifecycle.daml
    │               │   │       └── Claims.daml
    │               │   ├── Equity
    │               │   │   ├── Factory.daml
    │               │   │   └── Instrument.daml
    │               │   ├── Lifecycle
    │               │   │   ├── Clock.daml
    │               │   │   ├── Effect.daml
    │               │   │   ├── Event.daml
    │               │   │   ├── Lifecyclable.daml
    │               │   │   ├── Observable.daml
    │               │   │   └── SettlementRule.daml
    │               │   └── Settlement
    │               │       ├── Instructable.daml
    │               │       ├── Instruction.daml
    │               │       ├── Settleable.daml
    │               │       └── Types.daml
    │               ├── Lifecycle
    │               │   ├── Effect.daml
    │               │   ├── ElectionEffect.daml
    │               │   ├── Event
    │               │   │   ├── Distribution.daml
    │               │   │   └── Replacement.daml
    │               │   └── Rule
    │               │       ├── Distribution.daml
    │               │       ├── Replacement.daml
    │               │       └── Settlement.daml
    │               ├── RefData
    │               │   ├── HolidayCalendar.daml
    │               │   ├── Observation.daml
    │               │   └── Time
    │               │       └── DateClock.daml
    │               └── Settlement
    │                   ├── Batch.daml
    │                   └── Instruction.daml
    └── test
        └── daml
            └── Daml
                └── Finance
                    ├── Asset
                    │   └── Test
                    │       ├── Common.daml
                    │       ├── Fungible.daml
                    │       ├── NoCrossTransfer.daml
                    │       ├── NonFungible.daml
                    │       ├── NonTransferable.daml
                    │       └── Util
                    │           ├── Account.daml
                    │           ├── Holding.daml
                    │           └── Instrument.daml
                    ├── Bond
                    │   └── Test
                    │       ├── FixedRate.daml
                    │       ├── FloatingRate.daml
                    │       ├── InflationLinked.daml
                    │       ├── Util.daml
                    │       └── ZeroCoupon.daml
                    ├── Common
                    │   └── Test
                    │       └── Date
                    │           ├── Calendar.daml
                    │           ├── DayCount.daml
                    │           ├── RollConvention.daml
                    │           └── Schedule.daml
                    ├── Derivative
                    │   └── Test
                    │       ├── CallableBond.daml
                    │       ├── EuropeanOption.daml
                    │       ├── ForwardCash.daml
                    │       ├── ForwardPhysical.daml
                    │       ├── Intermediated
                    │       │   └── BondCoupon.daml
                    │       └── Util.daml
                    ├── Equity
                    │   └── Test
                    │       ├── Dividend.daml
                    │       ├── Merger.daml
                    │       ├── StockSplit.daml
                    │       └── Util.daml
                    ├── RefData
                    │   └── Test
                    │       └── HolidayCalendar.daml
                    ├── Settlement
                    │   └── Test
                    │       ├── Batch.daml
                    │       ├── BatchWithRoute.daml
                    │       ├── Intermediated.daml
                    │       └── Transfer.daml
                    └── Test
                        └── Util
                            └── Common.daml

The Daml source code of the 8 Daml packages is contained in the src folder, without the daml.yaml files. The package folder contains symlinks to the folders containing the Daml code of the packages, and it also contains the daml.yaml files. In the project root, there is a daml.yaml file, with the following content:

sdk-version: 2.4.0-snapshot.20220809.10365.0.7d59e3d4
name: daml-finance
source: src/test/daml
version: 0.1.1
dependencies:
  - daml-prim
  - daml-stdlib
  - daml-script
data-dependencies:
  - lib/contingent-claims-3.0.0.20220721.1.dar
build-options:
  - --target=1.dev
  - --include=src/main/daml

How this project structure works? Why is it useful? Why we need the symlinks? Is this some kind of workaround for the missing “workspace” feature of Daml?

6 Likes

The structure used by the wallet matches the one in the docs. The big caveat with that structure is that changes do not propagate across packages until you rebuild via daml build and reload window/restart vscode. The upside is that it is simple to setup and to understand.

The structure used by finlib tries to build a setup where changes do propagate across packages in vscode. To do that it keeps a single project that you open in vscode so everything works smoothly there and then it symlinks the files into a bunch of separate projects so that daml build can build individual dars. The upside is that it gives you a better ux in daml studio. The downside is that it’s more complex to setup and you might run into some issues where daml build behaves slightly differently from daml studio.

Now the real solution ofc is to provide the nice Daml Studio UX natively but I cannot provide a timeline for that yet.

4 Likes

Thank you!