Skip to content

Commit f83c8bf

Browse files
authored
v.pref: allow for -os wasm32_emscripten and filtering _d_wasm32_emscripten.c.v and _notd_wasm32_emscripten.c.v files. (#23797)
1 parent 252df04 commit f83c8bf

File tree

13 files changed

+171
-43
lines changed

13 files changed

+171
-43
lines changed

examples/2048/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@
22
2048
33
main
44

5+
index.js
6+
index.wasm

examples/2048/README.md

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ Compile & run the game with `./v run examples/2048`
2828

2929
## Compiling to WASM
3030

31-
1. Install Emscripten from https://emscripten.org/docs/getting_started/downloads.html
31+
1. Install Emscripten from:
32+
https://emscripten.org/docs/getting_started/downloads.html
3233

3334
2. Make sure that the environment in your shell is setup correctly,
3435
i.e. that `emcc --version` works.
@@ -39,15 +40,9 @@ Compile & run the game with `./v run examples/2048`
3940
```
4041

4142
3. Compile the game to WASM:
42-
43-
```sh
44-
v -skip-unused -prod -os wasm32_emscripten examples/2048/`
45-
```
46-
47-
4. Copy the 2048 file to `index.js` (can be done once; this step will be removed soon):
48-
43+
(the JS file contains a loader for the .wasm file, without the extension):
4944
```sh
50-
cp examples/2048/2048 examples/2048/index.js
45+
v -prod -os wasm32_emscripten -o examples/2048/index.js examples/2048/
5146
```
5247

5348
5. Run/test the game:

vlib/os/os.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ pub fn find_abs_path_of_executable(exe_name string) !string {
608608
$if trace_find_abs_path_of_executable ? {
609609
dump(found_abs_path)
610610
}
611-
if exists(found_abs_path) && is_executable(found_abs_path) {
611+
if is_file(found_abs_path) && is_executable(found_abs_path) {
612612
res = found_abs_path
613613
break
614614
}

vlib/v/builder/cc.v

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ pub enum CC {
108108
icc
109109
msvc
110110
clang
111+
emcc
111112
unknown
112113
}
113114

@@ -210,6 +211,7 @@ fn (mut v Builder) setup_ccompiler_options(ccompiler string) {
210211
cc_file_name.contains('clang') || ccoptions.guessed_compiler == 'clang' { .clang }
211212
cc_file_name.contains('msvc') || ccoptions.guessed_compiler == 'msvc' { .msvc }
212213
cc_file_name.contains('icc') || ccoptions.guessed_compiler == 'icc' { .icc }
214+
cc_file_name.contains('emcc') || ccoptions.guessed_compiler == 'emcc' { .emcc }
213215
else { .unknown }
214216
// vfmt on
215217
}
@@ -652,7 +654,7 @@ pub fn (mut v Builder) cc() {
652654
// whether to just create a .c or .js file and exit, for example: `v -o v.c cmd.v`
653655
ends_with_c := v.pref.out_name.ends_with('.c')
654656
ends_with_js := v.pref.out_name.ends_with('.js')
655-
if ends_with_c || ends_with_js {
657+
if ends_with_c || (ends_with_js && v.pref.os != .wasm32_emscripten) {
656658
v.pref.skip_running = true
657659
msg_mv := 'os.mv_by_cp ${os.quoted_path(v.out_name_c)} => ${os.quoted_path(v.pref.out_name)}'
658660
util.timing_start(msg_mv)

vlib/v/pref/default.v

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ fn (mut p Preferences) setup_os_and_arch_when_not_explicitly_set() {
6161
host_os := if p.backend == .wasm { OS.wasi } else { get_host_os() }
6262
if p.os == ._auto {
6363
p.os = host_os
64-
p.build_options << '-os ${host_os}'
64+
p.build_options << '-os ${host_os.lower()}'
6565
}
6666

6767
if !p.output_cross_c {
@@ -83,6 +83,19 @@ fn (mut p Preferences) setup_os_and_arch_when_not_explicitly_set() {
8383
}
8484
}
8585

86+
pub fn (mut p Preferences) defines_map_unique_keys() string {
87+
mut defines_map := map[string]bool{}
88+
for d in p.compile_defines {
89+
defines_map[d] = true
90+
}
91+
for d in p.compile_defines_all {
92+
defines_map[d] = true
93+
}
94+
keys := defines_map.keys()
95+
skeys := keys.sorted()
96+
return skeys.join(',')
97+
}
98+
8699
pub fn (mut p Preferences) fill_with_defaults() {
87100
p.setup_os_and_arch_when_not_explicitly_set()
88101
p.expand_lookup_paths()
@@ -189,17 +202,20 @@ pub fn (mut p Preferences) fill_with_defaults() {
189202
}
190203
}
191204
}
205+
206+
final_os := p.os.lower()
207+
p.parse_define(final_os)
208+
192209
// Prepare the cache manager. All options that can affect the generated cached .c files
193210
// should go into res.cache_manager.vopts, which is used as a salt for the cache hash.
194211
vhash := @VHASH
195212
p.cache_manager = vcache.new_cache_manager([
196213
vhash,
197214
// ensure that different v versions use separate build artefacts
198-
'${p.backend} | ${p.os} | ${p.ccompiler} | ${p.is_prod} | ${p.sanitize}',
215+
'${p.backend} | ${final_os} | ${p.ccompiler} | ${p.is_prod} | ${p.sanitize}',
216+
p.defines_map_unique_keys(),
199217
p.cflags.trim_space(),
200218
p.third_party_option.trim_space(),
201-
p.compile_defines_all.str(),
202-
p.compile_defines.str(),
203219
p.lookup_path.str(),
204220
])
205221
// eprintln('prefs.cache_manager: $p')

vlib/v/pref/os.v

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,41 @@ pub fn os_from_string(os_str string) !OS {
131131
}
132132
}
133133

134+
// lower returns the name that could be used with `-os osname`, for each OS enum value
135+
// NOTE: it is important to not change the names here, they should match 1:1, since they
136+
// are used as part of the cache keys, when -usecache is passed.
137+
pub fn (o OS) lower() string {
138+
return match o {
139+
._auto { '' }
140+
.linux { 'linux' }
141+
.windows { 'windows' }
142+
.macos { 'macos' }
143+
.ios { 'ios' }
144+
.freebsd { 'freebsd' }
145+
.openbsd { 'openbsd' }
146+
.netbsd { 'netbsd' }
147+
.dragonfly { 'dragonfly' }
148+
.js_node { 'js' }
149+
.js_freestanding { 'js_freestanding' }
150+
.js_browser { 'js_browser' }
151+
.solaris { 'solaris' }
152+
.serenity { 'serenity' }
153+
.qnx { 'qnx' }
154+
.plan9 { 'plan9' }
155+
.vinix { 'vinix' }
156+
.android { 'android' }
157+
.termux { 'termux' }
158+
.haiku { 'haiku' }
159+
.raw { 'raw' }
160+
.wasm32 { 'wasm32' }
161+
.wasm32_wasi { 'wasm32_wasi' }
162+
.wasm32_emscripten { 'wasm32_emscripten' }
163+
.browser { 'browser' }
164+
.wasi { 'wasi' }
165+
.all { 'all' }
166+
}
167+
}
168+
134169
pub fn (o OS) str() string {
135170
// TODO: check more thoroughly, why this method needs to exist at all,
136171
// and why should it override the default autogenerated .str() method,

vlib/v/pref/pref.v

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ pub enum CompilerType {
7676
gcc
7777
tinyc
7878
clang
79+
emcc
7980
mingw
8081
msvc
8182
cplusplus
@@ -830,7 +831,7 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin
830831
res.build_options << '${arg}'
831832
}
832833
'-os' {
833-
target_os := cmdline.option(args[i..], '-os', '')
834+
target_os := cmdline.option(args[i..], '-os', '').to_lower_ascii()
834835
i++
835836
target_os_kind := os_from_string(target_os) or {
836837
if target_os == 'cross' {
@@ -895,12 +896,6 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin
895896
}
896897
'-o', '-output' {
897898
res.out_name = cmdline.option(args[i..], arg, '')
898-
if res.out_name.ends_with('.js') {
899-
res.backend = .js_node
900-
res.output_cross_c = true
901-
} else if res.out_name.ends_with('.o') {
902-
res.is_o = true
903-
}
904899
if !os.is_abs_path(res.out_name) {
905900
res.out_name = os.join_path(os.getwd(), res.out_name)
906901
}
@@ -1053,6 +1048,18 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin
10531048
res.is_run = true
10541049
}
10551050
res.show_asserts = res.show_asserts || res.is_stats || os.getenv('VTEST_SHOW_ASSERTS') != ''
1051+
1052+
if res.os != .wasm32_emscripten {
1053+
if res.out_name.ends_with('.js') {
1054+
res.backend = .js_node
1055+
res.output_cross_c = true
1056+
}
1057+
}
1058+
1059+
if res.out_name.ends_with('.o') {
1060+
res.is_o = true
1061+
}
1062+
10561063
if command == 'run' && res.is_prod && os.is_atty(1) > 0 {
10571064
eprintln_cond(show_output && !res.is_quiet, "Note: building an optimized binary takes much longer. It shouldn't be used with `v run`.")
10581065
eprintln_cond(show_output && !res.is_quiet, 'Use `v run` without optimization, or build an optimized binary with -prod first, then run it separately.')
@@ -1226,6 +1233,7 @@ pub fn cc_from_string(s string) CompilerType {
12261233
cc.contains('tcc') || cc.contains('tinyc') { .tinyc }
12271234
cc.contains('gcc') { .gcc }
12281235
cc.contains('clang') { .clang }
1236+
cc.contains('emcc') { .emcc }
12291237
cc.contains('msvc') { .msvc }
12301238
cc.contains('mingw') { .mingw }
12311239
cc.contains('++') { .cplusplus }

vlib/v/pref/should_compile.v

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,28 +15,9 @@ pub fn (prefs &Preferences) should_compile_filtered_files(dir string, files_ []s
1515
|| file.all_before_last('.v').all_before_last('.').ends_with('_test') {
1616
continue
1717
}
18-
if prefs.backend in [.c, .interpret] && !prefs.should_compile_c(file) {
19-
continue
20-
}
21-
if prefs.backend.is_js() && !prefs.should_compile_js(file) {
22-
continue
23-
}
24-
if prefs.backend == .native && !prefs.should_compile_native(file) {
25-
continue
26-
}
27-
if !prefs.backend.is_js() && !prefs.should_compile_asm(file) {
28-
continue
29-
}
30-
if file.starts_with('.#') {
31-
continue
32-
}
33-
if !prefs.prealloc && !prefs.output_cross_c && file.ends_with('prealloc.c.v') {
34-
continue
35-
}
36-
if prefs.nofloat && file.ends_with('float.c.v') {
37-
continue
38-
}
18+
mut is_d_notd_file := false
3919
if file.contains('_d_') {
20+
is_d_notd_file = true
4021
if prefs.compile_defines_all.len == 0 {
4122
continue
4223
}
@@ -58,6 +39,7 @@ pub fn (prefs &Preferences) should_compile_filtered_files(dir string, files_ []s
5839
}
5940
}
6041
if file.contains('_notd_') {
42+
is_d_notd_file = true
6143
mut allowed := true
6244
for cdefine in prefs.compile_defines {
6345
file_postfixes := ['_notd_${cdefine}.v', '_notd_${cdefine}.c.v']
@@ -75,6 +57,27 @@ pub fn (prefs &Preferences) should_compile_filtered_files(dir string, files_ []s
7557
continue
7658
}
7759
}
60+
if prefs.backend in [.c, .interpret] && !is_d_notd_file && !prefs.should_compile_c(file) {
61+
continue
62+
}
63+
if prefs.backend.is_js() && !prefs.should_compile_js(file) {
64+
continue
65+
}
66+
if prefs.backend == .native && !prefs.should_compile_native(file) {
67+
continue
68+
}
69+
if !prefs.backend.is_js() && !prefs.should_compile_asm(file) {
70+
continue
71+
}
72+
if file.starts_with('.#') {
73+
continue
74+
}
75+
if !prefs.prealloc && !prefs.output_cross_c && file.ends_with('prealloc.c.v') {
76+
continue
77+
}
78+
if prefs.nofloat && file.ends_with('float.c.v') {
79+
continue
80+
}
7881
if prefs.exclude.len > 0 {
7982
full_file_path := os.join_path(dir, file)
8083
for epattern in prefs.exclude {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module main
2+
3+
fn abc() {
4+
println('This is abc_d_wasm32_emscripten.c.v')
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module main
2+
3+
fn abc() {
4+
println('This is abc_notd_wasm32_emscripten.c.v')
5+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import os
2+
3+
const vexe = os.quoted_path(@VEXE)
4+
const project_folder = os.dir(@FILE)
5+
const output_path = os.join_path(os.vtmp_dir(), 'check_wasm_works')
6+
7+
fn testsuite_begin() {
8+
os.mkdir_all(output_path) or {}
9+
os.chdir(output_path)!
10+
dump(os.getwd())
11+
}
12+
13+
fn testsuite_end() {
14+
os.system('ls -la .')
15+
os.chdir(os.home_dir()) or {}
16+
os.rmdir_all(output_path) or {}
17+
}
18+
19+
fn test_normal() {
20+
if os.user_os() == 'windows' {
21+
return
22+
}
23+
defer { println('done ${@FN}') }
24+
dump(vexe)
25+
res := os.system('${os.quoted_path(vexe)} -o normal.exe ${os.quoted_path(project_folder)}')
26+
assert res == 0
27+
dump(res)
28+
assert os.exists('normal.exe')
29+
content := os.read_file('normal.exe')!
30+
assert content.contains('This is abc_notd_wasm32_emscripten.c.v')
31+
}
32+
33+
fn test_emcc() {
34+
if os.user_os() == 'windows' {
35+
return
36+
}
37+
defer { println('done ${@FN}') }
38+
emcc := os.find_abs_path_of_executable('emcc') or {
39+
println('skipping ${@FN} since `emcc` is not found')
40+
return
41+
}
42+
dump(emcc)
43+
res := os.system('${os.quoted_path(vexe)} -os wasm32_emscripten -o wasm_check.html ${os.quoted_path(project_folder)}')
44+
assert res == 0
45+
dump(res)
46+
assert os.exists('wasm_check.html')
47+
assert os.exists('wasm_check.js')
48+
assert os.exists('wasm_check.wasm')
49+
content := os.read_file('wasm_check.wasm')!
50+
assert content.contains('This is abc_d_wasm32_emscripten.c.v')
51+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module main
2+
3+
fn main() {
4+
abc()
5+
println('hi from main.v')
6+
}

vlib/v/tests/project_compiling_to_wasm/v.mod

Whitespace-only changes.

0 commit comments

Comments
 (0)