"""Functions used to generate source files during build time All such functions are invoked in a subprocess on Windows to prevent build flakiness. """ import json from platform_methods import subprocess_main def _spaced(e): return e if e[-1] == "*" else e + " " def _build_gdnative_api_struct_header(api): gdnative_api_init_macro = ["\textern const pandemonium_gdnative_core_api_struct *_gdnative_wrapper_api_struct;"] for ext in api["extensions"]: name = ext["name"] gdnative_api_init_macro.append( "\textern const pandemonium_gdnative_ext_{0}_api_struct *_gdnative_wrapper_{0}_api_struct;".format(name) ) gdnative_api_init_macro.append("\t_gdnative_wrapper_api_struct = options->api_struct;") gdnative_api_init_macro.append( "\tfor (unsigned int i = 0; i < _gdnative_wrapper_api_struct->num_extensions; i++) { " ) gdnative_api_init_macro.append("\t\tswitch (_gdnative_wrapper_api_struct->extensions[i]->type) {") for ext in api["extensions"]: name = ext["name"] gdnative_api_init_macro.append("\t\t\tcase GDNATIVE_EXT_%s:" % ext["type"]) gdnative_api_init_macro.append( "\t\t\t\t_gdnative_wrapper_{0}_api_struct = (pandemonium_gdnative_ext_{0}_api_struct *)" " _gdnative_wrapper_api_struct->extensions[i];".format(name) ) gdnative_api_init_macro.append("\t\t\t\tbreak;") gdnative_api_init_macro.append("\t\t}") gdnative_api_init_macro.append("\t}") out = [ "/* THIS FILE IS GENERATED DO NOT EDIT */", "#ifndef PANDEMONIUM_GDNATIVE_API_STRUCT_H", "#define PANDEMONIUM_GDNATIVE_API_STRUCT_H", "", "#include ", "#include ", "#include ", "#include ", "#include ", "#include ", "", "#define GDNATIVE_API_INIT(options) do { \\\n" + " \\\n".join(gdnative_api_init_macro) + " \\\n } while (0)", "", "#ifdef __cplusplus", 'extern "C" {', "#endif", "", "enum GDNATIVE_API_TYPES {", "\tGDNATIVE_" + api["core"]["type"] + ",", ] for ext in api["extensions"]: out += ["\tGDNATIVE_EXT_" + ext["type"] + ","] out += ["};", ""] def generate_extension_struct(name, ext, include_version=True): ret_val = [] if ext["next"]: ret_val += generate_extension_struct(name, ext["next"]) ret_val += [ "typedef struct pandemonium_gdnative_ext_" + name + ("" if not include_version else ("_{0}_{1}".format(ext["version"]["major"], ext["version"]["minor"]))) + "_api_struct {", "\tunsigned int type;", "\tpandemonium_gdnative_api_version version;", "\tconst pandemonium_gdnative_api_struct *next;", ] for funcdef in ext["api"]: args = ", ".join(["%s%s" % (_spaced(t), n) for t, n in funcdef["arguments"]]) ret_val.append("\t%s(*%s)(%s);" % (_spaced(funcdef["return_type"]), funcdef["name"], args)) ret_val += [ "} pandemonium_gdnative_ext_" + name + ("" if not include_version else ("_{0}_{1}".format(ext["version"]["major"], ext["version"]["minor"]))) + "_api_struct;", "", ] return ret_val def generate_core_extension_struct(core): ret_val = [] if core["next"]: ret_val += generate_core_extension_struct(core["next"]) ret_val += [ "typedef struct pandemonium_gdnative_core_" + ("{0}_{1}".format(core["version"]["major"], core["version"]["minor"])) + "_api_struct {", "\tunsigned int type;", "\tpandemonium_gdnative_api_version version;", "\tconst pandemonium_gdnative_api_struct *next;", ] for funcdef in core["api"]: args = ", ".join(["%s%s" % (_spaced(t), n) for t, n in funcdef["arguments"]]) ret_val.append("\t%s(*%s)(%s);" % (_spaced(funcdef["return_type"]), funcdef["name"], args)) ret_val += [ "} pandemonium_gdnative_core_" + "{0}_{1}".format(core["version"]["major"], core["version"]["minor"]) + "_api_struct;", "", ] return ret_val for ext in api["extensions"]: name = ext["name"] out += generate_extension_struct(name, ext, False) if api["core"]["next"]: out += generate_core_extension_struct(api["core"]["next"]) out += [ "typedef struct pandemonium_gdnative_core_api_struct {", "\tunsigned int type;", "\tpandemonium_gdnative_api_version version;", "\tconst pandemonium_gdnative_api_struct *next;", "\tunsigned int num_extensions;", "\tconst pandemonium_gdnative_api_struct **extensions;", ] for funcdef in api["core"]["api"]: args = ", ".join(["%s%s" % (_spaced(t), n) for t, n in funcdef["arguments"]]) out.append("\t%s(*%s)(%s);" % (_spaced(funcdef["return_type"]), funcdef["name"], args)) out += [ "} pandemonium_gdnative_core_api_struct;", "", "#ifdef __cplusplus", "}", "#endif", "", "#endif // PANDEMONIUM_GDNATIVE_API_STRUCT_H", "", ] return "\n".join(out) def _build_gdnative_api_struct_source(api): out = ["/* THIS FILE IS GENERATED DO NOT EDIT */", "", "#include ", ""] def get_extension_struct_name(name, ext, include_version=True): return ( "pandemonium_gdnative_ext_" + name + ("" if not include_version else ("_{0}_{1}".format(ext["version"]["major"], ext["version"]["minor"]))) + "_api_struct" ) def get_extension_struct_instance_name(name, ext, include_version=True): return ( "api_extension_" + name + ("" if not include_version else ("_{0}_{1}".format(ext["version"]["major"], ext["version"]["minor"]))) + "_struct" ) def get_extension_struct_definition(name, ext, include_version=True): ret_val = [] if ext["next"]: ret_val += get_extension_struct_definition(name, ext["next"]) ret_val += [ "extern const " + get_extension_struct_name(name, ext, include_version) + " " + get_extension_struct_instance_name(name, ext, include_version) + " = {", "\tGDNATIVE_EXT_" + ext["type"] + ",", "\t{" + str(ext["version"]["major"]) + ", " + str(ext["version"]["minor"]) + "},", "\t" + ( "NULL" if not ext["next"] else ("(const pandemonium_gdnative_api_struct *)&" + get_extension_struct_instance_name(name, ext["next"])) ) + ",", ] for funcdef in ext["api"]: ret_val.append("\t%s," % funcdef["name"]) ret_val += ["};\n"] return ret_val def get_core_struct_definition(core): ret_val = [] if core["next"]: ret_val += get_core_struct_definition(core["next"]) ret_val += [ "extern const pandemonium_gdnative_core_" + ("{0}_{1}_api_struct api_{0}_{1}".format(core["version"]["major"], core["version"]["minor"])) + " = {", "\tGDNATIVE_" + core["type"] + ",", "\t{" + str(core["version"]["major"]) + ", " + str(core["version"]["minor"]) + "},", "\t" + ( "NULL" if not core["next"] else ( "(const pandemonium_gdnative_api_struct *)& api_{0}_{1}".format( core["next"]["version"]["major"], core["next"]["version"]["minor"] ) ) ) + ",", ] for funcdef in core["api"]: ret_val.append("\t%s," % funcdef["name"]) ret_val += ["};\n"] return ret_val for ext in api["extensions"]: name = ext["name"] out += get_extension_struct_definition(name, ext, False) out += ["", "const pandemonium_gdnative_api_struct *gdnative_extensions_pointers[] = {"] for ext in api["extensions"]: name = ext["name"] out += ["\t(pandemonium_gdnative_api_struct *)&api_extension_" + name + "_struct,"] out += ["};\n"] if api["core"]["next"]: out += get_core_struct_definition(api["core"]["next"]) out += [ "extern const pandemonium_gdnative_core_api_struct api_struct = {", "\tGDNATIVE_" + api["core"]["type"] + ",", "\t{" + str(api["core"]["version"]["major"]) + ", " + str(api["core"]["version"]["minor"]) + "},", "\t" + ( "NULL" if not api["core"]["next"] else ( "(const pandemonium_gdnative_api_struct *)& api_{0}_{1}".format( api["core"]["next"]["version"]["major"], api["core"]["next"]["version"]["minor"] ) ) ) + ",", "\t" + str(len(api["extensions"])) + ",", "\tgdnative_extensions_pointers,", ] for funcdef in api["core"]["api"]: out.append("\t%s," % funcdef["name"]) out.append("};\n") return "\n".join(out) def build_gdnative_api_struct(target, source, env): with open(source[0], "r") as fd: api = json.load(fd) header, source = target with open(header, "w") as fd: fd.write(_build_gdnative_api_struct_header(api)) with open(source, "w") as fd: fd.write(_build_gdnative_api_struct_source(api)) def _build_gdnative_wrapper_code(api): out = [ "/* THIS FILE IS GENERATED DO NOT EDIT */", "", "#include ", "#include ", "#include ", "#include ", "", "#include ", "", "#ifdef __cplusplus", 'extern "C" {', "#endif", "", "pandemonium_gdnative_core_api_struct *_gdnative_wrapper_api_struct = 0;", ] for ext in api["extensions"]: name = ext["name"] out.append("pandemonium_gdnative_ext_" + name + "_api_struct *_gdnative_wrapper_" + name + "_api_struct = 0;") out += [""] for funcdef in api["core"]["api"]: args = ", ".join(["%s%s" % (_spaced(t), n) for t, n in funcdef["arguments"]]) out.append("%s%s(%s) {" % (_spaced(funcdef["return_type"]), funcdef["name"], args)) args = ", ".join(["%s" % n for t, n in funcdef["arguments"]]) return_line = "\treturn " if funcdef["return_type"] != "void" else "\t" return_line += "_gdnative_wrapper_api_struct->" + funcdef["name"] + "(" + args + ");" out.append(return_line) out.append("}") out.append("") for ext in api["extensions"]: name = ext["name"] for funcdef in ext["api"]: args = ", ".join(["%s%s" % (_spaced(t), n) for t, n in funcdef["arguments"]]) out.append("%s%s(%s) {" % (_spaced(funcdef["return_type"]), funcdef["name"], args)) args = ", ".join(["%s" % n for t, n in funcdef["arguments"]]) return_line = "\treturn " if funcdef["return_type"] != "void" else "\t" return_line += "_gdnative_wrapper_" + name + "_api_struct->" + funcdef["name"] + "(" + args + ");" out.append(return_line) out.append("}") out.append("") out += ["#ifdef __cplusplus", "}", "#endif"] return "\n".join(out) def build_gdnative_wrapper_code(target, source, env): with open(source[0], "r") as fd: api = json.load(fd) wrapper_file = target[0] with open(wrapper_file, "w") as fd: fd.write(_build_gdnative_wrapper_code(api)) if __name__ == "__main__": subprocess_main(globals())