442 lines
15 KiB
Bash
Executable File
442 lines
15 KiB
Bash
Executable File
#!/bin/bash
|
|
#===============================================================================
|
|
#
|
|
# build.sh
|
|
#
|
|
# Copyright (C) 2013-2026 by Digi International Inc.
|
|
# All rights reserved.
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify it
|
|
# under the terms of the GNU General Public License version 2 as published by
|
|
# the Free Software Foundation.
|
|
#
|
|
#
|
|
# !Description: Yocto autobuild script from Jenkins.
|
|
#
|
|
# Parameters set by Jenkins:
|
|
# DY_BUILD_RELEASE: Build for release mode
|
|
# DY_BUILD_TCHAIN: Build toolchain for DEY images
|
|
# DY_DISTRO: Distribution name (the default is 'dey')
|
|
# DY_PLATFORMS: Platforms to build
|
|
# DY_REVISION: Revision of the manifest repository (for 'repo init')
|
|
# DY_RM_WORK: Remove the package working folders to save disk space.
|
|
# DY_TARGET: Target image (the default is platform dependent)
|
|
# DY_USE_MIRROR: Use internal Digi mirror to download packages
|
|
# DY_CVE_REPORT: Generate Vigiles CVE report
|
|
# DY_VIGILES_DIR: Path to Vigiles configuration files on the build server
|
|
# DY_USE_CVE_LAYER: Apply meta-digi-security layer with CVE fixes
|
|
# DY_MANIFEST: Use specific manifest file (none by default)
|
|
#
|
|
#===============================================================================
|
|
|
|
set -e
|
|
|
|
MANIFEST_URL="ssh://git@stash.digi.com/dey/digi-yocto-sdk-manifest.git"
|
|
|
|
DIGI_PREMIRROR_CFG="
|
|
# Use internal mirror
|
|
SOURCE_MIRROR_URL = \"http://log-sln-jenkins.digi.com/yocto/downloads/\"
|
|
INHERIT += \"own-mirrors\"
|
|
BB_GENERATE_MIRROR_TARBALLS = \"1\"
|
|
"
|
|
|
|
RM_WORK_CFG="
|
|
INHERIT += \"rm_work\"
|
|
# Exclude rm_work for some key packages (for debugging purposes)
|
|
RM_WORK_EXCLUDE += \"dey-image-qt dey-image-webkit linux-dey qtbase u-boot-dey\"
|
|
"
|
|
|
|
VIGILES_CFG="
|
|
unset do_vigiles_check[noexec]
|
|
VIGILES_KEY_FILE = \"${DY_VIGILES_DIR}/linuxlink_key.json\"
|
|
VIGILES_DASHBOARD_CONFIG = \"##VIGILES_CONF_PATH##\"
|
|
VIGILES_SUBFOLDER_NAME = \"${DY_REVISION}\"
|
|
INHERIT += \"##VIGILES_BBCLASS##\"
|
|
"
|
|
|
|
SDCARD_FSTYPE="
|
|
IMAGE_FSTYPES:append:ccimx6 = \" wic.bmap wic.gz\"
|
|
IMAGE_FSTYPES:append:ccimx8x = \" wic.bmap wic.gz\"
|
|
IMAGE_FSTYPES:append:ccimx8m = \" wic.bmap wic.gz\"
|
|
IMAGE_FSTYPES:append:ccimx9 = \" wic.bmap wic.gz\"
|
|
"
|
|
|
|
SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-$(date +%s)}"
|
|
BUILD_TIMESTAMP="
|
|
SOURCE_DATE_EPOCH = \"${SOURCE_DATE_EPOCH}\"
|
|
REPRODUCIBLE_TIMESTAMP_ROOTFS = \"${SOURCE_DATE_EPOCH}\"
|
|
"
|
|
|
|
REPO="$(which repo)"
|
|
|
|
error() {
|
|
printf "%s" "${1}"
|
|
exit 1
|
|
}
|
|
|
|
#
|
|
# Copy buildresults (images, licenses, packages)
|
|
#
|
|
# $1: destination directoy
|
|
# $2: action (full or partial)
|
|
#
|
|
copy_images() {
|
|
local action="$2"
|
|
|
|
# Copy individual packages only for 'release' builds, not for 'daily'.
|
|
# For 'daily' builds just copy the firmware images (the buildserver
|
|
# cannot afford such amount of disk space)
|
|
if [ "${DY_BUILD_RELEASE}" = "true" ]; then
|
|
cp -u -r tmp/deploy/* "${1}"/
|
|
else
|
|
cp -u -r tmp/deploy/images "${1}"/
|
|
if [ "${DY_BUILD_TCHAIN}" = "true" ]; then
|
|
if [ -d tmp/deploy/sdk ]; then
|
|
cp -u -r tmp/deploy/sdk "${1}"/
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [ "${action}" = "full" ]; then
|
|
# Images directory post-processing
|
|
# - Jenkins artifact archiver does not copy symlinks, so remove them
|
|
# beforehand to avoid ending up with several duplicates of the same
|
|
# files.
|
|
# - Remove 'README_-_DO_NOT_DELETE_FILES_IN_THIS_DIRECTORY.txt' files
|
|
# - Create MD5SUMS file
|
|
find "${1}" -type l -delete
|
|
find "${1}" -type f -name 'README_-_DO_NOT_DELETE*' -delete
|
|
find "${1}" -type f -not -name MD5SUMS -print0 | xargs -r -0 md5sum | sed -e "s,${1}/,,g" | sort -k2,2 > "${1}"/MD5SUMS
|
|
fi
|
|
}
|
|
|
|
#
|
|
# For a given image recipe print the SWU recipe (if it exists)
|
|
#
|
|
# $1: image recipe
|
|
#
|
|
swu_recipe_name() {
|
|
if [ -n "$(find "${YOCTO_INST_DIR}"/sources/meta-digi -type f -name "${1}-swu.bb")" ]; then
|
|
printf "%s-swu" "${1}"
|
|
fi
|
|
}
|
|
|
|
#
|
|
# For a given image recipe add/remove additional Yocto local.conf configuration
|
|
#
|
|
# $1: image recipe
|
|
# $2: action (add or remove)
|
|
# $3: path to conf file
|
|
#
|
|
handle_extra_yocto_conf() {
|
|
local target="$1"
|
|
local action="$2"
|
|
local conf_file="$3"
|
|
local conf_string
|
|
local start_marker
|
|
local end_marker
|
|
|
|
if [[ ! -v EXTRA_YOCTO_CONF["$target"] ]]; then
|
|
return 0
|
|
fi
|
|
|
|
conf_string="${EXTRA_YOCTO_CONF[$target]}"
|
|
|
|
start_marker="# BEGIN extra config for ${target}"
|
|
end_marker="# END extra config for ${target}"
|
|
|
|
case "$action" in
|
|
add)
|
|
printf "\n[INFO] Adding extra local.conf configuration for target '%s'\n" "$target"
|
|
|
|
{
|
|
printf "\n%s\n" "$start_marker"
|
|
printf "%s\n" "$conf_string"
|
|
printf "%s\n" "$end_marker"
|
|
} >> "$conf_file"
|
|
;;
|
|
|
|
remove)
|
|
printf "\n[INFO] Removing extra local.conf configuration for target '%s'\n" "$target"
|
|
|
|
if grep -Fq "$start_marker" "$conf_file"; then
|
|
sed -i "\|${start_marker}|,\|${end_marker}|d" "$conf_file"
|
|
else
|
|
printf "\n[INFO] No extra local.conf configuration found for target '%s'\n" "$target"
|
|
fi
|
|
;;
|
|
|
|
*)
|
|
printf "\n[ERROR] Invalid Yocto conf action: %s\n" "$action"
|
|
return 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
#
|
|
# For a given image recipe add/remove additional yocto layers required
|
|
#
|
|
# $1: image recipe
|
|
# $2: action (add or remove)
|
|
#
|
|
handle_extra_yocto_layers() {
|
|
local target="$1"
|
|
local action="$2"
|
|
local items_string
|
|
local item
|
|
local layer_path
|
|
|
|
if [[ ! -v EXTRA_YOCTO_LAYERS["$target"] ]]; then
|
|
return 0
|
|
fi
|
|
|
|
items_string="${EXTRA_YOCTO_LAYERS[$target]}"
|
|
|
|
if [[ "$action" == "remove" ]]; then
|
|
reversed=""
|
|
|
|
# Convert string to array using spaces as separator
|
|
items=($items_string)
|
|
|
|
for (( i=${#items[@]} - 1; i >= 0; i-- )); do
|
|
reversed+="${items[$i]} "
|
|
done
|
|
|
|
items_string="$reversed"
|
|
fi
|
|
|
|
printf "\n[INFO] '%s' requires manage additional Yocto layers\n" "$target"
|
|
|
|
for item in $items_string; do
|
|
layer_path="${YOCTO_INST_DIR}/sources/${item}"
|
|
|
|
case "$action" in
|
|
add)
|
|
printf "\n[INFO] Adding layer '%s' for '%s'\n" "$item" "$target"
|
|
bitbake-layers add-layer "$layer_path"
|
|
;;
|
|
|
|
remove)
|
|
printf "\n[INFO] Removing layer: '%s' for '%s'\n" "$item" "$target"
|
|
bitbake-layers remove-layer "$layer_path"
|
|
;;
|
|
|
|
*)
|
|
printf "\n[ERROR] Invalid Yocto layer action: %s\n" "$action"
|
|
return 1
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# Sanity check (Jenkins environment)
|
|
[ -z "${DY_REVISION}" ] && error "DY_REVISION not specified"
|
|
[ -z "${DY_RM_WORK}" ] && error "DY_RM_WORK not specified"
|
|
[ -z "${DY_USE_MIRROR}" ] && error "DY_USE_MIRROR not specified"
|
|
[ -z "${WORKSPACE}" ] && error "WORKSPACE not specified"
|
|
|
|
# Set default settings if Jenkins does not do it
|
|
[ -z "${DY_DISTRO}" ] && DY_DISTRO="dey"
|
|
|
|
[ -z "${DY_BUILD_RELEASE}" ] && [[ "${JOB_NAME}" =~ dey-.*-release ]] && DY_BUILD_RELEASE="true"
|
|
|
|
# If DY_BUILD_TCHAIN is unset, set it for release jobs
|
|
[ -z "${DY_BUILD_TCHAIN}" ] && [ "${DY_BUILD_RELEASE}" = "true" ] && DY_BUILD_TCHAIN="true"
|
|
|
|
# If DY_MFG_IMAGE is unset, set it depending on the job name
|
|
if [ -z "${DY_MFG_IMAGE}" ] && echo "${JOB_NAME}" | grep -qs 'dey.*mfg'; then
|
|
DY_MFG_IMAGE="true"
|
|
fi
|
|
|
|
[ -z "${DY_CVE_REPORT}" ] && DY_CVE_REPORT="false"
|
|
[ -z "${DY_USE_CVE_LAYER}" ] && DY_USE_CVE_LAYER="false"
|
|
|
|
[ "${DY_CVE_REPORT}" = "true" ] && [ -z "${DY_VIGILES_DIR}" ] && error "DY_VIGILES_DIR not specified"
|
|
[ "${DY_CVE_REPORT}" = "true" ] && [ -z "${DY_CODENAME}" ] && error "DY_CODENAME not specified"
|
|
|
|
# Per-platform data
|
|
while read -r _pl _tgt; do
|
|
AVAILABLE_PLATFORMS="${AVAILABLE_PLATFORMS:+${AVAILABLE_PLATFORMS} }${_pl}"
|
|
# shellcheck disable=SC2015
|
|
[ -n "${DY_TARGET}" ] && _tgt="${DY_TARGET}" || true
|
|
# Dashes are not allowed in variables so let's substitute them on
|
|
# the fly with underscores.
|
|
eval "${_pl//-/_}_tgt=\"${_tgt//,/ }\""
|
|
done<<-_EOF_
|
|
ccimx8mm-dvk dey-image-qt,dey-image-webkit,dey-image-lvgl,dey-image-flutter
|
|
ccimx8mn-dvk dey-image-qt,dey-image-webkit,dey-image-lvgl,dey-image-flutter
|
|
ccimx8x-sbc-pro dey-image-qt,dey-image-webkit,dey-image-lvgl,dey-image-flutter
|
|
ccimx8x-sbc-express dey-image-qt
|
|
ccimx6qpsbc dey-image-qt,dey-image-webkit,dey-image-lvgl
|
|
ccimx6sbc dey-image-qt,dey-image-webkit,dey-image-lvgl
|
|
ccimx6ulsbc core-image-base,dey-image-qt,dey-image-lvgl
|
|
ccimx6ulstarter core-image-base
|
|
ccimx6ulsom dey-image-mft-module-min
|
|
ccimx6ulrftest dey-image-mft-module-rf
|
|
ccmp15-dvk dey-image-qt,dey-image-webkit,dey-image-lvgl,dey-image-flutter
|
|
ccmp13-dvk core-image-base
|
|
ccmp25-dvk dey-image-qt,dey-image-webkit,dey-image-lvgl,dey-image-flutter,dey-image-containers
|
|
ccimx91-dvk core-image-base
|
|
ccimx93-dvk dey-image-qt,dey-image-lvgl
|
|
ccimx95-dvk dey-image-qt,dey-image-chromium,dey-image-lvgl,dey-image-flutter,dey-image-containers
|
|
_EOF_
|
|
|
|
# Set additional layers required for yocto images
|
|
declare -A EXTRA_YOCTO_LAYERS
|
|
EXTRA_YOCTO_LAYERS["dey-image-containers"]="\
|
|
meta-openembedded/meta-filesystems \
|
|
meta-virtualization \
|
|
meta-digi/meta-digi-containers"
|
|
|
|
# Set additional configurations required for yocto images
|
|
declare -A EXTRA_YOCTO_CONF
|
|
EXTRA_YOCTO_CONF["dey-image-containers"]="\
|
|
DISTRO_FEATURES:append = \" virtualization\" \
|
|
"
|
|
|
|
# Set default values if not provided by Jenkins
|
|
DY_PLATFORMS="${DY_PLATFORMS:-${AVAILABLE_PLATFORMS}}"
|
|
|
|
YOCTO_IMGS_DIR="${WORKSPACE}/images"
|
|
YOCTO_INST_DIR="${WORKSPACE}/digi-yocto-sdk.$(echo "${DY_REVISION}" | tr '/' '_')"
|
|
YOCTO_DOWNLOAD_DIR="${DY_DOWNLOADS:-${WORKSPACE}}/downloads"
|
|
YOCTO_PROJ_DIR="${WORKSPACE}/projects"
|
|
YOCTO_SSTATE_DIR="${DY_SSTATE:-${YOCTO_PROJ_DIR}/sstate-cache}"
|
|
|
|
# If CPUS is unset, set it with the machine cpus
|
|
if [ -z "${CPUS}" ]; then
|
|
CPUS="$(grep -c processor /proc/cpuinfo)"
|
|
fi
|
|
[ "${CPUS}" -gt 1 ] && MAKE_JOBS="-j${CPUS}"
|
|
|
|
printf "\n[INFO] Build Yocto \"%s\" for \"%s\" (cpus=%s)\n\n" "${DY_REVISION}" "${DY_PLATFORMS}" "${CPUS}"
|
|
|
|
# Install/Update Digi's Yocto SDK
|
|
if [ "${DY_BUILD_RELEASE}" = "true" ]; then
|
|
# Start a build release environment from scratch
|
|
rm -rf "${YOCTO_INST_DIR}"
|
|
fi
|
|
mkdir -p "${YOCTO_INST_DIR}"
|
|
if pushd "${YOCTO_INST_DIR}"; then
|
|
# Use git ls-remote to check the revision type
|
|
if [ "${DY_REVISION}" != "master" ]; then
|
|
if git ls-remote --tags --exit-code "${MANIFEST_URL}" "${DY_REVISION}"; then
|
|
printf "[INFO] Using tag \"%s\"\n" "${DY_REVISION}"
|
|
repo_revision="-b refs/tags/${DY_REVISION}"
|
|
elif git ls-remote --heads --exit-code "${MANIFEST_URL}" "${DY_REVISION}"; then
|
|
printf "[INFO] Using branch \"%s\"\n" "${DY_REVISION}"
|
|
repo_revision="-b ${DY_REVISION}"
|
|
else
|
|
error "Revision \"${DY_REVISION}\" not found"
|
|
fi
|
|
fi
|
|
# shellcheck disable=SC2086
|
|
yes "" 2>/dev/null | ${REPO} init --depth=1 --no-repo-verify -u ${MANIFEST_URL} ${repo_revision} ${DY_MANIFEST:+-m ${DY_MANIFEST}}
|
|
${REPO} --no-pager forall --ignore-missing -j4 -p -c 'git clean -fdx'
|
|
# shellcheck disable=SC2016
|
|
${REPO} --no-pager forall --ignore-missing -j4 -p -c 'git remote prune $(git remote)' || true
|
|
# shellcheck disable=SC2086
|
|
time ${REPO} sync -d ${MAKE_JOBS}
|
|
popd
|
|
fi
|
|
|
|
# Clean downloads directory
|
|
if [ "${DY_RM_DOWNLOADS}" = "true" ]; then
|
|
printf "\n[INFO] Removing the downloads folder.\n"
|
|
rm -rf "${YOCTO_DOWNLOAD_DIR}"
|
|
fi
|
|
|
|
# Clean images and projects folders
|
|
rm -rf "${YOCTO_IMGS_DIR}" "${YOCTO_PROJ_DIR}"
|
|
|
|
# Create projects and build
|
|
for platform in ${DY_PLATFORMS}; do
|
|
# The variable <platform>_tgt got its dashes converted to
|
|
# underscores, so we must convert also the ones in ${platform}.
|
|
eval "platform_targets=\"\${${platform//-/_}_tgt}\""
|
|
_this_prj_dir="${YOCTO_PROJ_DIR}/${platform}"
|
|
_this_img_dir="${YOCTO_IMGS_DIR}/${platform}"
|
|
mkdir -p "${_this_img_dir}" "${_this_prj_dir}"
|
|
if pushd "${_this_prj_dir}"; then
|
|
# Configure and build the project in a sub-shell to avoid
|
|
# mixing environments between different platform's projects
|
|
(
|
|
export TEMPLATECONF="${TEMPLATECONF:+${TEMPLATECONF}/${platform}}"
|
|
# shellcheck disable=SC1091,SC2086
|
|
MKP_PAGER="" . ${YOCTO_INST_DIR}/mkproject.sh -p "${platform}" ${DY_MACHINES_LAYER:+-m ${DY_MACHINES_LAYER}} <<< "y"
|
|
# Set a common DL_DIR and SSTATE_DIR for all platforms
|
|
sed -i -e "/^#DL_DIR ?=/cDL_DIR ?= \"${YOCTO_DOWNLOAD_DIR}\"" \
|
|
-e "/^#SSTATE_DIR ?=/cSSTATE_DIR ?= \"${YOCTO_SSTATE_DIR}\"" \
|
|
conf/local.conf
|
|
# Set the DISTRO and remove 'meta-digi-dey' layer if distro is not DEY based
|
|
sed -i -e "/^DISTRO ?=/cDISTRO ?= \"${DY_DISTRO}\"" conf/local.conf
|
|
if ! echo "${DY_DISTRO}" | grep -qs "dey"; then
|
|
sed -i -e '/meta-digi-dey/d' conf/bblayers.conf
|
|
fi
|
|
if [ "${DY_USE_MIRROR}" = "true" ]; then
|
|
sed -i -e "s,^#DIGI_INTERNAL_GIT,DIGI_INTERNAL_GIT,g" conf/local.conf
|
|
printf "%s" "${DIGI_PREMIRROR_CFG}" >> conf/local.conf
|
|
fi
|
|
if [ "${DY_RM_WORK}" = "true" ]; then
|
|
printf "%s" "${RM_WORK_CFG}" >> conf/local.conf
|
|
fi
|
|
printf "%s" "${SDCARD_FSTYPE}" >> conf/local.conf
|
|
# Append extra configuration macros if provided from build environment
|
|
if [ -n "${DY_EXTRA_LOCAL_CONF}" ]; then
|
|
printf "%s\n" "${DY_EXTRA_LOCAL_CONF}" >> conf/local.conf
|
|
fi
|
|
# Add build timestamp
|
|
if [ -n "${BUILD_TIMESTAMP}" ]; then
|
|
printf "%s" "${BUILD_TIMESTAMP}" >> conf/local.conf
|
|
fi
|
|
# Check if it is a manufacturing job and, if the mfg layer is not there, add it
|
|
if [ "${DY_MFG_IMAGE}" = "true" ] && ! grep -qs "meta-digi-mfg" conf/bblayers.conf; then
|
|
sed -i -e "/meta-digi-dey/a\ ${YOCTO_INST_DIR}/sources/meta-digi-mfg \\\\" conf/bblayers.conf
|
|
fi
|
|
# Apply CVE layer if needed (do so before potentially inheriting "digi_ccss" to avoid errors)
|
|
[ "${DY_USE_CVE_LAYER}" = "true" ] && bitbake-layers add-layer "${YOCTO_INST_DIR}"/sources/meta-digi-security
|
|
# If we want to generate a CVE report, update conf/local.conf
|
|
if [ "${DY_CVE_REPORT}" = "true" ]; then
|
|
# Build Vigiles config path using platform and patch status
|
|
status="non-patched"
|
|
bbclass="vigiles"
|
|
[ "${DY_USE_CVE_LAYER}" = "true" ] && { status="patched"; bbclass="digi_ccss"; }
|
|
VIGILES_CONF_PATH="${DY_VIGILES_DIR}/configs/${DY_CODENAME}/${platform}_${status}_config"
|
|
# Return error if config file doesn't exist
|
|
[ ! -f "${VIGILES_CONF_PATH}" ] && error "Cannot find Vigiles config file ${VIGILES_CONF_PATH}"
|
|
printf "%s" "${VIGILES_CFG}" | sed -e "s,##VIGILES_CONF_PATH##,${VIGILES_CONF_PATH},g" -e "s,##VIGILES_BBCLASS##,${bbclass},g" >> conf/local.conf
|
|
fi
|
|
printf "\n[INFO] Show customized local.conf.\n"
|
|
cat conf/local.conf
|
|
|
|
for target in ${platform_targets:?}; do
|
|
# Add additional layers and configs required by this image
|
|
handle_extra_yocto_layers "$target" add
|
|
handle_extra_yocto_conf "$target" add "conf/local.conf"
|
|
|
|
printf "\n[INFO] Building the %s target.\n" "${target}"
|
|
# shellcheck disable=SC2046
|
|
time bitbake "${target}" $(swu_recipe_name "${target}")
|
|
printf "\n[INFO] Building the %s target was finished.\n" "${target}"
|
|
|
|
# Remove additional layers and configs after the build
|
|
handle_extra_yocto_conf "$target" remove "conf/local.conf"
|
|
handle_extra_yocto_layers "$target" remove
|
|
|
|
# Partial build artifacts copy to destination path
|
|
copy_images "${_this_img_dir}" partial
|
|
done
|
|
|
|
# Build the toolchain for DEY images
|
|
if [ "${DY_BUILD_TCHAIN}" = "true" ]; then
|
|
printf "\n[INFO] Building the toolchain for %s.\n" "${platform}"
|
|
time bitbake -c populate_sdk dey-toolchain
|
|
fi
|
|
)
|
|
|
|
# Full build artifacts copy to destination path
|
|
copy_images "${_this_img_dir}" full
|
|
popd
|
|
fi
|
|
done
|