chore(core): automatic generation of CMakeLists

[no changelog]
pull/2762/head
tychovrahe 1 year ago committed by TychoVrahe
parent f8c432e955
commit 9748a56a55

2
core/.gitignore vendored

@ -8,3 +8,5 @@ tests/trezor_monero_tests*
.coverage.*
htmlcov/
mypy_report
/CMakeLists.txt
/cmake-build-debug/

@ -24,6 +24,7 @@ BITCOIN_ONLY ?= 0
TREZOR_MODEL ?= T
TREZOR_MEMPERF ?= 0
ADDRESS_SANITIZER ?= 0
CMAKELISTS ?= 0
# OpenOCD interface default. Alternative: ftdi/olimex-arm-usb-tiny-h
OPENOCD_INTERFACE ?= stlink
@ -155,33 +156,33 @@ build: build_boardloader build_bootloader build_firmware build_prodtest build_un
build_embed: build_boardloader build_bootloader build_firmware # build boardloader, bootloader, firmware
build_boardloader: ## build boardloader
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" $(BOARDLOADER_BUILD_DIR)/boardloader.bin
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" $(BOARDLOADER_BUILD_DIR)/boardloader.bin
build_bootloader: ## build bootloader
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" $(BOOTLOADER_BUILD_DIR)/bootloader.bin
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" $(BOOTLOADER_BUILD_DIR)/bootloader.bin
build_bootloader_ci: ## build CI device testing bootloader
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" $(BOOTLOADER_CI_BUILD_DIR)/bootloader.bin
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" $(BOOTLOADER_CI_BUILD_DIR)/bootloader.bin
build_prodtest: ## build production test firmware
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" $(PRODTEST_BUILD_DIR)/prodtest.bin
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" $(PRODTEST_BUILD_DIR)/prodtest.bin
build_reflash: ## build reflash firmware + reflash image
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" $(REFLASH_BUILD_DIR)/reflash.bin
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" $(REFLASH_BUILD_DIR)/reflash.bin
dd if=build/boardloader/boardloader.bin of=$(REFLASH_BUILD_DIR)/sdimage.bin bs=1 seek=0
dd if=build/bootloader/bootloader.bin of=$(REFLASH_BUILD_DIR)/sdimage.bin bs=1 seek=49152
build_firmware: templates build_cross ## build firmware with frozen modules
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" PYOPT="$(PYOPT)" BITCOIN_ONLY="$(BITCOIN_ONLY)" $(FIRMWARE_BUILD_DIR)/firmware.bin
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" PYOPT="$(PYOPT)" BITCOIN_ONLY="$(BITCOIN_ONLY)" $(FIRMWARE_BUILD_DIR)/firmware.bin
build_unix: templates ## build unix port
$(SCONS) CFLAGS="$(CFLAGS)" $(UNIX_BUILD_DIR)/trezor-emu-core $(UNIX_PORT_OPTS) TREZOR_MODEL="$(TREZOR_MODEL)" PYOPT="0" BITCOIN_ONLY="$(BITCOIN_ONLY)" TREZOR_EMULATOR_ASAN="$(ADDRESS_SANITIZER)"
$(SCONS) CFLAGS="$(CFLAGS)" $(UNIX_BUILD_DIR)/trezor-emu-core $(UNIX_PORT_OPTS) TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" PYOPT="0" BITCOIN_ONLY="$(BITCOIN_ONLY)" TREZOR_EMULATOR_ASAN="$(ADDRESS_SANITIZER)"
build_unix_frozen: templates build_cross ## build unix port with frozen modules
$(SCONS) CFLAGS="$(CFLAGS)" $(UNIX_BUILD_DIR)/trezor-emu-core $(UNIX_PORT_OPTS) TREZOR_MODEL="$(TREZOR_MODEL)" PYOPT="$(PYOPT)" BITCOIN_ONLY="$(BITCOIN_ONLY)" TREZOR_EMULATOR_ASAN="$(ADDRESS_SANITIZER)" TREZOR_MEMPERF="$(TREZOR_MEMPERF)" TREZOR_EMULATOR_FROZEN=1
$(SCONS) CFLAGS="$(CFLAGS)" $(UNIX_BUILD_DIR)/trezor-emu-core $(UNIX_PORT_OPTS) TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" PYOPT="$(PYOPT)" BITCOIN_ONLY="$(BITCOIN_ONLY)" TREZOR_EMULATOR_ASAN="$(ADDRESS_SANITIZER)" TREZOR_MEMPERF="$(TREZOR_MEMPERF)" TREZOR_EMULATOR_FROZEN=1
build_unix_debug: templates ## build unix port
$(SCONS) --max-drift=1 CFLAGS="$(CFLAGS)" $(UNIX_BUILD_DIR)/trezor-emu-core $(UNIX_PORT_OPTS) TREZOR_MODEL="$(TREZOR_MODEL)" BITCOIN_ONLY="$(BITCOIN_ONLY)" TREZOR_EMULATOR_ASAN=1 TREZOR_EMULATOR_DEBUGGABLE=1
$(SCONS) --max-drift=1 CFLAGS="$(CFLAGS)" $(UNIX_BUILD_DIR)/trezor-emu-core $(UNIX_PORT_OPTS) TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" BITCOIN_ONLY="$(BITCOIN_ONLY)" TREZOR_EMULATOR_ASAN=1 TREZOR_EMULATOR_DEBUGGABLE=1
build_cross: ## build mpy-cross port
$(MAKE) -C vendor/micropython/mpy-cross $(CROSS_PORT_OPTS)

@ -4,6 +4,7 @@ import os
import tools
TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T')
CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0))
if TREZOR_MODEL in ('1', ):
# skip boardloader build
@ -111,7 +112,9 @@ env.Replace(
LINK='arm-none-eabi-gcc',
SIZE='arm-none-eabi-size',
STRIP='arm-none-eabi-strip',
OBJCOPY='arm-none-eabi-objcopy', )
OBJCOPY='arm-none-eabi-objcopy',
PYTHON='python',
MAKECMAKELISTS='$PYTHON tools/make_cmakelists.py',)
env.Replace(
TREZOR_MODEL=TREZOR_MODEL, )
@ -154,6 +157,16 @@ env.Replace(
ASFLAGS=CPU_ASFLAGS,
ASPPFLAGS='$CFLAGS $CCFLAGS', )
env.Replace(
ALLSOURCES=SOURCE_MOD + SOURCE_BOARDLOADER + SOURCE_STMHAL + SOURCE_TREZORHAL,
ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES']))
cmake_gen = env.Command(
target='CMakeLists.txt',
source='',
action='$MAKECMAKELISTS --sources $ALLSOURCES --dirs $CPPPATH --defs $ALLDEFS',
)
#
# Program objects
#
@ -177,6 +190,9 @@ BINARY_NAME += "-" + tools.get_git_revision_short_hash()
BINARY_NAME += "-dirty" if tools.get_git_modified() else ""
BINARY_NAME += ".bin"
if CMAKELISTS != 0:
env.Depends(program_elf, cmake_gen)
program_bin = env.Command(
target='boardloader.bin',
source=program_elf,

@ -4,6 +4,7 @@ import os
import tools
TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T')
CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0))
DMA2D = False
if TREZOR_MODEL in ('1', ):
@ -164,7 +165,9 @@ env.Replace(
LINK='arm-none-eabi-gcc',
SIZE='arm-none-eabi-size',
STRIP='arm-none-eabi-strip',
OBJCOPY='arm-none-eabi-objcopy', )
OBJCOPY='arm-none-eabi-objcopy',
PYTHON='python',
MAKECMAKELISTS='$PYTHON tools/make_cmakelists.py', )
env.Replace(
TREZOR_MODEL=TREZOR_MODEL, )
@ -223,6 +226,17 @@ env.Replace(
HEADERTOOL='tools/headertool.py',
)
env.Replace(
ALLSOURCES=SOURCE_MOD + SOURCE_BOOTLOADER + SOURCE_NANOPB + SOURCE_STMHAL + SOURCE_TREZORHAL,
ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES']))
cmake_gen = env.Command(
target='CMakeLists.txt',
source='',
action='$MAKECMAKELISTS --sources $ALLSOURCES --dirs $CPPPATH --defs $ALLDEFS',
)
#
# Program objects
#
@ -247,6 +261,9 @@ BINARY_NAME += "-" + tools.get_git_revision_short_hash()
BINARY_NAME += "-dirty" if tools.get_git_modified() else ""
BINARY_NAME += ".bin"
if CMAKELISTS != 0:
env.Depends(program_elf, cmake_gen)
program_bin = env.Command(
target='bootloader.bin',
source=program_elf,

@ -4,6 +4,7 @@ import os
import tools
TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T')
CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0))
if TREZOR_MODEL in ('1', ):
# skip bootloader_ci build
@ -147,7 +148,9 @@ env.Replace(
LINK='arm-none-eabi-gcc',
SIZE='arm-none-eabi-size',
STRIP='arm-none-eabi-strip',
OBJCOPY='arm-none-eabi-objcopy', )
OBJCOPY='arm-none-eabi-objcopy',
PYTHON='python',
MAKECMAKELISTS='$PYTHON tools/make_cmakelists.py',)
env.Replace(
TREZOR_MODEL=TREZOR_MODEL, )
@ -192,12 +195,24 @@ env.Replace(
'PB_VALIDATE_UTF8',
] + CPPDEFINES_MOD,
ASFLAGS=CPU_ASFLAGS,
ASPPFLAGS='$CFLAGS $CCFLAGS', )
ASPPFLAGS='$CFLAGS $CCFLAGS',
ALLSOURCES=SOURCE_MOD + SOURCE_BOOTLOADER + SOURCE_STMHAL + SOURCE_TREZORHAL+ SOURCE_NANOPB, )
env.Replace(
HEADERTOOL='tools/headertool.py',
)
env.Replace(
ALLSOURCES=SOURCE_MOD + SOURCE_BOOTLOADER + SOURCE_NANOPB + SOURCE_STMHAL + SOURCE_TREZORHAL,
ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES']))
cmake_gen = env.Command(
target='CMakeLists.txt',
source='',
action='$MAKECMAKELISTS --sources $ALLSOURCES --dirs $CPPPATH --defs $ALLDEFS',
)
#
# Program objects
#
@ -222,6 +237,9 @@ BINARY_NAME += "-" + tools.get_git_revision_short_hash()
BINARY_NAME += "-dirty" if tools.get_git_modified() else ""
BINARY_NAME += ".bin"
if CMAKELISTS != 0:
env.Depends(program_elf, cmake_gen)
program_bin = env.Command(
target='bootloader.bin',
source=program_elf,

@ -8,6 +8,7 @@ BITCOIN_ONLY = ARGUMENTS.get('BITCOIN_ONLY', '0')
EVERYTHING = BITCOIN_ONLY != '1'
TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T')
DMA2D = TREZOR_MODEL in ('T', )
CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0))
FEATURE_FLAGS = {
"RDI": True,
@ -508,6 +509,7 @@ env.Replace(
MAKEQSTRDATA='$PYTHON vendor/micropython/py/makeqstrdata.py',
MAKEVERSIONHDR='$PYTHON vendor/micropython/py/makeversionhdr.py',
MAKEMODULEDEFS='$PYTHON vendor/micropython/py/makemoduledefs.py',
MAKECMAKELISTS='$PYTHON tools/make_cmakelists.py',
MPY_TOOL='$PYTHON vendor/micropython/tools/mpy-tool.py',
MPY_CROSS='vendor/micropython/mpy-cross/mpy-cross -O' + PYOPT,
PB2PY='$PYTHON ../common/protob/pb2py',
@ -752,10 +754,12 @@ env.Append(LINKFLAGS=f' -l{RUST_LIB}')
# Program objects
#
source_files = SOURCE_MOD + SOURCE_FIRMWARE + SOURCE_MICROPYTHON + SOURCE_MICROPYTHON_SPEED + SOURCE_STMHAL + SOURCE_TREZORHAL
obj_program = []
obj_program.extend(env.Object(source=SOURCE_MOD))
if FEATURE_FLAGS["SECP256K1_ZKP"]:
obj_program.extend(env.Object(source=SOURCE_MOD_SECP256K1_ZKP, CCFLAGS='$CCFLAGS -Wno-unused-function'))
source_files.extend(SOURCE_MOD_SECP256K1_ZKP)
obj_program.extend(env.Object(source=SOURCE_FIRMWARE))
obj_program.extend(env.Object(source=SOURCE_MICROPYTHON))
obj_program.extend(env.Object(source=SOURCE_MICROPYTHON_SPEED, COPT='-O3'))
@ -764,6 +768,18 @@ obj_program.extend(env.Object(source=SOURCE_TREZORHAL))
if FROZEN:
obj_program.extend(env.Object(source=source_mpyc))
env.Replace(
ALLSOURCES=source_files,
ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES']))
cmake_gen = env.Command(
target='CMakeLists.txt',
source='',
action='$MAKECMAKELISTS --sources $ALLSOURCES --dirs $CPPPATH --defs $ALLDEFS',
)
VENDORHEADER = 'embed/vendorheader/vendorheader_' + ('unsafe_signed_prod.bin' if ARGUMENTS.get('PRODUCTION', '0') == '0' else 'satoshilabs_signed_prod.bin')
obj_program.extend(
@ -797,6 +813,8 @@ program_elf = env.Command(
'$LINK -o $TARGET $CCFLAGS $CFLAGS $SOURCES $LINKFLAGS -lc_nano -lm -lgcc',
)
if CMAKELISTS != 0:
env.Depends(program_elf, cmake_gen)
env.Depends(program_elf, rust)
BINARY_NAME = f"build/firmware/firmware-{tools.get_model_identifier(TREZOR_MODEL)}"

@ -4,6 +4,7 @@ import os
import tools
TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T')
CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0))
CCFLAGS_MOD = ''
CPPPATH_MOD = []
@ -116,7 +117,9 @@ env.Replace(
LINK='arm-none-eabi-gcc',
SIZE='arm-none-eabi-size',
STRIP='arm-none-eabi-strip',
OBJCOPY='arm-none-eabi-objcopy', )
OBJCOPY='arm-none-eabi-objcopy',
PYTHON='python',
MAKECMAKELISTS='$PYTHON tools/make_cmakelists.py',)
env.Replace(
TREZOR_MODEL=TREZOR_MODEL, )
@ -165,6 +168,18 @@ env.Replace(
HEADERTOOL='tools/headertool.py',
)
env.Replace(
ALLSOURCES=SOURCE_MOD + SOURCE_PRODTEST + SOURCE_STMHAL + SOURCE_TREZORHAL,
ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES']))
cmake_gen = env.Command(
target='CMakeLists.txt',
source='',
action='$MAKECMAKELISTS --sources $ALLSOURCES --dirs $CPPPATH --defs $ALLDEFS',
)
#
# Program objects
#
@ -198,6 +213,9 @@ BINARY_NAME += "-" + tools.get_git_revision_short_hash()
BINARY_NAME += "-dirty" if tools.get_git_modified() else ""
BINARY_NAME += ".bin"
if CMAKELISTS != 0:
env.Depends(program_elf, cmake_gen)
program_bin = env.Command(
target='prodtest.bin',
source=program_elf,

@ -4,6 +4,7 @@ import os
import tools
TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T')
CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0))
CCFLAGS_MOD = ''
CPPPATH_MOD = []
@ -109,7 +110,9 @@ env.Replace(
LINK='arm-none-eabi-gcc',
SIZE='arm-none-eabi-size',
STRIP='arm-none-eabi-strip',
OBJCOPY='arm-none-eabi-objcopy', )
OBJCOPY='arm-none-eabi-objcopy',
PYTHON='python',
MAKECMAKELISTS='$PYTHON tools/make_cmakelists.py',)
env.Replace(
TREZOR_MODEL=TREZOR_MODEL, )
@ -158,6 +161,16 @@ env.Replace(
HEADERTOOL='tools/headertool.py',
)
env.Replace(
ALLSOURCES=SOURCE_MOD + SOURCE_REFLASH + SOURCE_STMHAL + SOURCE_TREZORHAL,
ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES']))
cmake_gen = env.Command(
target='CMakeLists.txt',
source='',
action='$MAKECMAKELISTS --sources $ALLSOURCES --dirs $CPPPATH --defs $ALLDEFS',
)
#
# Program objects
#
@ -191,6 +204,9 @@ BINARY_NAME += "-" + tools.get_git_revision_short_hash()
BINARY_NAME += "-dirty" if tools.get_git_modified() else ""
BINARY_NAME += ".bin"
if CMAKELISTS != 0:
env.Depends(program_elf, cmake_gen)
program_bin = env.Command(
target='reflash.bin',
source=program_elf,

@ -8,6 +8,7 @@ BITCOIN_ONLY = ARGUMENTS.get('BITCOIN_ONLY', '0')
EVERYTHING = BITCOIN_ONLY != '1'
TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T')
DMA2D = TREZOR_MODEL in ('T', )
CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0))
FEATURE_FLAGS = {
"SECP256K1_ZKP": True, # required for trezor.crypto.curve.bip340 (BIP340/Taproot)
@ -460,6 +461,7 @@ env.Replace(
MAKEQSTRDATA='$PYTHON vendor/micropython/py/makeqstrdata.py',
MAKEVERSIONHDR='$PYTHON vendor/micropython/py/makeversionhdr.py',
MAKEMODULEDEFS='$PYTHON vendor/micropython/py/makemoduledefs.py',
MAKECMAKELISTS='$PYTHON tools/make_cmakelists.py',
MPY_TOOL='$PYTHON vendor/micropython/tools/mpy-tool.py',
MPY_CROSS='vendor/micropython/mpy-cross/mpy-cross -O' + PYOPT,
PB2PY='$PYTHON ../common/protob/pb2py',
@ -697,14 +699,28 @@ env.Append(LINKFLAGS=f'-l{RUST_LIB}')
#
obj_program = []
source_files = SOURCE_MOD + SOURCE_MICROPYTHON + SOURCE_UNIX
obj_program.extend(env.Object(source=SOURCE_MOD))
if FEATURE_FLAGS["SECP256K1_ZKP"]:
obj_program.extend(env.Object(source=SOURCE_MOD_SECP256K1_ZKP, CCFLAGS='$CCFLAGS -Wno-unused-function'))
source_files.extend(SOURCE_MOD_SECP256K1_ZKP)
obj_program.extend(env.Object(source=SOURCE_MICROPYTHON))
obj_program.extend(env.Object(source=SOURCE_UNIX))
if FROZEN:
obj_program.extend(env.Object(source=source_mpyc))
env.Replace(
ALLSOURCES=source_files,
ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES']))
cmake_gen = env.Command(
target='CMakeLists.txt',
source='',
action='$MAKECMAKELISTS --sources $ALLSOURCES --dirs $CPPPATH --defs $ALLDEFS',
)
env.Depends(obj_program, qstr_generated)
program = env.Command(
@ -712,4 +728,6 @@ program = env.Command(
source=obj_program,
action='$CC -o $TARGET $SOURCES $_LIBDIRFLAGS $_LIBFLAGS $LINKFLAGS', )
if CMAKELISTS != 0:
env.Depends(program, cmake_gen)
env.Depends(program, rust)

@ -18,7 +18,6 @@ def get_hw_model_as_number(hw_model):
return int.from_bytes(hw_model.encode(), 'little')
def configure_board(model, env, defines, sources):
model_r_version = 4
@ -91,3 +90,13 @@ def get_git_revision_short_hash() -> str:
def get_git_modified() -> bool:
return subprocess.check_output(['git', 'diff', '--name-status']).decode('ascii').strip() != ''
def get_defs_for_cmake(defs):
result = []
for d in defs:
if type(d) is tuple:
result.append(d[0] + "=" + d[1])
else:
result.append(d)
return result

@ -0,0 +1,59 @@
import argparse
def gen(sources, dirs, defs):
target = "CMakeLists.txt"
with open(target, 'w') as f:
f.write("cmake_minimum_required(VERSION 3.20)\n")
f.write("project(core)\n")
f.write("\n")
f.write("set(CMAKE_CXX_STANDARD 14)\n")
f.write("\n")
f.write("\n")
f.write("add_definitions(\n")
for d in defs:
f.write(f' -D{d}\n')
f.write(")\n")
f.write("\n")
f.write("\n")
for d in dirs:
f.write(f'include_directories({d})\n')
f.write("\n")
f.write("\n")
f.write("add_executable(core\n")
for s in sources:
f.write(f' {s}\n')
f.write(")\n")
f.write("\n")
if __name__ == "__main__":
CLI = argparse.ArgumentParser()
CLI.add_argument(
"--sources",
nargs="*",
type=str,
default=[],
)
CLI.add_argument(
"--dirs",
nargs="*",
type=str,
default=[],
)
CLI.add_argument(
"--defs",
nargs="*",
type=str,
default=[],
)
args = CLI.parse_args()
gen(args.sources, args.dirs, args.defs)
Loading…
Cancel
Save