fxconv: enable custom types in the fxconv-metadata.txt system

Set the custom type with "custom-type: your_type_name" (instead of using
--custom on the command-line).

The converter.py in the current directory is still auto-detected as a
custom converter, but that won't work with CMake (which builds with the
build folder as current directory). Instead, a new option --converters=
with a semicolon-separated of Python files has been added. Use
fxconv_declare_converters() from the fxSDK-provided Fxconv module to
declare them programatically in CMake.
This commit is contained in:
Lephenixnoir 2021-05-04 17:38:28 +02:00
parent ff6d3c2199
commit ed10e727df
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
3 changed files with 57 additions and 23 deletions

View File

@ -6,6 +6,7 @@ import os
import re
import fnmatch
import fxconv
import importlib
help_string = f"""
usage: fxconv [<TYPE>] <INPUT> -o <OUTPUT> [--fx|--cg] [<PARAMETERS>...]
@ -22,8 +23,10 @@ When TYPE is specified (one-shot conversion), it should be one of:
-f, --font Convert to gint's topti font format
--bopti-image Convert to gint's bopti image format
--libimg-image Convert to the libimg image format
--custom Use converters.py; you might want to specify an explicit type
by adding a parameter type:your_custom_type (see below)
--custom Use a custom converter; you might want to specify an explicit
type by adding "custom-type:your_custom_type" (see below)
--converters Semicolon-separated list of custom converters (converters.py
in the current directory is detected as one per legacy)
During one-shot conversions, parameters can be specified with a "NAME:VALUE"
syntax (names can contain dots). For example:
@ -43,11 +46,13 @@ def err(msg):
def warn(msg):
print("\x1b[33;1mwarning:\x1b[0m", msg, file=sys.stderr)
# "converters" module from the user project... if it exists
# "converters" module from the user project... if it exists. This
# auto-detection is legacy, you should use --converters instead.
try:
import converters
import converters as conv
converters = [conv.convert]
except ImportError:
converters = None
converters = []
def parse_parameters(params):
"""Parse parameters of the form "NAME:VALUE" into a dictionary."""
@ -102,6 +107,7 @@ def main():
model = None
target = { 'toolchain': None, 'arch': None, 'section': None }
use_custom = False
converter_paths = []
# Parse command-line arguments
@ -110,8 +116,9 @@ def main():
sys.exit(1)
try:
longs = f"help output= toolchain= arch= section= fx cg {types}"
opts, args = getopt.gnu_getopt(sys.argv[1:], "hsbifo:", longs.split())
longs = ["help", "output=", "toolchain=", "arch=", "section=", "fx",
"cg", "converters="] + types.split()
opts, args = getopt.gnu_getopt(sys.argv[1:], "hsbifo:", longs)
except getopt.GetoptError as error:
return err(error)
@ -133,6 +140,8 @@ def main():
elif name == "--custom":
use_custom = True
mode = "custom"
elif name == "--converters":
converter_paths = [path for path in value.split(";") if path]
# Other names are modes
else:
mode = name[1] if len(name)==2 else name[2:]
@ -175,14 +184,14 @@ def main():
warn("type 'image' is deprecated, use 'bopti-image' instead")
params["type"] = "bopti-image"
# Use the custom module
custom = None
if use_custom:
if converters is None:
return err("--custom specified but no [converters] module")
custom = converters.convert
# Load custom converters:
for path in converter_paths:
spec = importlib.util.spec_from_file_location("converters", path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
converters.append(module.convert)
fxconv.convert(input, params, target, output, model, custom)
fxconv.convert(input, params, target, output, model, converters)
if __name__ == "__main__":
try:

View File

@ -974,24 +974,34 @@ def convert(input, params, target, output=None, model=None, custom=None):
if target["arch"] is None:
target["arch"] = model
if "type" not in params:
if "custom-type" in params:
t = params["custom-type"]
# Also copy it in "type" for older converters (this is legacy)
params["type"] = t
elif "type" in params:
t = params["type"]
else:
raise FxconvError(f"missing type in conversion '{input}'")
elif params["type"] == "binary":
if t == "binary":
convert_binary(input, output, params, target)
elif params["type"] == "bopti-image" and model in [ "fx", None ]:
elif t == "bopti-image" and model in [ "fx", None ]:
convert_bopti_fx(input, output, params, target)
elif params["type"] == "bopti-image" and model == "cg":
elif t == "bopti-image" and model == "cg":
convert_bopti_cg(input, output, params, target)
elif params["type"] == "font":
elif t == "font":
convert_topti(input, output, params, target)
elif params["type"] == "libimg-image" and model in [ "fx", None ]:
elif t == "libimg-image" and model in [ "fx", None ]:
convert_libimg_fx(input, output, params, target)
elif params["type"] == "libimg-image" and model == "cg":
elif t == "libimg-image" and model == "cg":
convert_libimg_cg(input, output, params, target)
elif custom is not None:
custom(input, output, params, target)
for converter in custom:
if converter(input, output, params, target) == 0:
return
raise FxconvError(f'unknown custom resource type \'{t}\'')
else:
raise FxconvError(f'unknown resource type \'{params["type"]}\'')
raise FxconvError(f'unknown resource type \'{t}\'')
def elf(data, output, symbol, toolchain=None, arch=None, section=None,
assembly=None):

View File

@ -18,3 +18,18 @@ function(fxconv_declare_assets)
endif()
endforeach()
endfunction()
function(fxconv_declare_converters)
# Get the absolute path for each converter
foreach(CONVERTER IN LISTS ARGN)
get_filename_component(CONVERTER_PATH "${CONVERTER}" ABSOLUTE)
list(APPEND FXCONV_CONVERTERS "${CONVERTER_PATH}")
endforeach()
# Record the names in the list
set(FXCONV_CONVERTERS "${FXCONV_CONVERTERS}" PARENT_SCOPE)
# Update the compile command
set(CMAKE_FXCONV_COMPILE_OBJECT
"fxconv <SOURCE> -o <OBJECT> --toolchain=sh-elf --${FXSDK_PLATFORM} --converters=${FXCONV_CONVERTERS}" PARENT_SCOPE)
endfunction()