v2 / vlib / v / pref / should_compile.v
418 lines · 399 sloc · 11.71 KB · a24f57285fe53d359b21bbe253c38288c9d26031
Raw
1module pref
2
3import os
4
5pub fn (prefs &Preferences) should_compile_filtered_files(dir string, files_ []string) []string {
6 mut res := []string{}
7 mut files := files_.clone()
8 files.sort()
9 mut all_v_files := []string{}
10 files_loop: for file in files {
11 if !file.ends_with('.v') && !file.ends_with('.vh') {
12 continue
13 }
14 if file.ends_with('_test.v')
15 || file.all_before_last('.v').all_before_last('.').ends_with('_test') {
16 continue
17 }
18 mut is_d_notd_file := false
19 if file.contains('_d_') {
20 is_d_notd_file = true
21 if prefs.compile_defines_all.len == 0 {
22 continue
23 }
24 mut allowed := false
25 for cdefine in prefs.compile_defines {
26 file_postfixes := ['_d_${cdefine}.v', '_d_${cdefine}.c.v']
27 for file_postfix in file_postfixes {
28 if file.ends_with(file_postfix) {
29 allowed = true
30 break
31 }
32 }
33 if allowed {
34 break
35 }
36 }
37 if !allowed {
38 continue
39 }
40 }
41 if file.contains('_notd_') {
42 is_d_notd_file = true
43 mut allowed := true
44 for cdefine in prefs.compile_defines {
45 file_postfixes := ['_notd_${cdefine}.v', '_notd_${cdefine}.c.v']
46 for file_postfix in file_postfixes {
47 if file.ends_with(file_postfix) {
48 allowed = false
49 break
50 }
51 }
52 if !allowed {
53 break
54 }
55 }
56 if !allowed {
57 continue
58 }
59 }
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.is_js() && !prefs.should_compile_asm(file) {
67 continue
68 }
69 if prefs.backend == .wasm && !prefs.should_compile_wasm(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 }
81 if prefs.exclude.len > 0 {
82 full_file_path := os.join_path(dir, file)
83 for epattern in prefs.exclude {
84 if full_file_path.match_glob(epattern) {
85 continue files_loop
86 }
87 }
88 }
89 all_v_files << os.join_path(dir, file)
90 }
91
92 mut defaults := []string{}
93 mut fnames_no_postfixes := map[string][]string{}
94 for file in all_v_files {
95 if file.contains('default.c.v') {
96 defaults << file
97 } else {
98 res << file
99 no_postfix_key := fname_without_platform_postfix(file)
100 mut candidates := fnames_no_postfixes[no_postfix_key]
101 candidates << file
102 fnames_no_postfixes[no_postfix_key] = candidates
103 }
104 }
105 for file in defaults {
106 no_postfix_key := fname_without_platform_postfix(file)
107 if no_postfix_key in fnames_no_postfixes {
108 if prefs.is_verbose {
109 println('>>> should_compile_filtered_files: skipping _default.c.v file ${file} ; the specialized versions are: ${fnames_no_postfixes[no_postfix_key]}')
110 }
111 continue
112 }
113 res << file
114 }
115 res = prefs.filter_bsd_specific_files(res)
116 if prefs.is_verbose {
117 // println('>>> prefs: ${prefs}')
118 println('>>> should_compile_filtered_files: res: ${res}')
119 }
120 return res
121}
122
123const platform_specific_postfixes = [
124 '_android_outside_termux.c.v',
125 '_wasm32_emscripten.c.v',
126 '_wasm32_emscripten.v',
127 '_dragonfly.c.v',
128 '_dragonfly.v',
129 '_windows.c.v',
130 '_windows.v',
131 '_freebsd.c.v',
132 '_freebsd.v',
133 '_openbsd.c.v',
134 '_openbsd.v',
135 '_netbsd.c.v',
136 '_netbsd.v',
137 '_solaris.c.v',
138 '_serenity.c.v',
139 '_android.c.v',
140 '_termux.c.v',
141 '_darwin.c.v',
142 '_darwin.v',
143 '_macos.c.v',
144 '_macos.v',
145 '_linux.c.v',
146 '_linux.v',
147 '_default.c.v',
148 '_bsd.c.v',
149 '_bsd.v',
150 '_nix.c.v',
151 '_nix.v',
152 '_ios.c.v',
153 '_ios.v',
154 '_qnx.c.v',
155 '_plan9.c.v',
156 '_vinix.c.v',
157 '_haiku.c.v',
158]
159
160fn fname_without_platform_postfix(file string) string {
161 for postfix in platform_specific_postfixes {
162 if file.ends_with(postfix) {
163 return file[..file.len - postfix.len]
164 }
165 }
166 return file
167}
168
169struct BsdSpecificFiles {
170mut:
171 has_bsd bool
172 has_exact bool
173}
174
175fn (prefs &Preferences) filter_bsd_specific_files(files []string) []string {
176 if !prefs.os.is_bsd_target() {
177 return files
178 }
179 mut variants := map[string]BsdSpecificFiles{}
180 for file in files {
181 kind := prefs.bsd_specific_file_kind(file)
182 if kind == '' {
183 continue
184 }
185 key := fname_without_platform_postfix(file)
186 mut info := variants[key]
187 if kind == 'bsd' {
188 info.has_bsd = true
189 }
190 if kind == 'exact' {
191 info.has_exact = true
192 }
193 variants[key] = info
194 }
195 mut res := []string{}
196 for file in files {
197 kind := prefs.bsd_specific_file_kind(file)
198 if kind == '' {
199 res << file
200 continue
201 }
202 info := variants[fname_without_platform_postfix(file)]
203 if kind == 'nix' && info.has_bsd {
204 if prefs.is_verbose {
205 println('>>> should_compile_filtered_files: skipping _nix file ${file} ; _bsd is more specific')
206 }
207 continue
208 }
209 if kind == 'bsd' && info.has_exact {
210 if prefs.is_verbose {
211 println('>>> should_compile_filtered_files: skipping _bsd file ${file} ; exact BSD target is more specific')
212 }
213 continue
214 }
215 res << file
216 }
217 return res
218}
219
220fn (prefs &Preferences) bsd_specific_file_kind(file string) string {
221 if file.ends_with('_nix.c.v') || file.ends_with('_nix.v') {
222 return 'nix'
223 }
224 if file.ends_with('_bsd.c.v') || file.ends_with('_bsd.v') {
225 return 'bsd'
226 }
227 if prefs.os == .macos && (file.ends_with('_darwin.c.v') || file.ends_with('_darwin.v')
228 || file.ends_with('_macos.c.v') || file.ends_with('_macos.v')) {
229 return 'exact'
230 }
231 if prefs.os == .freebsd && (file.ends_with('_freebsd.c.v') || file.ends_with('_freebsd.v')) {
232 return 'exact'
233 }
234 if prefs.os == .openbsd && (file.ends_with('_openbsd.c.v') || file.ends_with('_openbsd.v')) {
235 return 'exact'
236 }
237 if prefs.os == .netbsd && (file.ends_with('_netbsd.c.v') || file.ends_with('_netbsd.v')) {
238 return 'exact'
239 }
240 if prefs.os == .dragonfly
241 && (file.ends_with('_dragonfly.c.v') || file.ends_with('_dragonfly.v')) {
242 return 'exact'
243 }
244 return ''
245}
246
247// TODO: Rework this using is_target_of()
248pub fn (prefs &Preferences) should_compile_c(file string) bool {
249 if file.ends_with('.js.v') || file.ends_with('.wasm.v') {
250 // Probably something like `a.js.v` or `a.wasm.v`.
251 return false
252 }
253 if prefs.is_bare && file.ends_with('.freestanding.v') {
254 return true
255 }
256 if prefs.os == .all {
257 return true
258 }
259 if file.ends_with('_native.v') {
260 return false
261 }
262 if prefs.building_v && prefs.output_cross_c && file.ends_with('_windows.v') {
263 // TODO: temp hack to make msvc_windows.v work with -os cross
264 return true
265 }
266 if prefs.os == .windows && (file.ends_with('_nix.c.v') || file.ends_with('_nix.v')) {
267 return false
268 }
269 if prefs.os != .windows && (file.ends_with('_windows.c.v') || file.ends_with('_windows.v')) {
270 return false
271 }
272
273 if prefs.os != .linux && (file.ends_with('_linux.c.v') || file.ends_with('_linux.v')) {
274 return false
275 }
276
277 if prefs.os != .macos && (file.ends_with('_darwin.c.v') || file.ends_with('_darwin.v')) {
278 return false
279 }
280 if prefs.os != .macos && (file.ends_with('_macos.c.v') || file.ends_with('_macos.v')) {
281 return false
282 }
283
284 if prefs.os != .ios && (file.ends_with('_ios.c.v') || file.ends_with('_ios.v')) {
285 return false
286 }
287 if !prefs.os.is_bsd_target() && (file.ends_with('_bsd.c.v') || file.ends_with('_bsd.v')) {
288 return false
289 }
290 if prefs.os != .freebsd && (file.ends_with('_freebsd.c.v') || file.ends_with('_freebsd.v')) {
291 return false
292 }
293 if prefs.os != .openbsd && (file.ends_with('_openbsd.c.v') || file.ends_with('_openbsd.v')) {
294 return false
295 }
296 if prefs.os != .netbsd && (file.ends_with('_netbsd.c.v') || file.ends_with('_netbsd.v')) {
297 return false
298 }
299 if prefs.os != .dragonfly
300 && (file.ends_with('_dragonfly.c.v') || file.ends_with('_dragonfly.v')) {
301 return false
302 }
303 if prefs.os != .solaris && file.ends_with('_solaris.c.v') {
304 return false
305 }
306 if prefs.os != .qnx && file.ends_with('_qnx.c.v') {
307 return false
308 }
309 if prefs.os != .serenity && file.ends_with('_serenity.c.v') {
310 return false
311 }
312 if prefs.os != .plan9 && file.ends_with('_plan9.c.v') {
313 return false
314 }
315 if prefs.os != .vinix && file.ends_with('_vinix.c.v') {
316 return false
317 }
318 if prefs.os in [.android, .termux] {
319 // Note: Termux is running natively on Android devices, but the compilers there (clang) usually do not have access
320 // to the Android SDK. The code here ensures that you can have `_termux.c.v` and `_android_outside_termux.c.v` postfixes,
321 // to target both the cross compilation case (where the SDK headers are used and available), and the Termux case,
322 // where the Android SDK is not used.
323 if file.ends_with('_android.c.v') {
324 // common case, should compile for both cross android and termux
325 // eprintln('prefs.os: ${prefs.os} | file: ${file} | common')
326 return true
327 }
328 if file.ends_with('_android_outside_termux.c.v') {
329 // compile code that targets Android, but NOT Termux (i.e. the SDK is available)
330 // eprintln('prefs.os: ${prefs.os} | file: ${file} | android_outside_termux')
331 return prefs.os == .android
332 }
333 if file.ends_with('_termux.c.v') {
334 // compile Termux specific code
335 // eprintln('prefs.os: ${prefs.os} | file: ${file} | termux specific')
336 return prefs.os == .termux
337 }
338 } else if file.ends_with('_android.c.v') || file.ends_with('_termux.c.v')
339 || file.ends_with('_android_outside_termux.c.v') {
340 return false
341 }
342 if prefs.os != .wasm32_emscripten
343 && (file.ends_with('_wasm32_emscripten.c.v') || file.ends_with('_wasm32_emscripten.v')) {
344 return false
345 }
346 return true
347}
348
349pub fn (prefs &Preferences) should_compile_asm(path string) bool {
350 if path.count('.') != 2 || path.ends_with('c.v') || path.ends_with('js.v') {
351 return true
352 }
353 file := path.all_before_last('.v')
354 arch := arch_from_string(file.all_after_last('.')) or { Arch._auto }
355
356 if arch != prefs.arch && prefs.arch != ._auto && arch != ._auto {
357 return false
358 }
359 file_os := os_from_string(file.all_after_last('_').all_before('.')) or { OS._auto }
360
361 if file_os != prefs.os && prefs.os != ._auto && file_os != ._auto {
362 return false
363 }
364 return true
365}
366
367pub fn (prefs &Preferences) should_compile_js(file string) bool {
368 if !file.ends_with('.js.v') && file.split('.').len > 2 {
369 // Probably something like `a.c.v`.
370 return false
371 }
372 return true
373}
374
375pub fn (prefs &Preferences) should_compile_wasm(file string) bool {
376 if !file.ends_with('.wasm.v') && file.count('.') >= 2 {
377 // not .wasm.v not just .v something else like .c.v
378 return false
379 }
380 return true
381}
382
383// is_target_of returns true if this_os is included in the target specified
384// for example, 'nix' is true for Linux and FreeBSD but not Windows
385pub fn (this_os OS) is_target_of(target string) bool {
386 if this_os == .all {
387 return true
388 }
389 // Note: Termux is running natively on Android devices, but the compilers there (clang) usually do not have access
390 // to the Android SDK. The code here ensures that you can have `_termux.c.v` and `_android_outside_termux.c.v` postfixes,
391 // to target both the cross compilation case (where the SDK headers are used and available), and the Termux case,
392 // where the Android SDK is not used.
393 // 'nix' means "all but Windows"
394 if (this_os == .windows && target == 'nix')
395 || (this_os != .windows && target == 'windows')
396 || (this_os != .linux && target == 'linux')
397 || (this_os != .macos && target in ['darwin', 'macos', 'mac'])
398 || (!this_os.is_bsd_target() && target == 'bsd')
399 || (this_os != .ios && target == 'ios')
400 || (this_os != .freebsd && target == 'freebsd')
401 || (this_os != .openbsd && target == 'openbsd')
402 || (this_os != .netbsd && target == 'netbsd')
403 || (this_os != .dragonfly && target == 'dragonfly')
404 || (this_os != .solaris && target == 'solaris')
405 || (this_os != .qnx && target == 'qnx')
406 || (this_os != .serenity && target == 'serenity')
407 || (this_os != .plan9 && target == 'plan9')
408 || (this_os != .vinix && target == 'vinix')
409 || (this_os != .android && target in ['android', 'android_outside_termux'])
410 || (this_os != .termux && target == 'termux') {
411 return false
412 }
413 return true
414}
415
416fn (this_os OS) is_bsd_target() bool {
417 return this_os in [.macos, .freebsd, .openbsd, .netbsd, .dragonfly]
418}
419