main.odin (5299B)
1 package bindgen2 2 3 import vmem "core:mem/virtual" 4 import "core:mem" 5 import "core:os" 6 import "core:os/os2" 7 import "core:fmt" 8 import "core:strings" 9 import "core:path/filepath" 10 import "base:runtime" 11 import "core:encoding/json" 12 import "core:slice" 13 import "core:log" 14 15 main :: proc() { 16 permanent_arena: vmem.Arena 17 permanent_allocator := vmem.arena_allocator(&permanent_arena) 18 context.allocator = permanent_allocator 19 context.temp_allocator = permanent_allocator 20 context.logger = log.create_console_logger() 21 22 ensure(len(os.args) == 2, "Usage: 'bindgen directory' or 'bindgen directory/bindgen.sjson'") 23 config_dir_or_file := os.args[1] 24 25 DEFAULT_CONFIG_FILENAME :: "bindgen.sjson" 26 27 config_filename: string 28 dir: string 29 30 if strings.has_suffix(config_dir_or_file, ".sjson") && os.is_file(config_dir_or_file) { 31 config_filename = config_dir_or_file 32 dir = filepath.dir(config_dir_or_file) 33 } else if os.is_dir(config_dir_or_file) { 34 config_filename = filepath.join({config_dir_or_file, DEFAULT_CONFIG_FILENAME}) 35 dir = config_dir_or_file 36 } else { 37 fmt.panicf("%v is not a directory nor a valid config file", config_dir_or_file) 38 } 39 40 default_output_folder := "output" 41 default_package_name := "pkg" 42 43 if config_dir_handle, config_dir_handle_err := os2.open(dir); config_dir_handle_err == nil { 44 if stat, stat_err := config_dir_handle.fstat(config_dir_handle, context.allocator); stat_err == nil { 45 default_output_folder = stat.name 46 default_package_name = stat.name 47 } 48 } 49 50 config: Config 51 52 if os.is_file(config_filename) { 53 if config_data, config_data_ok := os.read_entire_file(config_filename); config_data_ok { 54 config_err := json.unmarshal(config_data, &config, .SJSON) 55 fmt.ensuref( 56 config_err == nil, 57 "Failed parsing config %v: %v", 58 config_filename, 59 config_err, 60 ) 61 } else { 62 fmt.ensuref(config_data_ok, "Failed parsing config %v", config_filename) 63 } 64 } else { 65 config.inputs = slice.clone([]string{"."}) 66 } 67 68 output_folder := filepath.join({dir, config.output_folder != "" ? config.output_folder : default_output_folder}) 69 package_name := config.package_name != "" ? config.package_name : default_package_name 70 71 if config.imports_file != "" { 72 config.imports_file = filepath.join({dir, config.imports_file}) 73 } 74 75 input_files: [dynamic]string 76 77 for input_base in config.inputs { 78 input := filepath.join({dir, input_base}) 79 if os.is_dir(input) { 80 input_folder, input_folder_err := os2.open(input) 81 log.ensuref(input_folder_err == nil, "Failed opening folder %v: %v", input, input_folder_err) 82 iter := os2.read_directory_iterator_create(input_folder) 83 84 for f in os2.read_directory_iterator(&iter) { 85 if f.type != .Regular { 86 continue 87 } 88 89 append(&input_files, filepath.join({input, f.name})) 90 } 91 92 os2.close(input_folder) 93 } else if os.is_file(input) { 94 append(&input_files, input) 95 } else { 96 log.errorf("%v is neither directory or .h file", input) 97 } 98 } 99 100 if output_folder != "" && !os2.exists(output_folder) { 101 make_dir_err := os2.make_directory_all(output_folder) 102 log.ensuref(make_dir_err == nil, "Failed creating output directory %v: %v", output_folder, make_dir_err) 103 } 104 105 for input_filename in input_files { 106 if filepath.ext(input_filename) == ".h" { 107 types_arena: vmem.Arena 108 types_arena_err := vmem.arena_init_static(&types_arena, 100 * mem.Megabyte) 109 log.assertf(types_arena_err == nil, "Failed reserving types arena memory. Error: %v", types_arena_err) 110 111 decls_arena: vmem.Arena 112 decls_arena_err := vmem.arena_init_static(&decls_arena, 100 * mem.Megabyte) 113 log.assertf(decls_arena_err == nil, "Failed reserving types arena memory. Error: %v", decls_arena_err) 114 115 type_arr := make([dynamic]Type, allocator = vmem.arena_allocator(&types_arena)) 116 types := Type_List(&type_arr) 117 decl_arr := make([dynamic]Decl, allocator = vmem.arena_allocator(&decls_arena)) 118 decls := Decl_List(&decl_arr) 119 120 add_decl(decls, {}) 121 add_type(types, {}) 122 123 gen_arena: vmem.Arena 124 context.allocator = vmem.arena_allocator(&gen_arena) 125 context.temp_allocator = vmem.arena_allocator(&gen_arena) 126 gen_ctx = context 127 128 log.infof("Collecting data from %v", input_filename) 129 collect_res, collect_ok := translate_collect(input_filename, config, types, decls) 130 131 if !collect_ok { 132 continue 133 } 134 135 translate_macros(collect_res.macros, decls) 136 137 log.infof("Processing data from %v", input_filename) 138 process_res := translate_process(collect_res, config, types, decls) 139 140 input_folder := filepath.dir(input_filename) 141 filename_stem := filepath.stem(input_filename) 142 footer_filename := filepath.join({input_folder, fmt.tprintf("%v_footer.odin", filename_stem)}) 143 144 footer: string 145 if os.exists(footer_filename) { 146 if footer_bytes, footer_bytes_ok := os.read_entire_file(footer_filename); footer_bytes_ok { 147 footer = string(footer_bytes) 148 } 149 } 150 151 output_filename := filepath.join({output_folder, fmt.tprintf("%v.odin", filename_stem)}) 152 log.infof("Writing %v", output_filename) 153 output(types, decls, process_res, output_filename, footer, package_name) 154 vmem.arena_destroy(&gen_arena) 155 vmem.arena_destroy(&types_arena) 156 vmem.arena_destroy(&decls_arena) 157 } 158 } 159 } 160 161 gen_ctx: runtime.Context 162 163 to_cstring :: proc(str: string) -> cstring { 164 return strings.clone_to_cstring(str) 165 }