uhd/.ci/fpga/templates/job-build-fpga.yml
2026-09-29 09:09:08 +02:00

182 lines
6.9 KiB
YAML

#
# Copyright 2022 Ettus Research, a National Instruments Brand
#
# SPDX-License-Identifier: LGPL-3.0-or-later
#
# Description:
#
# This template shall be used for FPGA builds within the uhddev
# repository. Exports the FPGA build results (bitfile, device tree and build
# report from build directory) as artifacts '<target>'.
#
# See description for the parameters below.
#
parameters:
### Required parameters
# FPGA targets to be built.
# E.g.
# targets_matrix:
# X410_XG_100:
# target: X410_XG_100
# timeout: 480
# X410_X4_200:
# target: X410_X4_200
# timeout: 480
- name: targets_matrix
type: object
# IP artifact name (from pipeline) to be used
- name: ip_artifact
type: string
# PATH to device's top directory (where Makefile is located)
- name: top_dir
type: string
### Optional parameters
# Set to true if the intermediate files from build-<target> directory should
# be exported for debugging as artifact 'Build artifacts <target> (Attempt <attempt>)'
- name: publish_int_files
type: boolean
default: false
- name: max_parallel
type: number
default: 20
displayName: 'Max parallel jobs'
- name: additional_setup_steps
type: stepList
default: []
- name: rfnoc_include_dir
type: string
default: ""
displayName: RFNoC OOT module path
jobs:
- job: build_fpga
displayName: 'Build FPGA'
timeoutInMinutes: $[ variables['timeout'] ]
pool:
name: Drivers-NIBuildFarm-RFMIBUILD
demands:
- Agent.OS -equals Linux
- SUPER_HIGH_CPU_PER_THREAD
variables:
- group: sdr-pipeline-vars
strategy:
matrix:
${{ parameters.targets_matrix }}
maxParallel: ${{ parameters.max_parallel }}
dependsOn: ${{ parameters.ip_artifact }}
condition: and(succeeded(), eq(variables.BuildRequired, true))
steps:
- ${{ parameters.additional_setup_steps }}
- template: setup_steps.yml
- download: current
artifact: ${{ parameters.ip_artifact }}
displayName: 'Download ${{ parameters.ip_artifact }}'
- bash: |
mv $(Pipeline.Workspace)/${{ parameters.ip_artifact }} \
${{ parameters.top_dir }}/build-ip/
displayName: 'Populate build-ip'
- bash: |
# Purge any existing UHD install
rm -rf $(Build.BinariesDirectory)/prefix $(Build.BinariesDirectory)/build_image_builder
mkdir -p $(Build.BinariesDirectory)/prefix
# hwtools hwsetup.sh will setup a venv, so we'll reuse that for the
# image builder! That's also why we install the image builder in the
# same step as building the bitfile: To avoid having to run hwsetup.sh
# twice.
echo "##[group]Setting up build environment..."
source $(Build.SourcesDirectory)/uhddev/.ci/fpga/scripts/run_setup.sh ./
python3 -m pip install --upgrade pip
pip3 install -U numpy mako "ruamel.yaml<0.18.0" jsonschema
set -o xtrace
# hwsetup.sh injects garbage cmake versions into PATH, so avoid that by
# going straight to /usr/bin/cmake
/usr/bin/cmake -S $(Build.SourcesDirectory)/uhddev/host \
-B $(Build.BinariesDirectory)/build_image_builder \
-DCMAKE_INSTALL_PREFIX=$(Build.BinariesDirectory)/prefix \
-DUHD_BOOST_REQUIRED=OFF \
-DENABLE_LIBUHD=OFF -DENABLE_PYMOD_UTILS=ON \
-DENABLE_DOXYGEN=OFF -DENABLE_MAN_PAGES=OFF -DENABLE_MANUAL=OFF
/usr/bin/cmake --build $(Build.BinariesDirectory)/build_image_builder
/usr/bin/cmake --install $(Build.BinariesDirectory)/build_image_builder
echo "##[group]Executing FPGA build..."
# rfnoc_image_builder does not currently get installed to a bin/ folder
# via pip, so we add it to PATH
export PATH=$BUILD_BINARIESDIRECTORY/prefix/bin:$VIRTUAL_ENV/bin:$PATH
if [ -n "$TARGET_NAME" ]; then
export TARGET_ARG="--target $TARGET_NAME"
fi
if [ -z "$IMAGE_CORE_NAME" ]; then
echo "##vso[task.logissue type=error]image_core_name must be set for proper functioning of pipeline!"
exit 1
fi
if [[ -z "$BUILD_SEED" ]]
then
export BUILD_SEED=$(($(System.JobAttempt)-1))
fi
# Add timeout arg if provided, otherwise don't specify a timeout.
if [ -n "$ATTEMPT_TIMEOUT" ]; then
# Convert from minutes to hours
export TIMEOUT_ARG="--timeout $(echo "scale=2; $ATTEMPT_TIMEOUT / 60.0" | bc)"
else
export TIMEOUT_ARG=""
fi
if [[ -n "${{ parameters.rfnoc_include_dir }}" ]]; then
export INCLUDE_DIR_ARG="--include-dir ${{ parameters.rfnoc_include_dir }}"
fi
python3 ../../tools/utils/repeat_fpga_build.py \
--image-core $(image_core) $TARGET_ARG $BITFILE_NAME_ARG $INCLUDE_DIR_ARG \
--image-core-name $IMAGE_CORE_NAME \
--vivado-path $XILINX_VIVADO \
--num $(max_attempts) --seed $BUILD_SEED --persistent \
$TIMEOUT_ARG
pip3 uninstall -y uhd
workingDirectory: ${{ parameters.top_dir }}
displayName: 'Build Target'
name: build_target
# Publish the final result only if all previous steps passed
- publish: ${{ parameters.top_dir }}/build
artifact: '$(artifact_name)'
displayName: 'Publish FPGA'
# Create a variable so we know that we generated this artifact
- bash: |
echo "##vso[task.setvariable variable=GeneratedArtifact_$(artifact_name);isOutput=true]true"
echo "##vso[task.setvariable variable=GeneratedArtifact;isOutput=true]true"
echo "Variable name: GeneratedArtifact_$(artifact_name)"
displayName: 'Set GeneratedArtifact variable'
name: set_generated_artifact_variable
# extract build artifact directory
- bash: |
export BUILD_ARTIFACT_DIR=`ls | grep build-usrp`
echo "Build artifact dir: $BUILD_ARTIFACT_DIR"
echo "##vso[task.setvariable variable=BuildArtifactDir;isOutput=true]$BUILD_ARTIFACT_DIR"
echo "##vso[task.setvariable variable=image_core_basename;isOutput=true]`basename $(image_core)`"
workingDirectory: ${{ parameters.top_dir }}
displayName: 'Find Build Artifact Directory'
name: find_build_artifact_dir
condition: and(always(), eq('${{ parameters.publish_int_files }}', true))
# Publish intermediate files.
- publish: ${{ parameters.top_dir }}/$(find_build_artifact_dir.BuildArtifactDir)
artifact: 'Build artifacts for $(find_build_artifact_dir.image_core_basename) (Target $(target_name), Image core name $(image_core_name), Attempt $(System.JobAttempt))'
condition: and(always(), eq('${{ parameters.publish_int_files }}', true))
displayName: 'Publish Build Directory'
# Check if FPGA build left any untracked files.
- template: check_clean_repo_steps.yml
parameters:
directory: ${{ parameters.top_dir }}
- bash: |
make cleanall
workingDirectory: ${{ parameters.top_dir }}
displayName: 'Clean up build artifacts'