461 lines
15 KiB
Python
Executable File
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)
|
|
|