v / cmd / tools / vshould-compile-all.v
130 lines · 124 sloc · 4.2 KB · b00f68cb2b01efd152e07e786d9ca454fb88b2e0
Raw
1import os
2import log
3
4const should_clean = os.args.contains('-c')
5
6fn main() {
7 log.use_stdout()
8 unbuffer_stdout()
9 mut files := []string{}
10 args := os.args#[2..].filter(it != '-c')
11 for a in args {
12 if os.is_file(a) {
13 files << a
14 continue
15 }
16 if os.is_dir(a) {
17 files << os.walk_ext(a, '.v')
18 continue
19 }
20 }
21 files.sort()
22 if files.len == 0 {
23 println('0 .v files found.\n')
24 println('Usage:')
25 println(' v should-compile-all [-c] examples/ some/deep/file.v another/')
26 println('... will try to compile all .v files found in the given folders and files, one by one.')
27 println('If every single one of them compiles, the command will exit with an error code of 0.')
28 println('If *any* of them *fail* to compile, the command will exit with an error code of 1.')
29 println('')
30 println(' -c will remove all the compiled executables at the end.')
31 println('')
32 println('Note: this command is intended to be used in CI pipelines for v modules, like this:')
33 println(' cd module/ ; v should-compile-all examples/ \n')
34 exit(1)
35 }
36 mut executables := []string{}
37 mut failed_commands := []string{}
38 mut project_folders := map[string]bool{}
39 mut skipped_files := []string{}
40 for idx, example in files {
41 folder_of_example := os.dir(example)
42 if os.is_file(os.join_path_single(folder_of_example, '.skip_should_compile_all')) {
43 log.info('>>> skipping file: ${example}, because a `.skip_should_compile_all` file is present next to it.')
44 skipped_files << example
45 continue
46 }
47 // project folders usually contain many .v files, that are *all* part of the same program.
48 // NOTE: => projects should be compiled with `v project/`.
49 // To do that, just record the presence of such a folder for now, and try to compile it separately later.
50 if project_folders[folder_of_example] {
51 skipped_files << example
52 continue
53 }
54 if os.is_file(os.join_path_single(folder_of_example, 'v.mod')) {
55 log.info('>>> delaying compilation of entire project folder ${folder_of_example} ...')
56 project_folders[folder_of_example] = true
57 skipped_files << example
58 continue
59 }
60 //
61 mut backend_options := '-b c'
62 if example.ends_with('.wasm.v') {
63 backend_options = '-b wasm -os browser'
64 }
65 if example.ends_with('.js.v') {
66 backend_options = '-b js'
67 }
68 lines := os.read_lines(example)!#[..50].filter(it.starts_with('module'))
69 if lines.len > 0 && lines[0] !in ['module main', 'module no_main'] {
70 log.info('>>> skipping non main module file: ${example}')
71 skipped_files << example
72 continue
73 }
74 cmd := '${os.quoted_path(@VEXE)} ${backend_options} ${os.quoted_path(example)}'
75 log.info('> compiling program ${idx + 1:4}/${files.len:-4}: ${cmd}')
76 if 0 != os.system(cmd) {
77 failed_commands << cmd
78 } else {
79 executables << executable_name(example)
80 }
81 }
82
83 mut glsl_folders := map[string]bool{}
84 mut pfi := 0
85 for pf, _ in project_folders {
86 glsl_files := os.walk_ext(pf, '.glsl')
87 if glsl_files.len > 0 {
88 if pf !in glsl_folders {
89 log.debug('>>> found .glsl files in ${pf} ... running `v shader ${pf}` ...')
90 os.system('${os.quoted_path(@VEXE)} shader ${os.quoted_path(pf)}')
91 glsl_folders[pf] = true
92 }
93 }
94 exe_path := os.join_path(pf, os.file_name(pf) + exe_extension)
95 cmd := '${os.quoted_path(@VEXE)} -o ${exe_path} ${pf}'
96 log.info('> compiling project ${pfi + 1:4}/${project_folders.len:-4}: ${cmd}')
97 if 0 != os.system(cmd) {
98 failed_commands << cmd
99 } else {
100 executables << exe_path
101 }
102 pfi++
103 }
104
105 if should_clean {
106 log.info('Removing ${executables.len} successfully build executables...')
107 for f in executables {
108 os.rm(f) or { log.error('>> could not remove ${f}, err: ${err}') }
109 }
110 }
111 if failed_commands.len > 0 {
112 for idx, fcmd in failed_commands {
113 log.error('>>> FAILED command ${idx + 1:4}/${failed_commands.len:-4}: ${fcmd}')
114 }
115 log.info('Summary: ${failed_commands.len:4}/${files.len:-4} file(s) failed to compile.')
116 exit(1)
117 }
118 log.info('Summary: all ${files.len} program file(s), and ${project_folders.len} project(s) compiled successfully. Skipped files: ${skipped_files.len} .')
119}
120
121const exe_extension = if os.user_os() == 'windows' {
122 '.exe'
123} else {
124 ''
125}
126
127fn executable_name(source string) string {
128 basepath := source.replace(os.file_ext(source), '')
129 return basepath + exe_extension
130}
131