linuxOS_D21X/tools/scripts/add_board.py
2024-11-29 16:33:21 +08:00

461 lines
15 KiB
Python
Executable File

#!/usr/bin/env python3
# SPDX-License-Identifier: Apache-2.0
# Copyright (C) 2022-2024 ArtInChip
# Wu Dehuang
import os
import sys
import argparse
import subprocess
UBOOT_DIR = 'source/uboot-2021.10/'
LINUX_DIR = ''
def GetLinuxDir(args):
global LINUX_DIR
dirs = os.listdir(args.topdir + '/source')
for sub_dir in dirs:
if 'linux' in sub_dir:
LINUX_DIR = 'source/' + sub_dir + '/'
def RunCommand(cmd, dumpmsg=False, verbose=False):
"""Execute command
Args:
cmd: cmd line content
dumpmsg: display message during cmd execute
Return:
0 if success, -1 if failure.
"""
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=-1)
ret = p.wait()
if ret != 0:
print('Run commmand error:')
print(' ' + cmd)
print('stdout: {}\nstderr: {}'.format(p.stdout.read(), p.stderr.read()))
return -1
if verbose:
print(cmd)
if dumpmsg or verbose:
print(p.stdout.read())
if verbose:
print(p.stderr.read())
return 0
def RunShellCommand(cmd):
ret = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if ret.returncode:
print(indent_str('Failed to run shell command:' + cmd, 1))
sys.exit(1)
return str(ret.stdout, encoding='utf-8')
def indent_str(text, indent):
itext = text
while indent > 0:
itext = '\t' + itext
indent -= 1
return itext
def GetChipList(targetdir):
cmd = 'grep "source *target/" {}'.format(targetdir + 'Config.in')
matchlist = RunShellCommand(cmd)
matchlist = matchlist.replace('source', '').replace('target/', '').replace('/Config.in', '')
matchlist = matchlist.split()
chiplist = []
for c in matchlist:
if os.path.isdir(targetdir + c):
chiplist.append(c)
return chiplist
def SelectChip(chiplist):
num = 1
print(indent_str('Chip list:', 1))
for c in chiplist:
print(indent_str('{}: {}'.format(num, chiplist[num - 1]), 2))
num += 1
inputstr = input(indent_str('Select chip for new board(number): ', 1)).strip()
if inputstr.isdigit() == False:
print(indent_str('Error, please input number'), 1)
sys.exit(1)
num = int(inputstr)
if num not in range(1, len(chiplist) + 1):
print(indent_str('Error, input number not in list', 1))
sys.exit(1)
selected = chiplist[num - 1]
print(indent_str(selected + '\n', 2))
return selected
def GetReferenceBoardDefconfig(targetcfg):
cmd = 'find {} -maxdepth 1 -type f -name "*_defconfig"'.format(targetcfg)
defconfigs = RunShellCommand(cmd)
return defconfigs.split()
def GetChipNameOfDefconfig(dotcfg):
f = open(dotcfg, 'r')
lines = f.readlines()
f.close()
name = None
for ln in lines:
if 'LUBAN_CHIP_NAME' in ln:
name = ln.replace('LUBAN_CHIP_NAME=', '').replace('"', '').strip()
break
return name
def GetChipOptionOfDefconfig(dotcfg, chip):
f = open(dotcfg, 'r')
lines = f.readlines()
f.close()
name = None
for ln in lines:
if 'LUBAN_CHIP_{}'.format(chip.upper()) in ln and '=y' in ln:
name = ln.replace('=y', '').strip()
break
return name
def GetBoardNameOfDefconfig(dotcfg):
f = open(dotcfg, 'r')
lines = f.readlines()
f.close()
name = None
for ln in lines:
if 'LUBAN_BOARD_NAME' in ln:
name = ln.replace('LUBAN_BOARD_NAME=', '').replace('"', '').strip()
break
return name
def GetBoardOptionNameOfDefconfig(dotcfg, board_name):
f = open(dotcfg, 'r')
lines = f.readlines()
f.close()
opt_name = None
for ln in lines:
if 'LUBAN_BOARD_' in ln and board_name.upper() in ln and '=y' in ln:
opt_name = ln.replace('=y', '').strip()
break
return opt_name
def GetArchOfRefDefconfig(dotcfg):
f = open(dotcfg, 'r')
lines = f.readlines()
f.close()
name = None
for ln in lines:
if 'BR2_ARCH=' in ln:
name = ln.replace('BR2_ARCH=', '').replace('"', '').strip()
break
return name
def SelectReferenceDefconfig(chip, defconfigs, dotconfigs):
reflist = []
for cfg in defconfigs:
for dotcfg in dotconfigs:
if os.path.basename(cfg) in dotcfg:
break
chipname = GetChipNameOfDefconfig(dotcfg)
if chipname == chip:
reflist.append(os.path.basename(cfg))
if len(reflist) == 0:
print(indent_str('Error, cannot find reference defconfig', 1))
sys.exit(1)
print(indent_str('Reference defconfig:(Create new board base on selected defconfig)', 1))
num = 1
for ref in reflist:
print(indent_str('{}: {}'.format(num, ref), 2))
num += 1
inputstr = input(indent_str('Select reference defconfig for new board(number): ', 1)).strip()
if inputstr.isdigit() == False:
print(indent_str('Error, please input number'), 1)
sys.exit(1)
num = int(inputstr)
if num not in range(1, len(reflist) + 1):
print(indent_str('Error, input number not in list', 1))
sys.exit(1)
selected = reflist[num - 1]
print(indent_str(selected + '\n', 2))
return selected
def CheckBoardNameIsValid(name):
invalid_name_char = '`~!@#$%^&*()-+=[]\\{}|;\':",./<>?'
for c in invalid_name_char:
if c in name:
return False
return True
def GetBoardNameForConfig(name):
return name.replace('\t', '_').replace(' ', '_')
def GetNewBoardName():
inputstr = input(indent_str("Input new board's name: ", 1)).strip()
if len(inputstr.strip()) == 0:
print(indent_str('Invalid name', 1))
sys.exit(1)
name = inputstr.strip()
if CheckBoardNameIsValid(name) == False:
print(indent_str('Invalid name', 1))
sys.exit(1)
print(indent_str(name + '\n', 2))
return name
def GetNewManufacturerName():
inputstr = input(indent_str("Input manufacturer's name: ", 1)).strip()
if len(inputstr.strip()) == 0:
print(indent_str('Invalid name', 1))
sys.exit(1)
name = inputstr.strip()
print(indent_str(name + '\n', 2))
return name
def GenDotConfig(args, cfg_list):
root_cfg = args.topdir + 'package/Config.in'
dotconfigs = []
tmpdir = os.path.dirname(args.conf) + '/tmp/'
cmd = 'rm -rf {} && mkdir -p {}'.format(tmpdir, tmpdir)
RunShellCommand(cmd)
for cfg in cfg_list:
dotcfg = tmpdir + os.path.basename(cfg) + '.config'
dotconfigs.append(dotcfg)
cmd = 'HOSTARCH={} BR2_CONFIG={} BASE_DIR={} BR2_DEFCONFIG={} {} --defconfig={} {}'.format(args.arch, dotcfg, args.outdir, cfg, args.conf, cfg, root_cfg)
RunShellCommand(cmd)
return dotconfigs
def CreateNewBoardDirectory(topdir, refcfg, dotconfigs, chip, boardname):
for ref_dotcfg in dotconfigs:
if refcfg in ref_dotcfg:
break
boardname_cfg = GetBoardNameForConfig(boardname)
newboard_dir = topdir + 'target/{}/{}'.format(chip, boardname_cfg)
if os.path.exists(newboard_dir):
print(indent_str("board {} already exist.".format(boardname_cfg), 1));
sys.exit(1)
refboardname = GetBoardNameOfDefconfig(ref_dotcfg)
refboard_dir = topdir + 'target/{}/{}'.format(chip, refboardname)
# copy new board directory
cmd = 'cp -rdf {} {}'.format(refboard_dir, newboard_dir)
RunShellCommand(cmd)
print(indent_str('Created: ' + newboard_dir.replace(topdir, ''), 1))
# update product name
cmd = 'find {} -type f -name "*.json" | xargs -I [] sed -i \'s/"product": *"[a-z,0-9,A-Z,_, ]*"/"product": "{}"/g\' []'.format(newboard_dir, boardname_cfg)
RunShellCommand(cmd)
def CreateNewDefconfig(topdir, refcfg, dotconfigs, chip, boardname, manu_name):
global UBOOT_DIR
global LINUX_DIR
for ref_dotcfg in dotconfigs:
if refcfg in ref_dotcfg:
break
arch = GetArchOfRefDefconfig(ref_dotcfg)
refboardname = GetBoardNameOfDefconfig(ref_dotcfg)
refboard_opt = GetBoardOptionNameOfDefconfig(ref_dotcfg, refboardname)
boardname_cfg = GetBoardNameForConfig(boardname)
target_cfgdir = topdir + 'target/configs/'
f = open(target_cfgdir + refcfg, 'r')
lines = f.readlines()
f.close()
# Create U-Boot/Kernel/Busybox defconfig for new board
ref_uboot_cfg = ''
ref_linux_cfg = ''
ref_busybox_cfg = ''
for ln in lines:
if 'BR2_TARGET_UBOOT_BOARD_DEFCONFIG' in ln:
ref_uboot_cfg = ln.replace('BR2_TARGET_UBOOT_BOARD_DEFCONFIG', '').replace('=', '').replace('"', '').strip() + '_defconfig'
if 'BR2_LINUX_KERNEL_DEFCONFIG' in ln:
ref_linux_cfg = ln.replace('BR2_LINUX_KERNEL_DEFCONFIG', '').replace('=', '').replace('"', '').strip() + '_defconfig'
if 'BR2_PACKAGE_BUSYBOX_CONFIG' in ln:
ref_busybox_cfg = ln.replace('BR2_PACKAGE_BUSYBOX_CONFIG', '').replace('=', '').replace('"', '').strip()
# Create defconfig for u-boot
newcfg_name = '{}_{}_defconfig'.format(chip, boardname_cfg)
refcfg_path = '{}{}configs/{}'.format(topdir, UBOOT_DIR, ref_uboot_cfg)
newcfg_path = '{}{}configs/{}'.format(topdir, UBOOT_DIR, newcfg_name)
cmd = 'cp {} {}'.format(refcfg_path, newcfg_path)
RunShellCommand(cmd)
print(indent_str('Created: ' + newcfg_path.replace(topdir, ''), 1))
# Create defconfig for linux kernel
if arch == 'riscv64':
arch = 'riscv'
newcfg_name = '{}_{}_defconfig'.format(chip, boardname_cfg)
refcfg_path = '{}{}arch/{}/configs/{}'.format(topdir, LINUX_DIR, arch, ref_linux_cfg)
newcfg_path = '{}{}arch/{}/configs/{}'.format(topdir, LINUX_DIR, arch, newcfg_name)
cmd = 'cp {} {}'.format(refcfg_path, newcfg_path)
RunShellCommand(cmd)
print(indent_str('Created: ' + newcfg_path.replace(topdir, ''), 1))
# Create config for busybox
newcfg_name = '{}_{}_defconfig'.format(chip, boardname_cfg)
refcfg_path = '{}{}'.format(topdir, ref_busybox_cfg)
newbusybox_cfg = '{}/{}'.format(os.path.dirname(ref_busybox_cfg), newcfg_name)
newcfg_path = '{}{}'.format(topdir, newbusybox_cfg)
cmd = 'cp {} {}'.format(refcfg_path, newcfg_path)
RunShellCommand(cmd)
print(indent_str('Created: ' + newcfg_path.replace(topdir, ''), 1))
# Create SDK defconfig
newdefcfg_name = '{}_{}_defconfig'.format(chip, boardname_cfg)
newcfg_path = '{}{}'.format(target_cfgdir, newdefcfg_name)
f = open(newcfg_path, 'w')
f.write('LUBAN_BOARD_{}_{}=y\n'.format(chip.upper(), boardname_cfg.upper()))
f.write('BR2_TARGET_GENERIC_ISSUE="Welcome to {} linux"\n'.format(manu_name))
for ln in lines:
if refboard_opt in ln:
# Skip ref board name
continue
if 'BR2_TARGET_GENERIC_HOSTNAME=' in ln:
f.write('BR2_TARGET_GENERIC_HOSTNAME="{}"\n'.format(boardname))
continue
if 'BR2_TARGET_GENERIC_ISSUE=' in ln:
# Skip old name
continue
if 'BR2_TARGET_UBOOT_BOARD_DEFCONFIG=' in ln:
f.write('BR2_TARGET_UBOOT_BOARD_DEFCONFIG="{}_{}"\n'.format(chip, boardname_cfg))
continue
if 'BR2_LINUX_KERNEL_DEFCONFIG=' in ln:
f.write('BR2_LINUX_KERNEL_DEFCONFIG="{}_{}"\n'.format(chip, boardname_cfg))
continue
rename_board = False
if 'BR2_PACKAGE_BUSYBOX_CONFIG=' in ln:
f.write('BR2_PACKAGE_BUSYBOX_CONFIG="{}"\n'.format(newbusybox_cfg))
continue
if 'BR2_ROOTFS_POST_BUILD_SCRIPT=' in ln:
rename_board = True
if 'BR2_ROOTFS_POST_FAKEROOT_SCRIPT=' in ln:
rename_board = True
if 'BR2_ROOTFS_POST_IMAGE_SCRIPT=' in ln:
rename_board = True
if 'BR2_ROOTFS_OVERLAY=' in ln:
rename_board = True
if 'BR2_TARGET_USERFS1_OVERLAY=' in ln:
rename_board = True
if 'BR2_TARGET_USERFS2_OVERLAY=' in ln:
rename_board = True
if 'BR2_TARGET_USERFS3_OVERLAY=' in ln:
rename_board = True
if rename_board:
f.write(ln.replace('{}/{}'.format(chip, refboardname), '{}/{}'.format(chip, boardname_cfg)))
continue
f.write(ln)
f.close()
print(indent_str('Created: ' + newcfg_path.replace(topdir, ''), 1))
# Add new board to Config.in
cfg_in = '{}target/{}/Config.in'.format(topdir, chip)
cmd = 'cp {} {}.old'.format(cfg_in, cfg_in)
RunShellCommand(cmd)
f = open(cfg_in, 'r')
lines = f.readlines()
f.close()
board_option = 'LUBAN_BOARD_{}_{}'.format(chip.upper(), refboardname.upper())
nboard_option = 'LUBAN_BOARD_{}_{}'.format(chip.upper(), boardname_cfg.upper())
f = open(cfg_in, 'w')
chip_option = GetChipOptionOfDefconfig(ref_dotcfg, chip)
insert_config = False
for ln in lines:
if 'config' in ln and board_option in ln:
insert_config = True
if insert_config and 'endchoice' in ln:
f.write('config {}\n'.format(nboard_option))
f.write('\tbool "{}"\n'.format(boardname))
f.write('\tdepends on {}\n\n'.format(chip_option))
insert_config = False
if 'default' in ln and board_option in ln:
f.write('\tdefault "{}" if {}\n'.format(boardname_cfg, nboard_option))
f.write(ln)
f.close()
print(indent_str('Updated: ' + cfg_in.replace(topdir, ''), 1))
def CreateNewBoard(args):
GetLinuxDir(args)
target_cfgdir = args.topdir + 'target/configs/'
defconfigs = GetReferenceBoardDefconfig(target_cfgdir)
defconfigs.sort()
if len(defconfigs) == 0:
print(indent_str("Error: no defconfig is found.", 1));
sys.exit(1)
dotconfigs = GenDotConfig(args, defconfigs)
chiplist = GetChipList(args.topdir + 'target/')
if len(chiplist) == 0:
print(indent_str("Error: no chip is found.", 1));
sys.exit(1)
chip = SelectChip(chiplist)
refcfg = SelectReferenceDefconfig(chip, defconfigs, dotconfigs)
boardname = GetNewBoardName()
manu_name = GetNewManufacturerName()
CreateNewBoardDirectory(args.topdir, refcfg, dotconfigs, chip, boardname)
CreateNewDefconfig(args.topdir, refcfg, dotconfigs, chip, boardname, manu_name)
return 0
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-c", "--conf", type=str, help="conf executable")
parser.add_argument("-t", "--topdir", type=str, help="Top root directory")
parser.add_argument("-o", "--outdir", type=str, help="Output root directory")
args = parser.parse_args()
if args.conf == None:
print(indent_str('Error, please provide path of application "conf"', 1))
sys.exit(1)
if os.path.exists(args.conf) == False:
print(indent_str('Error, "conf" is not exist', 1))
sys.exit(1)
if args.topdir == None:
print(indent_str('Error, please provide path of top directory', 1))
sys.exit(1)
args.topdir = os.path.abspath(args.topdir)
if args.topdir.endswith('/') == False:
args.topdir = args.topdir + '/'
if args.outdir == None:
args.outdir = args.topdir
else:
args.outdir = os.path.abspath(args.outdir)
if args.outdir.endswith('/') == False:
args.outdir = args.outdir + '/'
cmd = 'arch'
args.arch = RunShellCommand(cmd)
CreateNewBoard(args)