diff --git a/GOALS.md b/GOALS.md index 55a5737..817cd84 100644 --- a/GOALS.md +++ b/GOALS.md @@ -1,7 +1,7 @@ # Goals for future versions + Wrapper - + [ ] Add `from_compiler_flags` to import the compiler flags from `from` + + [x] Add `from_compiler_flags` to import the compiler flags from `from` + [ ] Add `includedirs`, `defines`, `flags` fields which get added on top of the `from_compiler_flags` + [ ] Add `load_all_includes` + [ ] Make more multi platform: Separate files for each platform diff --git a/cpp/wrapper/wrapper.odin b/cpp/wrapper/wrapper.odin index 6e26996..b892f9b 100644 --- a/cpp/wrapper/wrapper.odin +++ b/cpp/wrapper/wrapper.odin @@ -22,6 +22,7 @@ import "core:io" import "core:os" import "core:path/filepath" import "core:strings" +import cppcdg "root:cpp/codegen" import "root:errors" import "root:runic" import clang "shared:libclang" @@ -32,72 +33,76 @@ ClientData :: struct { source: io.Writer, } -generate_wrapper :: proc(rn: runic.Wrapper) -> (err: union { +generate_wrapper :: proc( + rn: runic.Wrapper, + rf: Maybe(runic.From), +) -> ( + err: union { errors.Error, io.Error, - }) { + }, +) { arena: runtime.Arena errors.wrap(runtime.arena_init(&arena, 0, context.allocator)) or_return defer runtime.arena_destroy(&arena) arena_alloc := runtime.arena_allocator(&arena) - clang_flags := [?]cstring { - // Android - "-U__ANDROID__", - // BSD - "-U__FreeBSD__", - "-U__FreeBSD_kernel__", - "-U__NetBSD__", - "-U__OpenBSD__", - "-U__bsdi__", - "-U__DragonFly__", - "-U_SYSTYPE_BSD", - "-UBSD", - // Linux - "-U__GLIBC__", - "-U__gnu_linux__", - "-U__linux__", - "-Ulinux", - "-U__linux", - // MacOS - "-Umacintosh", - "-UMacintosh", - "-U__APPLE__", - "-U__MACH__", - // Windows - "-U_WIN16", - "-U_WIN32", - "-U_WIN64", - // AMD64 & x86_64 - "-U__amd64__", - "-U__amd64", - "-U__x86_64__", - "-U__x86_64", - // ARM - "-U__arm__", - "-U__thumb__", - "-U__aarch64__", - // x86 - "-Ui386", - "-U__i386", - "-U__i386__", - "-U__i486__", - "-U__i586__", - "-U__i686__", - - // Linux - "-D__GLIBC__", - "-D__gnu_linux__", - "-D__linux__", - "-Dlinux", - "-D__linux", - // x86_64 - "-D__amd64__", - "-D__amd64", - "-D__x86_64__", - "-D__x86_64", - // Target - "--target=x86_64-linux-gnu", + // TODO: do not hardcode the platform + plat := runic.Platform{.Linux, .x86_64} + + defines: map[string]string + include_dirs: []string + flags: []cstring + + if rn.from_compiler_flags { + if from, from_ok := rf.?; from_ok { + from_defines, d_ok := runic.platform_value_get( + map[string]string, + from.defines, + plat, + ) + if d_ok do defines = from_defines + + from_include_dirs, inc_ok := runic.platform_value_get( + []string, + from.includedirs, + plat, + ) + if inc_ok do include_dirs = from_include_dirs + + from_flags, f_ok := runic.platform_value_get( + []cstring, + from.flags, + plat, + ) + if f_ok do flags = from_flags + } + } + + clang_flags := cppcdg.generate_clang_flags( + plat = plat, + disable_stdint_macros = false, + defines = defines, + include_dirs = include_dirs, + enable_host_includes = false, + stdinc_gen_dir = nil, + flags = flags, + allocator = arena_alloc, + ) + defer delete(clang_flags) + + when ODIN_DEBUG { + os.write_string(os.stderr, "wrapper clang_flags:") + for flag in clang_flags { + os.write_string(os.stderr, " \"") + + flag_str := strings.clone_from_cstring(flag) + defer delete(flag_str) + + os.write_string(os.stderr, flag_str) + os.write_rune(os.stderr, '"') + } + os.write_rune(os.stderr, '\n') } out_header, out_header_err := os.open( diff --git a/cpp/wrapper/wrapper_test.odin b/cpp/wrapper/wrapper_test.odin index ac1b187..174595d 100644 --- a/cpp/wrapper/wrapper_test.odin +++ b/cpp/wrapper/wrapper_test.odin @@ -37,13 +37,20 @@ test_cpp_wrapper :: proc(t: ^testing.T) { defer delete(out_source) rn := runic.Wrapper { - language = "c", - in_headers = {in_header}, - out_header = out_header, - out_source = out_source, + language = "c", + in_headers = {in_header}, + out_header = out_header, + out_source = out_source, + from_compiler_flags = true, } - err := generate_wrapper(rn) + rf := runic.From { + defines = {{{} = {"DYNA_FUNC" = "1"}}}, + } + defer delete(rf.defines.d) + defer delete(rf.defines.d[{}]) + + err := generate_wrapper(rn, rf) expect_value(t, err, nil) header_data, header_ok := os.read_entire_file( @@ -65,8 +72,10 @@ extern void print_stuff_wrapper(int a, int b); extern const float ** do_other_stuff_wrapper(float c, float ** d); extern spelling_t alphabet_wrapper(); extern struct foo_t japanese_wrapper(); +extern int dyna_func_wrapper(int a, int b); ` + SOURCE_EXPECTED :: `#include "wrapper_out_header.h" void print_stuff_wrapper(int a, int b) { @@ -85,8 +94,13 @@ struct foo_t japanese_wrapper() { return japanese(); } +int dyna_func_wrapper(int a, int b) { + return dyna_func(a, b); +} + ` + if expect_value(t, len(string(header_data)), len(HEADER_EXPECTED)) { expect_value(t, string(header_data), HEADER_EXPECTED) } diff --git a/runic.odin b/runic.odin index 0feaf9b..b96ac98 100644 --- a/runic.odin +++ b/runic.odin @@ -99,7 +99,12 @@ main :: proc() { if wrapper, ok := rune.wrapper.?; ok { switch strings.to_lower(wrapper.language, context.temp_allocator) { case "c", "cpp", "c++", "cxx": - err = errors.wrap(cppwrap.generate_wrapper(wrapper)) + from: Maybe(runic.From) + if rf, rf_ok := rune.from.(runic.From); rf_ok { + from = rf + } + + err = errors.wrap(cppwrap.generate_wrapper(wrapper, from)) case: fmt.eprintfln( "wrapper language \"{}\" is not supported", diff --git a/runic/rune.odin b/runic/rune.odin index f80e4d4..1c1a137 100644 --- a/runic/rune.odin +++ b/runic/rune.odin @@ -184,7 +184,9 @@ parse_rune :: proc( } if wrapper_value, wrapper_ok := y["wrapper"]; wrapper_ok { - wrapper: Wrapper + wrapper := Wrapper { + from_compiler_flags = true, + } #partial switch wrapper_map in wrapper_value { case yaml.Mapping: @@ -201,6 +203,20 @@ parse_rune :: proc( return } + if from_compiler_flags, ok := + wrapper_map["from_compiler_flags"]; ok { + #partial switch v in from_compiler_flags { + case bool: + wrapper.from_compiler_flags = v + case: + err = errors.message( + "\"wrapper.from_compiler_flags\" has invalid type %T", + v, + ) + return + } + } + if in_headers_value, ok := wrapper_map["in_headers"]; ok { #partial switch in_headers in in_headers_value { case yaml.Sequence: diff --git a/runic/rune_test.odin b/runic/rune_test.odin index 76a7ca3..3c3db0e 100644 --- a/runic/rune_test.odin +++ b/runic/rune_test.odin @@ -164,6 +164,7 @@ test_rune :: proc(t: ^testing.T) { wrapper := rn.wrapper.? expect_value(t, wrapper.language, "c") + expect_value(t, wrapper.from_compiler_flags, false) expect_value(t, len(wrapper.in_headers), 1) expect_value(t, wrapper.in_headers[0], in_header) expect_value(t, wrapper.out_header, out_header) diff --git a/runic/rune_types.odin b/runic/rune_types.odin index 57a85c0..351e38f 100644 --- a/runic/rune_types.odin +++ b/runic/rune_types.odin @@ -78,12 +78,14 @@ To :: struct { add_libs: PlatformValue([]string), } +// TODO: maybe make all values PlatformValue Wrapper :: struct { - language: string, + language: string, // C/C++ - in_headers: []string, - out_header: string, - out_source: string, + from_compiler_flags: bool, + in_headers: []string, + out_header: string, + out_source: string, } TrimSet :: struct { diff --git a/test_data/rune.yml b/test_data/rune.yml index d885ab6..ed04623 100644 --- a/test_data/rune.yml +++ b/test_data/rune.yml @@ -4,6 +4,7 @@ platforms: - Windows x86_64 wrapper: language: c + from_compiler_flags: false in_headers: wrapper.h out_header: wrapper.gen.h out_source: wrapper.gen.c diff --git a/test_data/wrapper_in_header.h b/test_data/wrapper_in_header.h index 0ad891d..ad36712 100644 --- a/test_data/wrapper_in_header.h +++ b/test_data/wrapper_in_header.h @@ -17,3 +17,7 @@ inline struct foo_t japanese() { return foo_tert{}; } struct foo_t chinese() { return foo_t {} } + +#ifdef DYNA_FUNC +inline int dyna_func(int a, int b) { return a + b; } +#endif