| 1 | module pref |
| 2 | |
| 3 | import os |
| 4 | |
| 5 | pub 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 | |
| 123 | const 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 | |
| 160 | fn 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 | |
| 169 | struct BsdSpecificFiles { |
| 170 | mut: |
| 171 | has_bsd bool |
| 172 | has_exact bool |
| 173 | } |
| 174 | |
| 175 | fn (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 | |
| 220 | fn (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() |
| 248 | pub 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 | |
| 349 | pub 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 | |
| 367 | pub 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 | |
| 375 | pub 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 |
| 385 | pub 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 | |
| 416 | fn (this_os OS) is_bsd_target() bool { |
| 417 | return this_os in [.macos, .freebsd, .openbsd, .netbsd, .dragonfly] |
| 418 | } |
| 419 | |