Files
ardupilot/Tools/scripts/build_bootloaders.py
T
Thomas Watson dd9bd7a08a Tools: fix build_bootloaders debug symbol flag
The debug flag, contrary to its documentation, enables a debug build,
increasing the size of the binary and changing its contents. Fix the
documentation to describe what it actually does.

Then add the same flag as waf to just add symbols without changing the
actual binary.
2026-04-04 14:34:44 -05:00

189 lines
7.1 KiB
Python
Executable File

#!/usr/bin/env python3
# flake8: noqa
"""
script to build all of our bootloaders using AP_Bootloader and put the resulting binaries in Tools/bootloaders
"""
import os
import shutil
import subprocess
import sys
import fnmatch
import re
# get command line arguments
from argparse import ArgumentParser
parser = ArgumentParser(description='This Program is used to build ArduPilot bootloaders for boards.')
parser.add_argument("--signing-key", type=str, action='append', help="signing key for secure bootloader (can be used multiple times)")
parser.add_argument("--omit-ardupilot-keys", action='store_true', default=False, help="omit ArduPilot signing keys")
parser.add_argument("--debug", action='store_true', default=False, help="configure as debug variant")
parser.add_argument("--debug-symbols", "-g", action='store_true', default=False, help="add debug symbols to build")
parser.add_argument("--periph-only", action='store_true', default=False, help="only build AP_Periph boards")
parser.add_argument("pattern", type=str, default='*', help="board wildcard pattern", nargs='?')
args = parser.parse_args()
os.environ['PYTHONUNBUFFERED'] = '1'
failed_boards = set()
def has_hwdef_bl(board):
"""Return True if libraries/AP_HAL_ChibiOS/hwdef/<board>/hwdef-bl.dat exists"""
hwdef = os.path.join('libraries', 'AP_HAL_ChibiOS', 'hwdef', board, 'hwdef-bl.dat')
return os.path.exists(hwdef)
def read_hwdef(filepath):
'''read a hwdef file recursively'''
fh = open(filepath)
ret = []
text = fh.readlines()
for line in text:
m = re.match(r"^\s*include\s+(.+)\s*$", line)
if m is not None:
ret += read_hwdef(os.path.join(os.path.dirname(filepath), m.group(1)))
else:
ret += [line]
return ret
def is_ap_periph(hwdef):
'''return True if a hwdef is for a AP_Periph board'''
lines = read_hwdef(hwdef)
for line in lines:
if line.find('AP_PERIPH') != -1:
return True
return False
def get_board_list():
'''add boards based on existence of hwdef-bl.dat in subdirectories for ChibiOS'''
board_list = []
dirname, dirlist, filenames = next(os.walk('libraries/AP_HAL_ChibiOS/hwdef'))
for d in dirlist:
hwdef = os.path.join(dirname, d, 'hwdef-bl.dat')
if os.path.exists(hwdef):
if args.periph_only and not is_ap_periph(hwdef):
continue
board_list.append(d)
return board_list
def validate_signing_keys(keys):
"""Validate that all signing key files exist and are not private keys"""
missing_keys = []
private_keys = []
for key in keys:
if not os.path.isfile(key):
missing_keys.append(key)
elif os.path.basename(key).lower().find("private") != -1:
private_keys.append(key)
if missing_keys:
print("Error: The following files were not found:")
for key in missing_keys:
print(f" {key}")
sys.exit(1)
if private_keys:
print("Error: You must use the public key in the bootloader. Check the following files:")
for key in private_keys:
print(f" {key}")
sys.exit(1)
if args.signing_key is not None:
validate_signing_keys(args.signing_key)
def run_program(cmd_list):
print("Running (%s)" % " ".join(cmd_list))
retcode = subprocess.call(cmd_list)
if retcode != 0:
print("Build failed: %s" % ' '.join(cmd_list))
return False
return True
def build_board(board):
# do not attempt to build a bootloader for boards without hwdef-bl.dat
if not has_hwdef_bl(board):
print(f"Skipping {board}: no hwdef-bl.dat (no bootloader for this board)")
return True # treat as success, since there is nothing to build
configure_args = "--board %s --bootloader --no-submodule-update --Werror" % board
configure_args = configure_args.split()
if args.signing_key is not None:
print("Building secure bootloader")
configure_args.append("--signed-fw")
if args.debug:
print("Building debug variant")
configure_args.append("--debug")
if args.debug_symbols:
print("Building with debug symbols")
configure_args.append("--debug-symbols")
if not run_program(["./waf", "configure"] + configure_args):
return False
if not run_program(["./waf", "clean"]):
return False
if not run_program(["./waf", "bootloader"]):
return False
return True
board_list = get_board_list()
def get_all_board_dirs():
dirname, dirlist, filenames = next(os.walk('libraries/AP_HAL_ChibiOS/hwdef'))
return dirlist
all_board_dirs = get_all_board_dirs()
# Determine pattern matches against *all* directories and against buildable boards
matches_all = [b for b in all_board_dirs if fnmatch.fnmatch(b, args.pattern)]
matches_buildable = [b for b in board_list if fnmatch.fnmatch(b, args.pattern)]
# If nothing matches any directory name at all, warn once
if args.pattern != '*' and not matches_all:
print(f"Warning: no board matches pattern '{args.pattern}'. Continuing.")
# For directories that match the pattern but *aren't* buildable (no hwdef-bl.dat),
# print the explicit skip message now so users see why their requested board didn't build.
for b in matches_all:
if b not in board_list:
print(f"Skipping {b}: no hwdef-bl.dat (no bootloader for this board)")
additional_args = []
if args.omit_ardupilot_keys:
# If the user has requested to omit ardupilot keys, ensure it is forwarded to the make_secure_bl program
additional_args.append("--omit-ardupilot-keys")
# check that the user-supplied board pattern matches something; if not, warn and exit
for board in board_list:
if not fnmatch.fnmatch(board, args.pattern):
continue
if not has_hwdef_bl(board):
print(f"Skipping {board}: no hwdef-bl.dat (no bootloader for this board)")
continue
print("Building for %s" % board)
if not build_board(board):
failed_boards.add(board)
continue
bl_file = 'Tools/bootloaders/%s_bl.bin' % board
hex_file = 'Tools/bootloaders/%s_bl.hex' % board
elf_file = 'Tools/bootloaders/%s_bl.elf' % board
shutil.copy('build/%s/bin/AP_Bootloader.bin' % board, bl_file)
print("Created %s" % bl_file)
shutil.copy('build/%s/bootloader/AP_Bootloader' % board, elf_file)
print("Created %s" % elf_file)
if args.signing_key is not None:
print("Signing bootloader with %s" % ", ".join(args.signing_key))
if not run_program(["./Tools/scripts/signing/make_secure_bl.py", *additional_args, bl_file] + args.signing_key):
print("Failed to sign bootloader for %s" % board)
sys.exit(1)
if not run_program(["./Tools/scripts/signing/make_secure_bl.py", *additional_args, elf_file] + args.signing_key):
print("Failed to sign ELF bootloader for %s" % board)
sys.exit(1)
if not run_program([sys.executable, "Tools/scripts/bin2hex.py", "--offset", "0x08000000", bl_file, hex_file]):
failed_boards.add(board)
continue
print("Created %s" % hex_file)
if len(failed_boards):
print("Failed boards: %s" % list(failed_boards))