This guide is for users who are developing systems using Baserock tooling for an ARM device. It assumes you have a Trove and an ARM distbuild network set up already.

It assumes you have a project definitions in your Trove that has been forked from the Baserock reference system definitions.

Placeholders that are used in this guide:

- $trove -- hostname and trove-id of your Trove
- $project -- name of your project
- $project/definitions -- your project definitions repo

All commands should be run in your Baserock chroot unless otherwise noted.


Set up a Baserock chroot (or VM) on your main development machine.

Configure Git and

git config --global "John Doe"
git config --global

Create a morph.conf file in /src

log = /src/morph.log
log-max = 200M
cachedir = /src/cache
tempdir = /src/tmp
trove-host = hostname-of-trove
trove-id = trove-id-of-your-trove
controller-initiator-address = hostname-of-your-controller-initiator

Then create a symlink to it from /etc:

ln -sv /src/morph.conf /etc/morph.conf

This way if you replace your chroot (or VM's root disk) you only need to re-create the symlink, as the contents of /src are shared between all versions.

Building a system

# Clone the definitions repository
git clone git://$trove/$projects/definitions /src/

# build the ARMv7 LHF base system
cd /src/definitions
morph distbuild systems/base-system-armv7lhf-generic.morph

Deploying a system to .tar file

# Work in your checked out definitions directory
cd /src/definitions

# Create the cluster definition file for the tarball
cat > tar.morph <<EOF
name: tar
kind: cluster
- morph: systems/base-system-armv7lhf-generic.morph
      type: extensions/tar
      location: rootfs.tar

# Deploy the built system using the cluster definition file
morph deploy tar.morph

# rootfs.tar now exists and you can unpack it to an SD card and boot
# your device.

Partial deployment

NOTE: This should not be used when deploying production systems, as it has a number of limitations.

It may be useful during development to be able to deploy just a chunk and its dependencies, rather than the whole system.

# Work in your checked out definitions directory
cd /src/definitions

# Create the cluster definition file for the partial deployment
cat > partial-tar.morph <<EOF
name: partial-tar
kind: cluster
- morph: systems/base-system-armv7lhf-generic.morph
      type: extensions/tar
      location: deployed-chunks.tar
      - strata/build-essential/busybox.morph

# Deploy using --partial
morph deploy --partial partial-tar.morph

deployed-chunks.tar now exists, containing busybox and its dependencies. This can now be extracted on top of an existing rootfs. Note that the components listed in partial-deploy-components must be in the system defined above (in the morph field), and can be chunks or strata. This only works for deployments with type: extensions/tar or type: extensions/sysroot.

If morph deploy is run without --partial, then partial-deploy-components is simply ignored and the full system is deployed.

Adding a chunk

To import open source projects into your Trove, see:

To add or change chunks in your systems, see: and (but use morph distbuild in place of morph build and $trove:$project/definitions in place of baserock:baserock/definitions).

Modifying a chunk

To modify a chunk, libpng in the example, do the following:

# Move to your checked out definitions directory
cd /src/definitions

morph get-chunk-details libpng

You should see the following output from morph get-chunk-details libpng:

In stratum graphics-common:
  Chunk: libpng
   Repo: git://
    Ref: 259fb7761d747655c607efcec7a12ff1f3c24561

This provides the details needed to modify the chunk.

# Move to somewhere you can clone the chunk repo.
cd /src/

# Clone the repo URL from the earlier `morph get-chunk-details` output
git clone git://

# <Make your changes to the chunk>
git commit
git push

NOTE: you can also use the morph get-repo command.

Now you can update your definitions to reference the updated chunk:

# Move back to your checked out definitions directory
cd /src/definitions

The earlier morph get-chunk-details libpng output showed that libpng was in the graphics-common stratum. Edit stratum/graphics-common.morph and update the libpng chunk's ref field.

Checking definitions reproducibility

Before producing a release, we should ensure that what we release is reproducible. We can use the morph certify tool to do this. In your definitions repo:

# Run the reproducibility certification tool.
morph certify . HEAD systems/base-system-armv7lhf-generic.morph

If it produces any warnings, the current state of definitions cannot be certified as reproducible and it will report FAILED. Otherwise you will see:

=> Reproducibility certification PASSED for

If certification passes, proceed to building the release:

# Build the system
morph distbuild --local-changes=ignore systems/base-system-armv7lhf-generic.morph

Working with binaries in Git repos

Trove allows you to use git-fat to manage binary content that needs to go in your Baserock system. This lets you track the history of the binary files in a Git repo while storing the actual content outside the repo, which stops the repo becoming enormous.

To add a binary file to a chunk repo:

morph add-binary ./large-binary-file

This will run git-fat init for you if needed, and will update and commit the .gitfat and .gitattributes files, in a way that causes large-binary-file to be stored in a special $repo/.gitfat directory on the Trove.

The binary files are not transferred as part of a normal git push operation. You can either use morph push in place of git push, OR use git push && git fat push to push.

Creating a cross-compile SDK

You can use Morph to generate a cross-compile 'SDK' for your rootfs. The SDK is treated as another Baserock system, built for x86_32 or x86_64 and containing your rootfs as a 'nested' system so that the headers and libraries are available. (This can make it rather large; including only the headers and libraries would be a nice improvement).

There are SDK systems in definitions.git for x86_32 and x86_64 hosts, both targetting armv7lhf:

It should be simple to adapt these for other host and/or target platforms.

To build one of these systems, use morph inside your x86_32 chroot (or whatever the host platform is):

# Work in your checked out definitions directory
cd master/$trove/$project/definitions/

morph build systems/armv7lhf-cross-toolchain-system-x86_32.morph

Make sure you have an up-to-date build of your target rootfs in your shared artifact cache, too. (See 'Building a system' section, above).

Now create a cluster (deployment) morph for your SDK system. Below is an example; see the sdk-example-cluster.morph file for further guidance.

name: sdk
kind: cluster
description: Cross-compile SDK for $project
- morph: systems/armv7lhf-cross-toolchain-system-x86_32.morph
      type: extensions/sdk
      location: $
      PREFIX: /usr
      TARGET: armv7lhf-baserock-linux-gnueabi
  - morph: systems/$project-system-armv7lhf.morph
        type: extensions/sysroot
        location: usr/armv7lhf-baserock-linux-gnueabi/sys-root

Replace the $project placeholders in this, save it as sdk.morph and run:

morph deploy sdk.morph

You should get a self-extracting shell script output written to $project-sdk-v1