How to: Cross-bootstrap using Morph

These are the steps to cross-bootstrap Baserock from one architecture to another.

0. Check architecture support

Unless you know your architecture is supported by morph, you will need to add your architecture to those supported by morph.

To confirm whether your architecture is supported, look at the definition of valid_archs in the morphlib/__init__.py file of the Morph repository.

If your architecture is not listed, add a descriptive string that morph may use to identify the architecture, and also modify the get_host_architecture() method in morphlib/util.py to contain appropriate detection logic, and return your selected string. When selecting a string be sure to use one that uniquely identifies both the instruction set (ISA) and the call interface (ABI) for the new architecture.

To use your modified morph, please refer to the documentation on using the latest morph.

If you have added support for a new architecture and you are intending to build a system based on the linux kernel, you will also need to provide translation logic to convert the morph architecture string to a linux architecture string. This is maintained in the Baserock Linux repository in a file named morph-arch on the baserock/build-essential branch.

Depending on the software in your system, you may wish to configure various additional build tools to use specific flags for your architecture. For example, to pass compilation flags to GCC, one would edit the shell script named morph-arch-config in the build-essential branch of the GCC repository.

1. Select a target architecture to do the cross-bootstrap

We only have morphologies to do cross-bootstrapping for x86_64, ppc64, armv5l, armv7lhf, armv8l64 and armv8b64, so if your target architecture is one of them you only have to pick one of the morphologies.

On the other hand, if your intention is to do a cross-bootstrap to another architecture you have to create a new morphology as follows:

  • Create a systems/cross-bootstrap-system-TARGET_ARCH-generic.morph file (where TARGET_ARCH is the target architecture) and edit it so that it contains the following (see the most up-to-date example of this here:

    name: cross-bootstrap-system-TARGET_ARCH-generic
    arch: TARGET_ARCH
    description: A system that produces the minimum needed to build a devel system
    kind: system
    strata:
    - name: build-essential
      morph: strata/build-essential.morph
    - name: core
      morph: strata/core.morph
    - name: python-cliapp
      morph: strata/python-cliapp.morph
    - name: python-pygobject
      morph: strata/python-pygobject.morph
    - name: libsoup-common
      morph: strata/libsoup-common.morph
    - name: ostree-core
      morph: strata/ostree-core.morph
    - name: morph-utils
      morph: strata/morph-utils.morph
    - name: cross-bootstrap
      morph: strata/cross-bootstrap.morph
    
  • You must replace TARGET_ARCH for the target architecture in the morphology. The morphology has to be commited and pushed in a git repository.

2. Generate a bootstrap Baserock tarball

Now is time to Cross-build Baserock. We cross-build the cross-bootstrap-system-TARGET_ARCH-generic using the cross-bootstrap command in morph. With this command morph generates a tarball of the system with a script to do finish the building in the target architecture:

  • Execute morph cross-bootstrap for the morphology file created:

    morph cross-bootstrap TARGET_ARCH baserock:baserock/definitions master systems/cross-bootstrap-system-TARGET_ARCH-generic.morph
    

    For this example we assume the morphology is in baserock:baserock/definitions repository and in the master branch.

  • Once morph finishes building, it will tell you where the tarball is.

3. Native building of the cross-bootstrap process

This is the second part of the cross-build process and it has to be done in the target architecture.

  • First of all you have to use the system created. To do that you have two options:

    1. If you have linux running in the target architecture you can copy the tarball there, extract it and then chroot into it with:

      chroot /path/to/extracted/tarball /bin/sh
      
    2. If you do not have a compatible Linux-based OS for the target architecture you can boot the cross-built system directly (e.g. using NFS boot). You will need to build a kernel yourself if you take this approach. Note that the bootstrap tarball doesn't have an init system, you should pass init=/bin/sh to the kernel when you boot into the bootstrap system.

  • Once you are into the filesystem created, you have to execute the native-bootstrap script (located in '/'). This script ends building everything.

    Note: we got a segment fault while directly run the native build script for armv8l64, but pipe the stdout message and background the process will workaround this issue. The reason is still unknown. e.g. ./native-bootstrap > build.log 2>&1 & tail -f build.log

    Note2: cmake failed to build on some of the architectures if the environment parameter $PATH is not set to /usr/bin:/bin:/usr/sbin:/sbin.

4. Using the bootstrap system

With the bootstrap system now we can use morph to build systems. Normally you will want to build a devel-system to start using it instead of the bootstrap system.

  • First of all you have to use the system created. To do that you have two options:

    1. If you have linux running in the target architecture you can copy the tarball there, extract it and then chroot into it with:

      chroot /path/to/extracted/tarball /bin/sh
      

      Note: See 4a for more detailed information.

    2. If you prefer, you also can boot the system (e.g. with NFS boot). The problem to do this is that the system doesn't have Kernel.

      Note: See 4b for more detailed information.

4a. Extra steps with chroot

  • You have to mount some special filesystems inside the chroot. To do that, run this outside the chroot:

    cd /path/to/uncompressed/tarball
    mount -t proc proc proc/
    mount -t sysfs sys sys/
    mount -o bind /dev dev/
    mount -o bind /tmp tmp/
    
  • And then, you are ready to chroot into it:

    chroot . /bin/sh
    PATH=/bin:/usr/bin:/sbin:/usr/sbin
    LD_LIBRARY_PATH=/lib:/lib64
    ldconfig
    
  • Morph uses linux-user-chroot when building, and this does not work inside a chroot. There are two options for fixing this:

    1. Create a bind mount to hide the chroot: cd /path/to/uncompressed/tarball && mount --bind . .
    2. Move the bootstrap filesystem to the top level of another disk. We haven't investigated why it works.

    To test that this works you should be able to run the following into the chroot environment.

    linux-user-chroot / /bin/sh
    

    Note: You will not be able to use Morph if this didn't work. If it works, come back out of the linux-user-chroot before building; you are only running it at this stage to check that it works.

4b. Extra steps if you booted the cross-bootstrap system directly

  • Mount sysfs and proc.

    mount -t sysfs none /sys
    mount -t proc none /proc
    
  • To be able to ssh into it:

    /usr/sbin/sshd-keygen
    /usr/bin/ssh-keygen -A
    /usr/sbin/sshd
    

4c. Build a devel system

Now you are ready to start using baserock, build and deploy a devel system.

Be warned that we use systemd for the network configuration, but cross-bootstrapped systems don't include systemd. This means that if you try to clone definitions, morph will fail to find the remote repository and will say something like: 'unable to look up git.baserock.org'. To fix this, you will need to make a file named resolv.conf in /etc, and add a nameserver entry to it.

How to: Cross-bootstrap using BuildStream

BuildStream is a new build tool which we hope that Baserock will adopt soon.

The Baserock definitions format can be converted to BuildStream's format using the defs2bst tool; you may be able to use the ongoing conversion in the sam/buildstream branch of definitions.git.

You need a couple of BuildStream patches. (For now).

You need to produce a host tools tarball.

Then build a sysroot and kernel for your target. For example:

bst --target-arch=armv8b64 build gnu-toolchain/stage2.bst
bst --target-arch=armv8b64 build bsp/stage2-linux.bst

You can then use bst checkout to check out your build results and use them to boot a system.

We are working on a bst source-bundle command that can then be used to bootstrap a Baserock 'build' system.