diff --git a/examples/2048/2048.v b/examples/2048/2048.v index 2d505ac4e3..50e4c5b1fa 100644 --- a/examples/2048/2048.v +++ b/examples/2048/2048.v @@ -909,6 +909,10 @@ fn (mut app App) showfps() { } } +$if emscripten ? { + #flag --embed-file ./examples/assets/fonts/RobotoMono-Regular.ttf@/assets/fonts/RobotoMono-Regular.ttf +} + fn main() { mut app := &App{} app.new_game() diff --git a/vlib/os/os.c.v b/vlib/os/os.c.v index 241e156039..36306ab269 100644 --- a/vlib/os/os.c.v +++ b/vlib/os/os.c.v @@ -901,7 +901,9 @@ pub fn fork() int { pub fn wait() int { mut pid := -1 $if !windows { - pid = C.wait(0) + $if !emscripten ? { + pid = C.wait(0) + } } $if windows { panic('os.wait not supported in windows') // TODO diff --git a/vlib/os/os_nix.c.v b/vlib/os/os_nix.c.v index 3d5998b659..05de17dc16 100644 --- a/vlib/os/os_nix.c.v +++ b/vlib/os/os_nix.c.v @@ -8,7 +8,7 @@ import strings #include #include #include -$if !solaris && !haiku { +$if !solaris && !haiku && !emscripten ? { #include } diff --git a/vlib/os/process_nix.c.v b/vlib/os/process_nix.c.v index c063a7b8b7..82df797606 100644 --- a/vlib/os/process_nix.c.v +++ b/vlib/os/process_nix.c.v @@ -75,7 +75,10 @@ fn (mut p Process) unix_kill_pgroup() { fn (mut p Process) unix_wait() { cstatus := 0 - ret := C.waitpid(p.pid, &cstatus, 0) + mut ret := -1 + $if !emscripten ? { + ret = C.waitpid(p.pid, &cstatus, 0) + } if ret == -1 { p.err = posix_get_error_msg(C.errno) return @@ -92,7 +95,10 @@ fn (mut p Process) unix_wait() { fn (mut p Process) unix_is_alive() bool { cstatus := 0 - ret := C.waitpid(p.pid, &cstatus, C.WNOHANG) + mut ret := -1 + $if !emscripten ? { + ret = C.waitpid(p.pid, &cstatus, C.WNOHANG) + } if ret == -1 { p.err = posix_get_error_msg(C.errno) return false diff --git a/vlib/sokol/c/declaration.c.v b/vlib/sokol/c/declaration.c.v index 3f2f977ad9..919fd736d0 100644 --- a/vlib/sokol/c/declaration.c.v +++ b/vlib/sokol/c/declaration.c.v @@ -25,6 +25,15 @@ $if ios { #flag -DSOKOL_METAL #flag -framework Foundation -framework Metal -framework MetalKit -framework UIKit } + +$if emscripten ? { + #flag -DSOKOL_GLES2 + #flag -DSOKOL_NO_ENTRY + #flag -s ERROR_ON_UNDEFINED_SYMBOLS=0 + #flag -s ASSERTIONS=1 + #flag -s MODULARIZE +} + // OPENGL #flag linux -DSOKOL_GLCORE33 #flag freebsd -DSOKOL_GLCORE33 diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v index 9ae69217f5..0b32ab10e5 100644 --- a/vlib/v/ast/types.v +++ b/vlib/v/ast/types.v @@ -42,6 +42,7 @@ pub enum Language { arm32 // 32-bit arm rv64 // 64-bit risc-v rv32 // 32-bit risc-v + wasm32 } pub fn pref_arch_to_table_language(pref_arch pref.Arch) Language { @@ -67,6 +68,9 @@ pub fn pref_arch_to_table_language(pref_arch pref.Arch) Language { .js_node, .js_browser, .js_freestanding { .js } + .wasm32 { + .wasm32 + } ._auto, ._max { .v } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 46560ef9df..dd2c186338 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -32,7 +32,7 @@ pub const ( valid_comptime_if_cpu_features = ['x64', 'x32', 'little_endian', 'big_endian'] valid_comptime_if_other = ['apk', 'js', 'debug', 'prod', 'test', 'glibc', 'prealloc', 'no_bounds_checking', 'freestanding', 'threads', 'js_node', 'js_browser', 'js_freestanding', - 'interpreter', 'es5', 'profile'] + 'interpreter', 'es5', 'profile', 'wasm32_emscripten'] valid_comptime_not_user_defined = all_valid_comptime_idents() array_builtin_methods = ['filter', 'clone', 'repeat', 'reverse', 'map', 'slice', 'sort', 'contains', 'index', 'wait', 'any', 'all', 'first', 'last', 'pop'] diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index c25b282d35..582de25530 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -279,7 +279,8 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { inner_loop: &ast.empty_stmt field_data_type: ast.Type(table.find_type_idx('FieldData')) is_cc_msvc: pref.ccompiler == 'msvc' - use_segfault_handler: !('no_segfault_handler' in pref.compile_defines || pref.os == .wasm32) + use_segfault_handler: !('no_segfault_handler' in pref.compile_defines + || pref.os in [.wasm32, .wasm32_emscripten]) } // anon fn may include assert and thus this needs // to be included before any test contents are written diff --git a/vlib/v/gen/c/comptime.v b/vlib/v/gen/c/comptime.v index e231c2f481..ce5e51e165 100644 --- a/vlib/v/gen/c/comptime.v +++ b/vlib/v/gen/c/comptime.v @@ -657,6 +657,9 @@ fn (mut g Gen) comptime_if_to_ifdef(name string, is_comptime_optional bool) ?str 'js' { return '_VJS' } + 'wasm32_emscripten' { + return '__EMSCRIPTEN__' + } // compilers: 'gcc' { return '__V_GCC__' diff --git a/vlib/v/pref/default.v b/vlib/v/pref/default.v index 4c5cdc4c29..0646b6d4dc 100644 --- a/vlib/v/pref/default.v +++ b/vlib/v/pref/default.v @@ -102,6 +102,10 @@ pub fn (mut p Preferences) fill_with_defaults() { if p.is_debug { p.parse_define('debug') } + if p.os == .wasm32_emscripten { + // TODO: remove after `$if wasm32_emscripten {` works + p.parse_define('emscripten') + } if p.os == ._auto { // No OS specifed? Use current system p.os = get_host_os() @@ -276,6 +280,9 @@ pub fn (p &Preferences) vcross_compiler_name() string { if p.os == .linux { return 'clang' } + if p.os == .wasm32_emscripten { + return 'emcc' + } if p.backend == .c && !p.out_name.ends_with('.c') { eprintln('Note: V can only cross compile to windows and linux for now by default.') eprintln('It will use `cc` as a cross compiler for now, although that will probably fail.') diff --git a/vlib/v/pref/os.v b/vlib/v/pref/os.v index e874d04196..410de3205c 100644 --- a/vlib/v/pref/os.v +++ b/vlib/v/pref/os.v @@ -34,33 +34,94 @@ pub enum OS { // Helper function to convert string names to OS enum pub fn os_from_string(os_str string) ?OS { match os_str { - 'linux' { return .linux } - 'windows' { return .windows } - 'ios' { return .ios } - 'macos' { return .macos } - 'darwin' { return .macos } - 'freebsd' { return .freebsd } - 'openbsd' { return .openbsd } - 'netbsd' { return .netbsd } - 'dragonfly' { return .dragonfly } - 'js', 'js_node' { return .js_node } - 'js_freestanding' { return .js_freestanding } - 'js_browser' { return .js_browser } - 'solaris' { return .solaris } - 'serenity' { return .serenity } - 'vinix' { return .vinix } - 'android' { return .android } - 'termux' { return .termux } - 'haiku' { return .haiku } - 'raw' { return .raw } - 'nix' { return .linux } - 'wasm32' { return .wasm32 } - 'wasm32-wasi' { return .wasm32_wasi } // TODO: remove these *or* the _ ones - 'wasm32-emscripten' { return .wasm32_emscripten } - 'wasm32_wasi' { return .wasm32_wasi } - 'wasm32_emscripten' { return .wasm32_emscripten } - '' { return ._auto } - else { return error('bad OS $os_str') } + '' { + return ._auto + } + 'linux' { + return .linux + } + 'nix' { + return .linux + } + 'windows' { + return .windows + } + 'ios' { + return .ios + } + 'macos' { + return .macos + } + 'darwin' { + return .macos + } + 'freebsd' { + return .freebsd + } + 'openbsd' { + return .openbsd + } + 'netbsd' { + return .netbsd + } + 'dragonfly' { + return .dragonfly + } + 'js', 'js_node' { + return .js_node + } + 'js_freestanding' { + return .js_freestanding + } + 'js_browser' { + return .js_browser + } + 'solaris' { + return .solaris + } + 'serenity' { + return .serenity + } + 'vinix' { + return .vinix + } + 'android' { + return .android + } + 'termux' { + return .termux + } + 'haiku' { + return .haiku + } + 'raw' { + return .raw + } + // WASM options: + 'wasm32' { + return .wasm32 + } + 'wasm32_wasi' { + return .wasm32_wasi + } + 'wasm32_emscripten' { + return .wasm32_emscripten + } + else { + // handle deprecated names: + match os_str { + 'wasm32-emscripten' { + eprintln('Please use `-os wasm32_emscripten` instead.') + return .wasm32_emscripten + } + 'wasm32-wasi' { + eprintln('Please use `-os wasm32_wasi` instead.') + return .wasm32_wasi + } + else {} + } + return error('bad OS $os_str') + } } } @@ -99,6 +160,13 @@ pub fn get_host_os() OS { $if android { return .android } + $if emscripten ? { + return .wasm32_emscripten + } + // TODO: make this work: + // $if wasm32_emscripten { + // return .wasm32_emscripten + // } $if linux { return .linux } diff --git a/vlib/v/pref/pref.v b/vlib/v/pref/pref.v index d756a3fec4..43deb35c60 100644 --- a/vlib/v/pref/pref.v +++ b/vlib/v/pref/pref.v @@ -82,12 +82,13 @@ pub enum Arch { js_node js_browser js_freestanding + wasm32 _max } const ( - list_of_flags_with_param = ['o', 'd', 'define', 'b', 'backend', 'cc', 'os', 'target-os', 'cf', - 'cflags', 'path', 'arch'] + list_of_flags_with_param = ['o', 'd', 'define', 'b', 'backend', 'cc', 'os', 'cf', 'cflags', + 'path', 'arch'] ) [heap; minify] @@ -606,6 +607,12 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin if target_os_kind == .wasm32 { res.is_bare = true } + if target_os_kind in [.wasm32, .wasm32_emscripten, .wasm32_wasi] { + res.arch = .wasm32 + } + if target_os_kind == .wasm32_emscripten { + res.gc_mode = .no_gc // TODO: enable gc (turn off threads etc, in builtin_d_gcboehm.c.v, once `$if wasm32_emscripten {` works) + } res.os = target_os_kind res.build_options << '$arg $target_os' } @@ -870,36 +877,39 @@ pub fn arch_from_string(arch_str string) ?Arch { match arch_str { 'amd64', 'x86_64', 'x64', 'x86' { // amd64 recommended - return Arch.amd64 + return .amd64 } 'aarch64', 'arm64' { // arm64 recommended - return Arch.arm64 + return .arm64 } 'aarch32', 'arm32', 'arm' { // arm32 recommended - return Arch.arm32 + return .arm32 } 'rv64', 'riscv64', 'risc-v64', 'riscv', 'risc-v' { // rv64 recommended - return Arch.rv64 + return .rv64 } 'rv32', 'riscv32' { // rv32 recommended - return Arch.rv32 + return .rv32 } 'x86_32', 'x32', 'i386', 'IA-32', 'ia-32', 'ia32' { // i386 recommended - return Arch.i386 + return .i386 } 'js', 'js_node' { - return Arch.js_node + return .js_node } 'js_browser' { - return Arch.js_browser + return .js_browser } 'js_freestanding' { - return Arch.js_freestanding + return .js_freestanding + } + 'wasm32' { + return .wasm32 } '' { return ._auto