#scope_file; LOWERCASE_FIELD_NAMES :: true; #run { set_build_options_dc(.{ do_output = false }); files_to_generate :: string.[ "radians", "degrees", "turns", ]; for files_to_generate { print("building library for unit: %\n", it); assert(build(it, dynamic = true, simd = true), "failed to build library, unit: %", it); assert(build(it, dynamic = true, simd = false), "failed to build library, unit: %", it); assert(build(it, dynamic = false, simd = false), "failed to build library, unit: %", it); assert(build(it, dynamic = false, simd = true), "failed to build library, unit: %", it); } print("generating bindings\n"); assert(generate(simd = true), "failed to generate bindings"); assert(generate(simd = false), "failed to generate bindings"); } build :: (unit: string, dynamic: bool, simd: bool) -> bool { #if OS == { case .WINDOWS; export_attribute :: "__declspec(dllexport)"; case; export_attribute :: "__attribute__((visibility(\"default\")))"; } tmp_data := tprint(#string END #define static #define inline #define COVERAGE(a, b) %1 #define HANDMADE_MATH_USE_%2 %3 #include "../HandmadeMath.h" END, export_attribute, to_upper_copy(unit), ifx !simd then "#define HANDMADE_MATH_NO_SIMD" else "", ); tmp_file := tprint(".build/tmp_%.c", ifx simd then "simd" else "nosimd"); if !write_entire_file(tmp_file, tmp_data) return false; #if OS == { case .WINDOWS; out_base :: "win"; case .MACOS; out_base :: "mac"; case .LINUX; out_base :: "linux"; } lib_name := tprint("hmm_%", unit); if simd lib_name = tprint("%_simd", lib_name); else lib_name = tprint("%_nosimd", lib_name); out_path := tprint("%/%", out_base, lib_name); lib_type := Build_Type.STATIC_LIBRARY; if dynamic lib_type = .DYNAMIC_LIBRARY; return build_cpp(out_path, tmp_file, type = lib_type); } generate :: (simd: bool) -> bool { #if OS == { case .WINDOWS; lib_ext :: "dll"; case .MACOS; lib_ext :: "dylib"; case .LINUX; lib_ext :: "so"; } #if OS == { case .WINDOWS; out_base :: "win"; case .MACOS; out_base :: "mac"; case .LINUX; out_base :: "linux"; } suffix := "simd"; if !simd suffix = "nosimd"; simd_support = simd; opts: Generate_Bindings_Options; opts.add_generator_command = false; opts.generate_library_declarations = false; opts.visitor = fixup_wrong_types; array_add(*opts.strip_prefixes, "HMM_", "_HMM_"); array_add(*opts.extra_clang_arguments, "-x", "c"); array_add(*opts.libpaths, out_base); array_add(*opts.libnames, tprint("hmm_radians_%.%", suffix, lib_ext)); array_add(*opts.source_files, tprint(".build/tmp_%.c", suffix)); if !generate_bindings(opts, tprint("hmm_%.jai", suffix)) { return false; } return true; } simd_support := false; fixup_wrong_types :: (decl: *Declaration, parent: *Declaration) -> Declaration_Visit_Result { if decl.kind == { case .TYPEDEF; td := decl.(*Typedef); if td.name == { // when simd support is specified, these are generated incorrectly so we create them manually case "HMM_Vec4"; #through; case "HMM_Quat"; if simd_support { td.decl_flags = .OMIT_FROM_OUTPUT; td.type.type_of_struct.decl_flags = .OMIT_FROM_OUTPUT; } } #if !LOWERCASE_FIELD_NAMES return .STOP; lower_names_recursive :: (s: *Struct) { for s.declarations { it.output_name = pascal_to_snake(it.name); if it.type.type_of_struct != null { lower_names_recursive(it.type.type_of_struct); } } } if td.type.type_of_struct != null { lower_names_recursive(td.type.type_of_struct); } return .RECURSE; case .FUNCTION; func := decl.(*Function); if func.name == { case "__hmm_invalid_generic"; func.decl_flags = .OMIT_FROM_OUTPUT; return .STOP; } // snake_case argument names funct := func.type.type_of_function; for funct.arguments { it.output_name = pascal_to_snake(it.name); } } return .STOP; } pascal_to_snake :: (name: string) -> string { is_upper :: (byte: u8) -> bool { return byte >= #char "A" && byte <= #char "Z"; } b: String_Builder; add_underscore := false; for 0..name.count - 1 { if is_upper(name[it]) { if it > 0 && name[it-1] != #char "_" { add_underscore = true; } if it-1 >= 0 && is_upper(name[it-1]) { add_underscore = false; } } if add_underscore { add_underscore = false; append(*b, "_"); } append(*b, to_lower(name[it])); } return builder_to_string(*b); } #import "File"; #import "Basic"; #import "String"; #import "Compiler"; #import "BuildCpp"; #import "Bindings_Generator";