X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=genbindings.py;h=ca88a3aa989fe43792e5521cf7e6d2d264902cd6;hb=d717c54e35f8f3c7ca39ffa2b9add818f889ff87;hp=3a6551430cd3fb40bea6f437120582bb3b11799f;hpb=56e9910ffaa7fccf2cb777dc9cf55e01a9681543;p=ldk-java diff --git a/genbindings.py b/genbindings.py index 3a655143..ca88a3aa 100755 --- a/genbindings.py +++ b/genbindings.py @@ -14,8 +14,12 @@ else: sys.exit(1) target = None -if sys.argv[6] == "java": +if sys.argv[6] == "java" or sys.argv[6] == "android": + import java_strings from java_strings import Consts + target = java_strings.Target.JAVA + if sys.argv[6] == "android": + target = java_strings.Target.ANDROID elif sys.argv[6] == "typescript": import typescript_strings from typescript_strings import Consts @@ -221,7 +225,8 @@ def java_c_types(fn_arg, ret_arr_len): c_ty = "int64_t" fn_arg = fn_arg[8:].strip() else: - c_ty = "intptr_t" + c_ty = "int64_t" + rust_obj = "uintptr_t" fn_arg = fn_arg[9:].strip() is_primitive = True elif is_const and fn_arg.startswith("char *"): @@ -303,7 +308,6 @@ def java_c_types(fn_arg, ret_arr_len): c_ty = consts.ptr_c_ty java_ty = consts.ptr_native_ty fn_ty_arg = "J" - is_primitive = False var_is_arr = var_is_arr_regex.match(fn_arg) if var_is_arr is not None or ret_arr_len is not None: @@ -344,7 +348,7 @@ with open(sys.argv[1]) as in_h: clone_fns.add(reg_fn.group(2)) else: rty = java_c_types(reg_fn.group(1), None) - if rty is not None and rty.rust_obj is not None and reg_fn.group(2) == rty.java_hu_ty + "_new": + if rty is not None and not rty.is_native_primitive and reg_fn.group(2) == rty.java_hu_ty + "_new": constructor_fns[rty.rust_obj] = reg_fn.group(3) continue arr_fn = fn_ret_arr_regex.match(line) @@ -360,176 +364,80 @@ write_c("static inline struct LDKThirtyTwoBytes ThirtyTwoBytes_clone(const struc java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order +with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util: + util.write(consts.util_fn_pfx) + with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: + # Map a top-level function def map_fn(line, re_match, ret_arr_len, c_call_string): - out_java.write("\t// " + line) - out_java.write("\tpublic static native ") - write_c(consts.c_fn_ty_pfx) + method_return_type = re_match.group(1) + method_name = re_match.group(2) + method_comma_separated_arguments = re_match.group(3) + method_arguments = method_comma_separated_arguments.split(',') - is_free = re_match.group(2).endswith("_free") - struct_meth = re_match.group(2).split("_")[0] + is_free = method_name.endswith("_free") + struct_meth = method_name.split("_")[0] - ret_info = type_mapping_generator.map_type(re_match.group(1), True, ret_arr_len, False, False) - write_c(ret_info.c_ty) - out_java.write(ret_info.java_ty) + return_type_info = type_mapping_generator.map_type(method_return_type, True, ret_arr_len, False, False) - if ret_info.ret_conv is not None: - ret_conv_pfx, ret_conv_sfx = ret_info.ret_conv - - out_java.write(" " + re_match.group(2) + "(") - write_c(" " + consts.c_fn_name_pfx + re_match.group(2).replace('_', '_1') + "(" + consts.c_fn_args_pfx) - - arg_names = [] + argument_types = [] default_constructor_args = {} takes_self = False args_known = True - for idx, arg in enumerate(re_match.group(3).split(',')): - if idx != 0: - out_java.write(", ") - if arg != "void": - write_c(", ") - arg_conv_info = type_mapping_generator.map_type(arg, False, None, is_free, True) - if arg_conv_info.c_ty != "void": - write_c(arg_conv_info.c_ty + " " + arg_conv_info.arg_name) - out_java.write(arg_conv_info.java_ty + " " + arg_conv_info.arg_name) - if idx == 0 and arg_conv_info.java_hu_ty == struct_meth: + + for argument_index, argument in enumerate(method_arguments): + argument_conversion_info = type_mapping_generator.map_type(argument, False, None, is_free, True) + if argument_index == 0 and argument_conversion_info.java_hu_ty == struct_meth: takes_self = True - if arg_conv_info.arg_conv is not None and "Warning" in arg_conv_info.arg_conv: - if arg_conv_info.rust_obj in constructor_fns: + if argument_conversion_info.arg_conv is not None and "Warning" in argument_conversion_info.arg_conv: + if argument_conversion_info.rust_obj in constructor_fns: assert not is_free - for explode_arg in constructor_fns[arg_conv_info.rust_obj].split(','): + for explode_arg in constructor_fns[argument_conversion_info.rust_obj].split(','): explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True) if explode_arg_conv.c_ty == "void": # We actually want to handle this case, but for now its only used in NetGraphMsgHandler::new() # which ends up resulting in a redundant constructor - both without arguments for the NetworkGraph. args_known = False pass - if not arg_conv_info.arg_name in default_constructor_args: - default_constructor_args[arg_conv_info.arg_name] = [] - default_constructor_args[arg_conv_info.arg_name].append(explode_arg_conv) - arg_names.append(arg_conv_info) + if not argument_conversion_info.arg_name in default_constructor_args: + default_constructor_args[argument_conversion_info.arg_name] = [] + default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv) + argument_types.append(argument_conversion_info) + + out_java.write("\t// " + line) + (out_java_delta, out_c_delta, out_java_struct_delta) = consts.map_function(argument_types, c_call_string, method_name, return_type_info, struct_meth, default_constructor_args, takes_self, args_known, type_mapping_generator) + out_java.write(out_java_delta) + + if is_free: + assert len(argument_types) == 1 + assert return_type_info.c_ty == "void" + write_c(consts.c_fn_ty_pfx + "void " + consts.c_fn_name_define_pfx(method_name, True) + argument_types[0].c_ty + " " + argument_types[0].ty_info.var_name + ") {\n") + if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs: + write_c("\tif ((" + argument_types[0].ty_info.var_name + " & 1) != 0) return;\n") + + for info in argument_types: + if info.arg_conv is not None: + write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n") + assert c_call_string is None + write_c("\t" + method_name + "(") + if argument_types[0].arg_conv_name is not None: + write_c(argument_types[0].arg_conv_name) + write_c(");") + for info in argument_types: + if info.arg_conv_cleanup is not None: + write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t")) + write_c("\n}\n\n") + else: + write_c(out_c_delta) out_java_struct = None if ("LDK" + struct_meth in opaque_structs or "LDK" + struct_meth in trait_structs) and not is_free: out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a") - if not args_known: - out_java_struct.write("\t// Skipped " + re_match.group(2) + "\n") - out_java_struct.close() - out_java_struct = None - else: - meth_n = re_match.group(2)[len(struct_meth) + 1:] - if not takes_self: - out_java_struct.write("\tpublic static " + ret_info.java_hu_ty + " constructor_" + meth_n + "(") - else: - out_java_struct.write("\tpublic " + ret_info.java_hu_ty + " " + meth_n + "(") - for idx, arg in enumerate(arg_names): - if idx != 0: - if not takes_self or idx > 1: - out_java_struct.write(", ") - elif takes_self: - continue - if arg.java_ty != "void": - if arg.arg_name in default_constructor_args: - for explode_idx, explode_arg in enumerate(default_constructor_args[arg.arg_name]): - if explode_idx != 0: - out_java_struct.write(", ") - out_java_struct.write(explode_arg.java_hu_ty + " " + arg.arg_name + "_" + explode_arg.arg_name) - else: - out_java_struct.write(arg.java_hu_ty + " " + arg.arg_name) - - - out_java.write(");\n") - write_c(") {\n") + elif method_name.startswith("C2Tuple_") and method_name.endswith("_read"): + struct_meth = method_name.rsplit("_", 1)[0] + out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") if out_java_struct is not None: - out_java_struct.write(") {\n") - - for info in arg_names: - if info.arg_conv is not None: - write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n") - - if ret_info.ret_conv is not None: - write_c("\t" + ret_conv_pfx.replace('\n', '\n\t')) - elif ret_info.c_ty != "void": - write_c("\t" + ret_info.c_ty + " ret_val = ") - else: - write_c("\t") - - if c_call_string is None: - write_c(re_match.group(2) + "(") - else: - write_c(c_call_string) - for idx, info in enumerate(arg_names): - if info.arg_conv_name is not None: - if idx != 0: - write_c(", ") - elif c_call_string is not None: - continue - write_c(info.arg_conv_name) - write_c(")") - if ret_info.ret_conv is not None: - write_c(ret_conv_sfx.replace('\n', '\n\t')) - else: - write_c(";") - for info in arg_names: - if info.arg_conv_cleanup is not None: - write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t")) - if ret_info.ret_conv is not None: - write_c("\n\treturn " + ret_info.ret_conv_name + ";") - elif ret_info.c_ty != "void": - write_c("\n\treturn ret_val;") - write_c("\n}\n\n") - if out_java_struct is not None: - out_java_struct.write("\t\t") - if ret_info.java_ty != "void": - out_java_struct.write(ret_info.java_ty + " ret = ") - out_java_struct.write("bindings." + re_match.group(2) + "(") - for idx, info in enumerate(arg_names): - if idx != 0: - out_java_struct.write(", ") - if idx == 0 and takes_self: - out_java_struct.write("this.ptr") - elif info.arg_name in default_constructor_args: - out_java_struct.write("bindings." + info.java_hu_ty + "_new(") - for explode_idx, explode_arg in enumerate(default_constructor_args[info.arg_name]): - if explode_idx != 0: - out_java_struct.write(", ") - expl_arg_name = info.arg_name + "_" + explode_arg.arg_name - if explode_arg.from_hu_conv is not None: - out_java_struct.write(explode_arg.from_hu_conv[0].replace(explode_arg.arg_name, expl_arg_name)) - else: - out_java_struct.write(expl_arg_name) - out_java_struct.write(")") - elif info.from_hu_conv is not None: - out_java_struct.write(info.from_hu_conv[0]) - else: - out_java_struct.write(info.arg_name) - out_java_struct.write(");\n") - if ret_info.to_hu_conv is not None: - if not takes_self: - out_java_struct.write("\t\t" + ret_info.to_hu_conv.replace("\n", "\n\t\t").replace("this", ret_info.to_hu_conv_name) + "\n") - else: - out_java_struct.write("\t\t" + ret_info.to_hu_conv.replace("\n", "\n\t\t") + "\n") - - for idx, info in enumerate(arg_names): - if idx == 0 and takes_self: - pass - elif info.arg_name in default_constructor_args: - for explode_arg in default_constructor_args[info.arg_name]: - expl_arg_name = info.arg_name + "_" + explode_arg.arg_name - if explode_arg.from_hu_conv is not None and ret_info.to_hu_conv_name: - out_java_struct.write("\t\t" + explode_arg.from_hu_conv[1].replace(explode_arg.arg_name, expl_arg_name).replace("this", ret_info.to_hu_conv_name) + ";\n") - elif info.from_hu_conv is not None and info.from_hu_conv[1] != "": - if not takes_self and ret_info.to_hu_conv_name is not None: - out_java_struct.write("\t\t" + info.from_hu_conv[1].replace("this", ret_info.to_hu_conv_name) + ";\n") - else: - out_java_struct.write("\t\t" + info.from_hu_conv[1] + ";\n") - - if ret_info.to_hu_conv_name is not None: - out_java_struct.write("\t\treturn " + ret_info.to_hu_conv_name + ";\n") - elif ret_info.java_ty != "void" and ret_info.rust_obj != "LDK" + struct_meth: - out_java_struct.write("\t\treturn ret;\n") - out_java_struct.write("\t}\n\n") - out_java_struct.close() + out_java_struct.write(out_java_struct_delta) def map_unitary_enum(struct_name, field_lines): with open(f"{sys.argv[3]}/enums/{struct_name}{consts.file_ext}", "w") as out_java_enum: @@ -657,13 +565,13 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: can_clone = False out_java.write("\tpublic static native boolean " + struct_name + "_result_ok(long arg);\n") - write_c(consts.c_fn_ty_pfx + "jboolean " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1result_1ok (" + consts.c_fn_args_pfx + ", " + consts.ptr_c_ty + " arg) {\n") + write_c(consts.c_fn_ty_pfx + "jboolean " + consts.c_fn_name_define_pfx(struct_name + "_result_ok", True) + consts.ptr_c_ty + " arg) {\n") write_c("\treturn ((" + struct_name + "*)arg)->result_ok;\n") write_c("}\n") out_java.write("\tpublic static native " + res_map.java_ty + " " + struct_name + "_get_ok(long arg);\n") - write_c(consts.c_fn_ty_pfx + res_map.c_ty + " " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1get_1ok (" + consts.c_fn_args_pfx + ", " + consts.ptr_c_ty + " arg) {\n") - write_c("\t" + struct_name + " *val = (" + struct_name + "*)arg;\n") + write_c(consts.c_fn_ty_pfx + res_map.c_ty + " " + consts.c_fn_name_define_pfx(struct_name + "_get_ok", True) + consts.ptr_c_ty + " arg) {\n") + write_c("\t" + struct_name + " *val = (" + struct_name + "*)(arg & ~1);\n") write_c("\tCHECK(val->result_ok);\n\t") out_java_struct.write("\tpublic static final class " + human_ty + "_OK extends " + human_ty + " {\n") if res_map.ret_conv is not None: @@ -693,14 +601,14 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: if res_map.from_hu_conv is not None: out_java_struct.write("\t\t\tthis(null, bindings.C" + human_ty + "_ok(" + res_map.from_hu_conv[0] + "));\n") if res_map.from_hu_conv[1] != "": - out_java_struct.write("\t\t\t" + res_map.from_hu_conv[1] + ";\n") + out_java_struct.write("\t\t\t" + res_map.from_hu_conv[1].replace("\n", "\n\t\t\t") + ";\n") else: out_java_struct.write("\t\t\tthis(null, bindings.C" + human_ty + "_ok(res));\n") out_java_struct.write("\t\t}\n\t}\n\n") out_java.write("\tpublic static native " + err_map.java_ty + " " + struct_name + "_get_err(long arg);\n") - write_c(consts.c_fn_ty_pfx + err_map.c_ty + " " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1get_1err (" + consts.c_fn_args_pfx + ", " + consts.ptr_c_ty + " arg) {\n") - write_c("\t" + struct_name + " *val = (" + struct_name + "*)arg;\n") + write_c(consts.c_fn_ty_pfx + err_map.c_ty + " " + consts.c_fn_name_define_pfx(struct_name + "_get_err", True) + consts.ptr_c_ty + " arg) {\n") + write_c("\t" + struct_name + " *val = (" + struct_name + "*)(arg & ~1);\n") write_c("\tCHECK(!val->result_ok);\n\t") out_java_struct.write("\tpublic static final class " + human_ty + "_Err extends " + human_ty + " {\n") if err_map.ret_conv is not None: @@ -731,59 +639,29 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: if err_map.from_hu_conv is not None: out_java_struct.write("\t\t\tthis(null, bindings.C" + human_ty + "_err(" + err_map.from_hu_conv[0] + "));\n") if err_map.from_hu_conv[1] != "": - out_java_struct.write("\t\t\t" + err_map.from_hu_conv[1] + ";\n") + out_java_struct.write("\t\t\t" + err_map.from_hu_conv[1].replace("\n", "\n\t\t\t") + ";\n") else: out_java_struct.write("\t\t\tthis(null, bindings.C" + human_ty + "_err(err));\n") out_java_struct.write("\t\t}\n\t}\n}\n") - if can_clone: - clone_fns.add(struct_name.replace("LDK", "") + "_clone") - write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n") - write_c("\t" + struct_name + " res = { .result_ok = orig->result_ok };\n") - write_c("\tif (orig->result_ok) {\n") - if res_map.c_ty == "void": - write_c("\t\tres.contents.result = NULL;\n") - else: - if res_map.is_native_primitive: - write_c("\t\t" + res_map.c_ty + "* contents = MALLOC(sizeof(" + res_map.c_ty + "), \"" + res_map.c_ty + " result OK clone\");\n") - write_c("\t\t*contents = *orig->contents.result;\n") - else: - write_c("\t\t" + res_map.rust_obj + "* contents = MALLOC(sizeof(" + res_map.rust_obj + "), \"" + res_map.rust_obj + " result OK clone\");\n") - write_c("\t\t*contents = " + res_map.rust_obj.replace("LDK", "") + "_clone(orig->contents.result);\n") - write_c("\t\tres.contents.result = contents;\n") - write_c("\t} else {\n") - if err_map.c_ty == "void": - write_c("\t\tres.contents.err = NULL;\n") - else: - if err_map.is_native_primitive: - write_c("\t\t" + err_map.c_ty + "* contents = MALLOC(sizeof(" + err_map.c_ty + "), \"" + err_map.c_ty + " result Err clone\");\n") - write_c("\t\t*contents = *orig->contents.err;\n") - else: - write_c("\t\t" + err_map.rust_obj + "* contents = MALLOC(sizeof(" + err_map.rust_obj + "), \"" + err_map.rust_obj + " result Err clone\");\n") - write_c("\t\t*contents = " + err_map.rust_obj.replace("LDK", "") + "_clone(orig->contents.err);\n") - write_c("\t\tres.contents.err = contents;\n") - write_c("\t}\n\treturn res;\n}\n") - def map_tuple(struct_name, field_lines): out_java.write("\tpublic static native long " + struct_name + "_new(") - write_c(consts.c_fn_ty_pfx + consts.ptr_c_ty + " " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1new(" + consts.c_fn_args_pfx) + write_c(consts.c_fn_ty_pfx + consts.ptr_c_ty + " " + consts.c_fn_name_define_pfx(struct_name + "_new", len(field_lines) > 3)) ty_list = [] for idx, line in enumerate(field_lines): if idx != 0 and idx < len(field_lines) - 2: ty_info = java_c_types(line.strip(';'), None) if idx != 1: out_java.write(", ") + write_c(", ") e = chr(ord('a') + idx - 1) out_java.write(ty_info.java_ty + " " + e) - write_c(", " + ty_info.c_ty + " " + e) + write_c(ty_info.c_ty + " " + e) ty_list.append(ty_info) tuple_types[struct_name] = (ty_list, struct_name) out_java.write(");\n") write_c(") {\n") write_c("\t" + struct_name + "* ret = MALLOC(sizeof(" + struct_name + "), \"" + struct_name + "\");\n") - can_clone = True - clone_str = "static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n" - clone_str = clone_str + "\t" + struct_name + " ret = {\n" for idx, line in enumerate(field_lines): if idx != 0 and idx < len(field_lines) - 2: ty_info = type_mapping_generator.map_type(line.strip(';'), False, None, False, False) @@ -795,25 +673,14 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: write_c("\tret->" + e + " = " + e + ";\n") if ty_info.arg_conv_cleanup is not None: write_c("\t//TODO: Really need to call " + ty_info.arg_conv_cleanup + " here\n") - if not ty_info.is_native_primitive and (ty_info.rust_obj.replace("LDK", "") + "_clone") not in clone_fns: - can_clone = False - elif can_clone and ty_info.is_native_primitive: - clone_str = clone_str + "\t\t." + chr(ord('a') + idx - 1) + " = orig->" + chr(ord('a') + idx - 1) + ",\n" - elif can_clone: - clone_str = clone_str + "\t\t." + chr(ord('a') + idx - 1) + " = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->" + chr(ord('a') + idx - 1) + "),\n" write_c("\treturn (long)ret;\n") write_c("}\n") - if can_clone: - clone_fns.add(struct_name.replace("LDK", "") + "_clone") - write_c(clone_str) - write_c("\t};\n\treturn ret;\n}\n") - for idx, ty_info in enumerate(ty_list): e = chr(ord('a') + idx) out_java.write("\tpublic static native " + ty_info.java_ty + " " + struct_name + "_get_" + e + "(long ptr);\n") - write_c(consts.c_fn_ty_pfx + ty_info.c_ty + " " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1get_1" + e + "(" + consts.c_fn_args_pfx + ", " + consts.ptr_c_ty + " ptr) {\n") - write_c("\t" + struct_name + " *tuple = (" + struct_name + "*)ptr;\n") + write_c(consts.c_fn_ty_pfx + ty_info.c_ty + " " + consts.c_fn_name_define_pfx(struct_name + "_get_" + e, True) + consts.ptr_c_ty + " ptr) {\n") + write_c("\t" + struct_name + " *tuple = (" + struct_name + "*)(ptr & ~1);\n") conv_info = type_mapping_generator.map_type_with_info(ty_info, False, None, False, True) if conv_info.ret_conv is not None: write_c("\t" + conv_info.ret_conv[0].replace("\n", "\n\t") + "tuple->" + e + conv_info.ret_conv[1].replace("\n", "\n\t") + "\n") @@ -936,7 +803,7 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: ty_info = type_mapping_generator.map_type(vec_ty + " arr_elem", False, None, False, False) if len(ty_info.java_fn_ty_arg) == 1: # ie we're a primitive of some form out_java.write("\tpublic static native long " + struct_name + "_new(" + ty_info.java_ty + "[] elems);\n") - write_c(consts.c_fn_ty_pfx + consts.ptr_c_ty + " " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1new(" + consts.c_fn_args_pfx + ", " + ty_info.c_ty + "Array elems) {\n") + write_c(consts.c_fn_ty_pfx + consts.ptr_c_ty + " " + consts.c_fn_name_define_pfx(struct_name + "_new", True) + ty_info.c_ty + "Array elems) {\n") write_c("\t" + struct_name + " *ret = MALLOC(sizeof(" + struct_name + "), \"" + struct_name + "\");\n") write_c("\tret->datalen = " + consts.get_native_arr_len_call[0] + "elems" + consts.get_native_arr_len_call[1] + ";\n") write_c("\tif (ret->datalen == 0) {\n") @@ -1035,14 +902,17 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: else: assert(line == "\n") - out_java.write("}\n") + out_java.write(consts.bindings_footer) for struct_name in opaque_structs: with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct: out_java_struct.write("}\n") for struct_name in trait_structs: with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct: out_java_struct.write("}\n") + with open(sys.argv[4], "w") as out_c: out_c.write(consts.c_file_pfx) out_c.write(consts.init_str()) out_c.write(c_file) +with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util: + util.write(consts.util_fn_sfx)