The TorizonCore Builder Tool provides a series of commands that allow the quick and easy customization of a Toradex Easy Installer image for deployment and provisioning. Most commands allow for the customization of very specific items, meaning that the full customization of an image would commonly require the execution of multiple such commands. This gives a great deal of flexibility to the user but it also makes the utilization of the tool more difficult. To simplify its usage, the tool provides the build command that allows the full customization of an image as a single step.
This article complies to the Typographic Conventions for the Toradex Documentation.
This article assumes that the tool has been installed as described in Installing TorizonCore Builder.
For a quick hands-on introduction to the tool, go over the User Guide. For more details about the build command and on the contents of the configuration file that controls its behavior, see the Detailed manual. They are both accessible through the tabs below.
In order to leverage the build command you will basically need to:
The easiest and thus recommended way for creating an initial configuration file is by running:
$ torizoncore-builder build --create-templateThe previous command will create a file named
tcbuild.yaml
containing all possible configuration parameters accepted by the command.
The configuration file is in a standard YAML format which should be recognized by most modern programming editors.
Any other name can be chosen for the file, but tcbuild.yaml
is the name that the build command will expect by default when running in build mode.
Most parameters in the generated file will be commented out which can be seen by the #
character at the beginning of each line.
Lines having the characters >>
are just explaining the contents of the file and should be left as-is or removed if desired.
The contents of the file are organized in a tree structure where the leaves are configurable properties. In order to set a certain property you need to make sure all its parent properties are also uncommented (by removing the #
character). For example, below we have a short stretch of the generated configuration file:
# >> The customization section defines the modifications to be applied to get
# >> the desired output image.
# customization:
# >> Splash screen:
# splash-screen: custom-splash-screen.png
If you wanted to set a splash screen, all you would need to do is to uncomment (and edit) the splash-screen
property and its parent properties, in this case the one named customization
, thus producing:
# >> The customization section defines the modifications to be applied to get # >> the desired output image. customization: # >> Splash screen: splash-screen: files/my-splash-screen.pngAlso, the file
files/my-splash-screen.png
should be available before running the build command.
Note: All paths to files or directories in the configuration file are relative to the working directory of the tool, which is set when the torizoncore-builder
alias is created (see the prerequisites section). Moreover, since TorizonCore Builder runs in a container, no paths above the working directory will be accessible by the tool (e.g. ../my-splash-screen.png would not work).
In the following sections we provide some examples that show how easy it is to create a custom image by employing the build command.
A minimal configuration file has to specify at least one input and one output. Below we assume that the input is a previously downloaded Toradex Easy Installer image that is stored in a directory called images
relative to the working directory (set by the alias of the tool).
# Sample configuration file: input: easy-installer: local: images/torizon-core-docker-colibri-imx6-Tezi_5.3.0-devel-202105+build.12.tar output: easy-installer: local: torizon-core-docker-colibri-imx6-Tezi_5.3.0.CUSTOM
Warning: As a general rule, the input image to be customized MUST NOT contain bundled container images – when choosing an image to download, e.g. from Toradex Easy Installer - OS and Demo Images be sure to download an image without evaluation containers.
The directory structure of such a "project" would look like this:
.
├── images
│ └── torizon-core-docker-colibri-imx6-Tezi_5.3.0-devel-202105+build.12.tar
└── tcbuild.yaml
To run the tool one would simply execute:
$ torizoncore-builder buildOnce the build process finishes, the custom Easy Installer image would be present in a directory called
torizon-core-docker-colibri-imx6-Tezi_5.3.0.CUSTOM
.
The input to the tool can be specified in different ways which are described in the Detailed Manual and they are independent of the customization being performed.
Warning: Notice that not all images allow the customization of every possible property that the "build" command provides; e.g. older images may not allow that kernel modules to be built from source and deployed with the image.
In the sample configuration file below, we directly download an image from Toradex's artifacts server:
# Sample configuration file specifying a remote: input: easy-installer: remote: "https://artifacts.toradex.com:443/artifactory/torizoncore-oe-prod-frankfurt/dunfell-5.x.y/release/1/colibri-imx6/torizon-upstream/torizon-core-docker/oedeploy/torizon-core-docker-colibri-imx6-Tezi_5.1.0%2Bbuild.1.tar;sha256sum=5d11dc0b6be688f6a7d159280e9bca15e26bc58732724e3e1dd66b0d0a6ada08" output: easy-installer: local: torizon-core-docker-colibri-imx6-Tezi_5.1.0+build.1.CUSTOM name: "My customized image"Notice the presence of the
sha256sum
parameter which can be used to ensure that the downloaded file has a certain SHA-256 checksum – the tool will stop if the actual file checksum does not match that value (the Detailed Manual gives more information about how a remote location can be specified).
This "project" would simply contain the tcbuild.yaml
file and by running:
$ torizoncore-builder buildYou would get a custom Easy Installer image in the directory
torizon-core-docker-colibri-imx6-Tezi_5.1.0+build.1.CUSTOM
. The only item actually customized in that image is its name
which is shown by the Toradex Easy Installer tool in its UI.
Here we have a configuration file where multiple items are being customized:
# Sample configuration file: input: easy-installer: toradex-feed: version: "5.3.0" release: monthly machine: colibri-imx6 distro: torizon-upstream variant: torizon-core-docker build-number: "12" build-date: "202105" customization: splash-screen: custom/splash-screen.png filesystem: - changes1/ - changes2/ kernel: arguments: - key1=val1 - key2=val2 output: easy-installer: local: torizon-core-docker-colibri-imx6-custom name: "My customized image" description: "My customized image (description)" licence: custom/licence.html release-notes: custom/release-notes.htmlThe input here was defined via the
toradex-feed
property which allows you to set the desired attributes of the image to be downloaded.
Notice also that we are applying two groups of changes to the filesystem which are listed under the customization/filesystem
property. These changes could have been extracted from a live device, for example, by utilizing the torizoncore-builder isolate
command. We are also setting custom kernel arguments and requesting the use of specific licence and release-notes files.
The directory structure of such a "project" could be like this:
.
├── changes1
│ └── usr
│ └── etc
│ ├── test1.txt
│ └── timezone
├── changes2
│ └── usr
│ └── etc
│ └── test2.txt
├── custom
│ ├── licence.html
│ ├── release-notes.html
│ └── splash-screen.png
└── tcbuild.yaml
Again, by simply running:
$ torizoncore-builder buildYou would get your custom Easy Installer image in the directory
torizon-core-docker-colibri-imx6-custom
.
In this sample configuration file we customize the device-tree to be deployed with an image:
# Sample configuration: input: easy-installer: local: images/torizon-core-docker-colibri-imx6-Tezi_5.3.0-devel-202105+build.12.tar customization: device-tree: include-dirs: - device-trees/include/ custom: device-trees/dts-arm32/imx6dl-colibri-eval-v3.dts overlays: add: - device-trees/overlays/colibri-imx6_hdmi_overlay.dts - device-trees/overlays/colibri-imx6_atmel-mxt-connector_overlay.dts output: easy-installer: local: torizon-core-docker-colibri-imx6-custom-dtUsually one would create a device-tree (DT) source file and supply it to the tool via the
customization/device-tree/custom
property. Another, usually simpler, option is to leverage the device-tree source files provided by Toradex along with DT overlays that override the relevant parts of the tree – this was the approach taken on the example. To get the source code of the Toradex supplied device-tree files (including overlays), one could use the torizoncore-builder dt checkout
command. A possibly better solution if you use Git for version control would be to manage these external device-trees through the Git submodule facility.
The directory structure for this "project" would look like this:
.
├── device-trees
│ ├── dts-arm32
│ │ ├── imx6dl-colibri-eval-v3.dts
│ ├── include
│ │ └── dt-bindings
│ │ ├── ...
│ ├── overlays
│ │ ├── ...
│ │ ├── colibri-imx6_atmel-mxt-adapter_overlay.dts
│ │ ├── colibri-imx6_atmel-mxt-connector_overlay.dts
│ │ ├── colibri-imx6_hdmi_overlay.dts
│ │ ├── colibri-imx6_parallel-rgb-lvds_overlay.dts
│ │ ├── colibri-imx6_parallel-rgb_overlay.dts
│ │ ├── ...
│ │ └── Makefile
│ └── README.md
├── images
│ └── torizon-core-docker-colibri-imx6-Tezi_5.3.0-devel-202105+build.12.tar
└── tcbuild.yaml
The device-trees directory subtree might have been obtained via the torizoncore-builder dt checkout
command, as mentioned.
Again, through the execution of:
$ torizoncore-builder buildYou would get a custom Easy Installer image in the directory
torizon-core-docker-colibri-imx6-custom-dt
.
The build command allows you to build and install kernel modules into the deployed OS image. This is demonstrated in this configuration file:
# Sample configuration: build virtual touchscreen into the image input: easy-installer: local: images/torizon-core-docker-colibri-imx6-Tezi_5.3.0-devel-202105+build.12.tar customization: kernel: modules: - source-dir: virtual_touchscreen/ autoload: no output: easy-installer: local: torizon-core-docker-colibri-imx6-vtIn this case, by running:
$ torizoncore-builder buildThe tool would build the kernel module from the sources located in directory
virtual_touchscreen
and create a custom Easy Installer image in the directory torizon-core-docker-colibri-imx6-vt
.
For more general information about the subject, please refer to Building External Kernel Modules With Torizon.
The build command also simplifies the process of bundling container images into an installer image. It is ideal for generating the image to be used during production programming and provisioning multiple devices.
If you want to install both the OS and application during an update, you should not use the Bundling feature. Instead, you should use the synchronous update feature of our Torizon Platform.
A sample configuration file leveraging that feature is this:
# Sample configuration file: input: easy-installer: remote: "https://artifacts.toradex.com:443/artifactory/torizoncore-oe-prod-frankfurt/dunfell-5.x.y/release/1/colibri-imx6/torizon-upstream/torizon-core-docker/oedeploy/torizon-core-docker-colibri-imx6-Tezi_5.1.0%2Bbuild.1.tar;sha256sum=5d11dc0b6be688f6a7d159280e9bca15e26bc58732724e3e1dd66b0d0a6ada08" output: easy-installer: local: torizon-core-docker-colibri-imx6-with-containers name: "My customized image with container images" bundle: compose-file: custom/docker-compose.ymlWith such an input, the tool will fetch the container images referenced by the specified
docker-compose.yml
file and combine them with the installer image. If you don't want the tool to download the images every time the build command is run, you can download them beforehand via the torizoncore-builder bundle
command which will fetch the images and store them into a directory which can then be supplied to the tool via the output/easy-installer/bundle/dir
property (in place of the output/easy-installer/bundle/compose-file
as in the example).
As before, by running:
$ torizoncore-builder buildYou will get a custom Easy Installer image in the directory
torizon-core-docker-colibri-imx6-with-containers
.
Warning: Due to the way TorizonCore Builder works, a directory called certs
will be created in the working directory when build is run with the compose-file
property. This is a known issue that will be solved in a future version of the tool.
A feature that can be especially useful in CI scripts is called variable substitution which allows the replacement of property values (or parts of them) based on parameters passed on the command-line of the tool. The following configuration file employs that feature:
# Sample configuration file: input: easy-installer: remote: "https://artifacts.toradex.com:443/artifactory/torizoncore-oe-prod-frankfurt/dunfell-5.x.y/release/1/colibri-imx6/torizon-upstream/torizon-core-docker/oedeploy/torizon-core-docker-colibri-imx6-Tezi_5.1.0%2Bbuild.1.tar;sha256sum=5d11dc0b6be688f6a7d159280e9bca15e26bc58732724e3e1dd66b0d0a6ada08" output: easy-installer: local: torizon-core-docker-colibri-imx6-with-containers name: "${IMAGE_NAME-Default image name}" description: "${IMAGE_DESC?Please provide a description for this image}" bundle: compose-file: custom/docker-compose.ymlThe value of property
output/easy-installer/name
in the example is set to the value of variable IMAGE_NAME
or to "Default image name" when the variable is not set.
The property output/easy-installer/description
depends on IMAGE_DESC
which is required and if not set will cause the tool to exit showing the specified message.
Running the build command by itself would fail like this:
$ torizoncore-builder build Building image as per configuration file 'tcbuild.yaml'... ** Exiting due to user-defined error: Please provide a description for this image
In order to successfully build an image with the previous configuration file (using the default value for IMAGE_NAME
), one could run:
$ torizoncore-builder build --set IMAGE_DESC="This is the required description"
For more information on the notation for replacing variables in the configuration file, please refer to the Detailed Manual.
We recommend that you take a look at the Detailed Manual tab to get a better understanding of the ideas behind the build command.
To simplify the process of generating custom images for deployment and provisioning, the TorizonCore Builder tool provides the “build” command, whose inputs and outputs are depicted below:
The build process is fully controlled by a configuration file (having a default name of tcbuild.yaml
) which informs the tool what installer image to take as input, what modifications are to be applied (along with the associated data) and what output to produce. Usually the input would be a Toradex Easy Installer image, while the output would be a new, customized image of the same kind.
The configuration file and the artifacts referenced by it are common filesystem objects such as files or directories which can be version controlled allowing for reproducible builds. The artifacts used to customize the output include a splash-screen image, source files for device-tree and device-tree overlays, source code for kernel modules, etc.
The configuration file follows the YAML format and syntax. The tool expects it to be made up of three sections, represented by the top-level properties (keys): input
, customization
and output
as outlined below:
# Configuration file outline: input: # Input section items (required). customization: # Customization section items. output: # Output section items (required).On the next items we describe each one of these properties. The descriptions are organized in the same form as they are expected in the file, for example: to provide a local file as input to the tool, you would set the property
input/easy-installer/local
so you would have to set property local
inside easy-installer
which is in the input
section.
The expected types of the elements in the file are indicated within parenthesis: objects are elements having child properties that in YAML parlance make up a mapping; string, boolean, number, integer types are leaf elements; properties of type array of a certain type represent sequences in the YAML naming. We recommend the usage of double quote "
characters around string values (even though they are not required in YAML) just to avoid them to be interpreted as numbers in some cases.
Note: Use double quote characters around strings.
Many of the properties in the configuration file accept paths to files. Relative paths (those not starting with a / character) are actually relative to the working directory of torizoncore-builder (which is usually set when the alias to invoke the tool is set) and must be underneath it. Absolute paths (which start with a / character) are also possible but they must be specified from the perspective of the container where torizoncore-builder will run. Due to the complications this might cause, we discourage the use of absolute paths in the configuration file.
Warning: Do not use absolute paths in the configuration file.
The input section defines the source artifact for customization. The definition can be provided in two different ways (mutually exclusive):
http://artifactory.toradex.com/.../tezi-image.tar;sha256sum=ad523…da02?key=val1&key2=val2
.
Notice that the sha256sum parameter comes before the query parameters (if any).
The name of the downloaded file will be determined from the last part of the path (the so called slug), if present.
The parameter filename can be employed to force a specific name for the file, e.g.:
http://artifactory.toradex.com/.../tezi-image.tar;filename=teziimage_new.zip?key=val1&key2=val2
.The customization section determines the modifications to be applied to the input to produce the desired output. It has the following structure:
torizoncore-builder isolate
command.torizoncore-builder kernel
command.
The output section provides the details about the output artifact(s) to be produced by the torizoncore-builder build
command. The section has this structure:
torizoncore-builder union
command.
image.json
file.wrapup.sh
file.torizon-core-docker
.torizoncore-builder bundle
command beforehand.torizoncore-builder platform provisioning-data
command. This property must be set both in offline and online modes.torizoncore-builder platform provisioning-data
command or even directly from the UI. The property must be set only in online mode and it is recommended to set it by employing variable substitution whenever possible - this way, its value can be kept outside of version control (for example, one can keep the sensitive data as an environment variable in their CI system which would be passed to torizoncore-builder
upon build time only).In order to simplify the usage of the configuration file in cases where some values need to be set differently on each invocation of the build command, we provide a feature commonly offered by command-line shells called variable substitution.
If such feature is enabled, all occurrences of $VAR
in string values are replaced by the corresponding value of variable named VAR
, which should be provided as part of the torizoncore-builder build
command-line invocation; the notation $$
can be used for inserting a single literal $
sign within strings in the configuration file. Additionally, the following notations are also allowed:
${VAR}
: Same as $VAR
; when the variable is not set in command-line, torizoncore-builder
will issue a warning and assume the variable value is the empty string.${VAR:-default}
: If VAR
is not set or empty, use default
as its value.${VAR-default}
: If VAR
is not set, use default
as its value.${VAR:?error}
: If VAR
is not set or empty, issue the error message error and exit the tool.${VAR?error}
: If VAR
is not set, issue the error message error and exit the tool.In a configuration file, the variable substitution notation would be used like this:
# ... username: "${USERNAME?Please provide a username}" password: "${PASSWORD?Please provide a password}" # ... commit-subject: "${SUBJECT-default commit subject}"
The build command has two different modes of operation. The first one allows the creation of a template configuration file that can then be modified to suit one's needs. In this case, usage is:
torizoncore-builder build [--file NAME] --create-templateIf NAME is not passed, the tool assumes the default file name of
tcbuild.yaml
.
It is possible to check how a template configuration file will be created before creating it. To do this, one would provide the tool with a file name like -
which will cause it to dump the template file contents to standard output, e.g.
$ torizoncore-builder build --file - --create-templateThe second mode of operation, when the switch
--create-template
is not passed, corresponds to the normal operation mode of the tool where it actually processes the configuration file to perform the customization. Usage:
torizoncore-builder build [--file NAME] [--set VAR=VALUE] [--no-subst] [--force]Again, if NAME is not passed the tool assumes the default file name of
tcbuild.yaml
(taken as input in this case). Variables used in the configuration file can be set via the --set
parameter (e.g. --set USERNAME="user1"
). The variable substitution feature which is enabled by default can be disabled completely by the --no-subst
switch. The --force
switch tells the tool to automatically remove the output if it already exists (by default, build fails in that case).
In order to have reproducible builds, one should version control the inputs to the build command – in general, this entails keeping the configuration file and each of the files referenced by it under version control. Moreover, if the configuration file employs variable substitution, the same values should be passed as arguments to build to ensure the same results. The input image does not necessarily need to be version controlled by the user because Toradex already takes care of that – so if you reference a certain quarterly or monthly release, you know that the exact referenced version will be available to you over the Internet (at least for a period of time).
Device-tree (DT) and device-tree overlay (DTO) source files are a kind of input to the build command that may require especial treatment. If you create your own DT or DTO source files then you would keep them under version control as usual. However, if you want to use DT and/or DTO source files supplied by Toradex, then the recommended approach is to set up a Git submodule referencing our device-trees repo – this way, one could more easily keep in sync with upstream changes which is commonly desired.