Build Design Considerations and Reference

Introduction

Fuze is a very flexible build system designed to fit into your build workflow where you see fit. It is designed such that if you currently have a complete build workflow, you can drop it right into Fuze with some minimal effort.

Fuze provides a command line interface (ie, the “build_commands” section of the build map) that allows you to sequentially call your build commands in the syntax and language provided by your CBE. That flexibility does, however, require you to design your strategy for targets, packages, and CBEs, which then informs how you will use the build_commands section of the build map file.

Build and Target Strategy

Fuze allows you to create builds at many different levels. Fuze could replace a build system such as make and call very low level commands such as the compiler and linker. Fuze could also call a very high level script, under which all of the building and packaging occurs. Both are supported, but either may not necessarily be correct for you and your project.

Although Fuze could do either high level or low level, it is best suited for somewhere in the middle, depending upon your project’s particular needs.

The following are some questions to consider about your system and its targets prior to defining your strategy:

  • Each build operation creates a new FuzeID. Therefore, how many FuzeID’s do you want or need for the build artifacts that you will generate?

  • What toolchain(s) and OS are required (ie, what CBE will be created and used)?

  • What dependencies are required?

  • Can I take advantage of interim build products to make builds more time efficient?

Best Practices and Rules

The following lists best practices and guidelines to help you design where Fuze fits into your build system.

Makefile, MSBuild, or Equivalent Rules

  • Assume all dependent files, packages, and directories are in the proper location. Do not perform OS file system manipulation commands that move files and directories. Use the Fuze build map to perform the dependency management and output package creation functions.

  • Create a target for each output image that requires a FuzeID. For example, if you have variant targets for which you would like to have separate versions, create a Makefile target for each of those, and corresponding target sections in the Fuze build map. A single FuzeID is generated per build (ie, Fuze execution), therefore, to generate multiple FuzeIDs for multiple targets, Fuze builds must be executed singularly on those targets.

  • Do not specify paths for the compile and linking toolchain. Assume the toolchain is inherently known, both the version and the path locations. It is the job of the CBE to ensure that the toolchain is available to the build commands. The build map can assume the toolchain and its paths are known. It is the job of the build map to call the proper CBE with the proper toolchain.

  • Create multiple build maps when you require different toolchains for targets. For example, if you wish to build your same firmware target with both GCC v4 and GCC v6, create a build map for each, and then differentiate the toolchains in each target’s build section by referencing a different CBE. By definition, Fuze must generate different FuzeID’s in this case.

  • A “clean” target may not be necessary. Fuze includes a special build target case for the “clean” keyword. Creating a “clean” target in your Makefile, and then calling it from your build map, will NOT perform a local clean as you might expect, since the make clean will execute in the CBE. But, the local cleaning case is covered by the Fuze special build target “clean” case.

  • Use relative paths to any utilities or scripts from the source repository that you require in the Makefile. You are guaranteed that the source repository exists, and the relative paths to any scripts and utilities in the repository are identical to your local file system. For example, if you use a script in your repository to create a source file at build time that assigns the FuzeID to a constant, your Makefile can call that script from its relative location in the repository.

  • Encapsulate your targets. Do NOT create unnecessary, unrelated, or phantom dependencies by assuming all targets are always built. For example, do not assume that a Windows tools build will always execute prior to an ARM firmware build. Note that this does NOT prevent, nor discourage actual dependencies in the build. For example, a composite Makefile build should assume that its constituent modules will be built in a particular order and exist. In fact, your build map file can and should govern that entire procedure.

  • Assume intermediate files/build products are available. The Fuze build map supports intermediate file locations. Including the location of intermediate object files in your build map allows you to cache your build information in your workspace(s), which allows for partial builds and avoiding always “building from scratch”.

Lower Level Build Script Rules

You will have times when it make sense to use scripting underneath the Fuze build map, but on top of make or msbuild. The Fuze build map calls a script, instead of make directly. When using scripts, adhere to the following rules:

  • Do NOT mix script language and OS types. For example, do not build one of your utilities as a Windows batch file and then call another in bash for the same target. This is a style guideline for debug and maintainability purposes, not a technical requirement.

  • Do NOT build output packages indirectly with a script. Use the packaging features of the build map and Fuze. Fuze has no way of knowing any package manipulation that occurs outside of its domain. Our purpose is 100% traceability, therefore, allowing Fuze to be the master of packaging is required.

  • Do NOT perform file system manipulations for the purpose of acquiring or moving build dependencies into place. Allow Fuze and the build map to control all of the dependency manipulation.

    Warning

    File system manipulation outside of Fuze’s knowledge may break its configuration management paradigm.

    Always use Fuze and its automated dependency management facilities to manage dependency locations.

The stack with build scripts may look like this:

_images/fuze-lowlevel-buildscript.png

Where the build-map.json calls the script build.sh, which calls make.

Higher Level Build Script Rules

You will have times when you wish to build scripting on top of or around Fuze. An example of this is a CI tool such as Bamboo or Jenkins. To use Fuze in the CI tool, a script task or pipeline is required to call the Fuze execution command.

The main rule, or consideration is the number of FuzeID’s you wish to produce.

The stack of build scripts looks like this:

_images/fuze-highlevel-buildscript.png

Where the build.sh calls Fuze with the build-map.json, which calls make.

Multiple FuzeID’s vs Single FuzeID for Build Packages

A FuzeID represents a versioned and configuration set of related objects. One consideration when creating build scripts underneath the build map, or around build maps, is how you wish to handle uniquely identifying output build packages. An execution of a build with Fuze will generate a single FuzeID for all targets and packages in that exexution.

If you wish to uniquely identify and version targets and packages from the same build map (ie, generate multiple FuzeID’s), then you must execute Fuze for each unique FuzeID you wish to generate.

Example of Single FuzeID for Multiple Builds and Packages

The following command will build all targets and create all packages specified in the mybuild.json build map, and each package will have the same FuzeID.

fuze --build-map mybuild.json --add-packages

Example of Multiple FuzeID’s From a Single Build Map

The following command sequence will build specific targets and packages and assign unique FuzeID’s for each. In this case, three packages with three unique FuzeIDs are generated.

#!/usr/bin/env bash

fuze --build-map mybuild.json --target dispatch --package dispatch_pkg
fuze --build-map mybuild.json --target utility --package utility_pkg
fuze --build-map mybuild.json --target primary_release --package release_pkg

Dependencies

You can use the [dependencies] section of the build map to specify:

  • A specific version of prebuilt packages: Specify a particular FuzeID for the dependency (note that the dependent package MUST have been priorly built what “is_dependency: true”)

  • Latest prebuilt package: Leave the FuzeID blank

  • Build the dependency from source: Populate the [build_steps], [workspace], and [post_actions] accordingly