diff --git a/fxconv/fxconv-main.py b/fxconv/fxconv-main.py index 4afe40a..a576d9e 100755 --- a/fxconv/fxconv-main.py +++ b/fxconv/fxconv-main.py @@ -6,6 +6,7 @@ import os import re import fnmatch import fxconv +import importlib help_string = f""" usage: fxconv [] -o [--fx|--cg] [...] @@ -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: diff --git a/fxconv/fxconv.py b/fxconv/fxconv.py index b4de5d2..8c34b50 100644 --- a/fxconv/fxconv.py +++ b/fxconv/fxconv.py @@ -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): diff --git a/fxsdk/cmake/Fxconv.cmake b/fxsdk/cmake/Fxconv.cmake index 20e9e5a..8b946e4 100644 --- a/fxsdk/cmake/Fxconv.cmake +++ b/fxsdk/cmake/Fxconv.cmake @@ -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 -o --toolchain=sh-elf --${FXSDK_PLATFORM} --converters=${FXCONV_CONVERTERS}" PARENT_SCOPE) +endfunction()