v / vlib / v2 / builder / native_test.v
661 lines · 570 sloc · 24.52 KB · ddb021b9866c3b4523b746fa2f4c16a594f8bd89
Raw
1module builder
2
3import os
4import v2.abi
5import v2.ast
6import v2.gen.x64
7import v2.pref
8
9fn test_native_x64_windows_selects_coff_and_windows_abi() {
10 assert is_windows_x64_native_target(.x64, 'windows')
11 assert native_x64_object_format_for_os('windows') == x64.ObjectFormat.coff
12 assert native_x64_codegen_abi_for_os('windows') == x64.X64Abi.windows
13 assert native_x64_lowering_abi_for_os('windows') == abi.X64Abi.windows
14}
15
16fn test_native_x64_non_windows_keeps_existing_object_formats_and_sysv() {
17 assert !is_windows_x64_native_target(.x64, 'linux')
18 assert native_x64_object_format_for_os('linux') == x64.ObjectFormat.elf
19 assert native_x64_codegen_abi_for_os('linux') == x64.X64Abi.sysv
20 assert native_x64_lowering_abi_for_os('linux') == abi.X64Abi.sysv
21
22 assert !is_windows_x64_native_target(.x64, 'macos')
23 assert native_x64_object_format_for_os('macos') == x64.ObjectFormat.macho
24 assert native_x64_codegen_abi_for_os('macos') == x64.X64Abi.sysv
25 assert native_x64_lowering_abi_for_os('macos') == abi.X64Abi.sysv
26 assert is_macos_native_target('macos')
27 assert is_macos_native_target('darwin')
28 assert native_x64_object_format_for_os('darwin') == x64.ObjectFormat.macho
29 assert native_x64_codegen_abi_for_os('darwin') == x64.X64Abi.sysv
30 assert native_x64_lowering_abi_for_os('darwin') == abi.X64Abi.sysv
31}
32
33fn test_minimal_x64_runtime_and_macos_tiny_object_targets() {
34 old_linux_tiny := os.getenv_opt('V2_X64_LINUX_TINY')
35 os.unsetenv('V2_X64_LINUX_TINY')
36 defer {
37 if old := old_linux_tiny {
38 os.setenv('V2_X64_LINUX_TINY', old, true)
39 } else {
40 os.unsetenv('V2_X64_LINUX_TINY')
41 }
42 }
43
44 mut prefs := pref.new_preferences()
45 prefs.backend = .x64
46 prefs.arch = .x64
47
48 prefs.target_os = 'linux'
49 linux_builder := new_builder(&prefs)
50 assert !linux_builder.uses_minimal_windows_x64_runtime()
51 assert linux_builder.uses_minimal_linux_x64_runtime()
52 assert linux_builder.uses_minimal_x64_runtime()
53 assert !linux_builder.uses_minimal_linux_x64_runtime_roots()
54 assert !linux_builder.uses_minimal_x64_runtime_roots()
55
56 os.setenv('V2_X64_LINUX_TINY', '1', true)
57 linux_tiny_builder := new_builder(&prefs)
58 assert linux_tiny_builder.uses_minimal_linux_x64_runtime()
59 assert linux_tiny_builder.uses_minimal_linux_x64_runtime_roots()
60 assert linux_tiny_builder.uses_minimal_x64_runtime_roots()
61 os.unsetenv('V2_X64_LINUX_TINY')
62
63 prefs.target_os = 'macos'
64 macos_builder := new_builder(&prefs)
65 assert !macos_builder.uses_minimal_windows_x64_runtime()
66 assert !macos_builder.uses_minimal_linux_x64_runtime()
67 assert !macos_builder.uses_minimal_x64_runtime()
68 assert !macos_builder.uses_minimal_x64_runtime_roots()
69 assert macos_builder.uses_macos_x64_tiny_object(.x64)
70 assert !macos_builder.uses_macos_x64_tiny_object(.arm64)
71
72 macos_tiny_builder := new_builder(&prefs)
73 assert !macos_tiny_builder.uses_minimal_x64_runtime()
74 assert !macos_tiny_builder.uses_minimal_x64_runtime_roots()
75 assert macos_tiny_builder.uses_macos_x64_tiny_object(.x64)
76 assert !macos_tiny_builder.uses_macos_x64_tiny_object(.arm64)
77
78 prefs.macos_tiny = false
79 macos_no_tiny_builder := new_builder(&prefs)
80 assert !macos_no_tiny_builder.uses_macos_x64_tiny_object(.x64)
81
82 prefs.macos_tiny = true
83 prefs.arch = .auto
84 macos_auto_arch_builder := new_builder(&prefs)
85 assert !macos_auto_arch_builder.uses_minimal_x64_runtime_roots()
86 assert macos_auto_arch_builder.uses_macos_x64_tiny_object(.x64)
87 assert !macos_auto_arch_builder.uses_macos_x64_tiny_object(.arm64)
88 prefs.arch = .x64
89
90 prefs.target_os = 'darwin'
91 darwin_builder := new_builder(&prefs)
92 assert !darwin_builder.uses_minimal_windows_x64_runtime()
93 assert !darwin_builder.uses_minimal_linux_x64_runtime()
94 assert !darwin_builder.uses_minimal_x64_runtime()
95 assert !darwin_builder.uses_minimal_x64_runtime_roots()
96 assert darwin_builder.uses_macos_x64_tiny_object(.x64)
97
98 prefs.target_os = 'windows'
99 windows_builder := new_builder(&prefs)
100 assert windows_builder.uses_minimal_windows_x64_runtime()
101 assert !windows_builder.uses_minimal_linux_x64_runtime()
102 assert windows_builder.uses_minimal_x64_runtime()
103 assert windows_builder.uses_minimal_x64_runtime_roots()
104 assert !windows_builder.uses_macos_x64_tiny_object(.x64)
105}
106
107fn test_macos_tiny_candidate_source_snapshot_is_auto_by_default_with_opt_out() {
108 mut prefs := pref.new_preferences()
109 prefs.backend = .x64
110 prefs.arch = .auto
111 prefs.target_os = 'macos'
112
113 mut hosted_builder := new_builder(&prefs)
114 hosted_builder.files = [
115 ast.File{
116 mod: 'main'
117 name: 'main.v'
118 },
119 ]
120 hosted_builder.prepare_macos_tiny_candidate_source_files()
121 assert hosted_builder.macos_tiny_candidate_source_files.len == 1
122 assert hosted_builder.macos_tiny_candidate_source_files[0].name == 'main.v'
123
124 prefs.macos_tiny = false
125 mut opt_out_builder := new_builder(&prefs)
126 opt_out_builder.files = [
127 ast.File{
128 mod: 'main'
129 name: 'main.v'
130 },
131 ]
132 opt_out_builder.prepare_macos_tiny_candidate_source_files()
133 assert opt_out_builder.macos_tiny_candidate_source_files.len == 0
134 assert !opt_out_builder.uses_minimal_x64_runtime_roots()
135}
136
137fn test_macos_tiny_candidate_source_snapshot_uses_flat_when_enabled() {
138 mut prefs := pref.new_preferences()
139 prefs.backend = .x64
140 prefs.arch = .auto
141 prefs.target_os = 'macos'
142
143 source_files := [
144 ast.File{
145 mod: 'main'
146 name: 'flat_main.v'
147 stmts: [
148 ast.Stmt(ast.FnDecl{
149 name: 'main'
150 }),
151 ]
152 },
153 ]
154 mut tiny_builder := new_builder(&prefs)
155 tiny_builder.files = [
156 ast.File{
157 mod: 'stale'
158 name: 'stale.v'
159 },
160 ]
161 tiny_builder.flat = ast.flatten_files(source_files)
162 tiny_builder.prepare_macos_tiny_candidate_source_files()
163 assert tiny_builder.macos_tiny_candidate_source_files.len == 0
164 assert tiny_builder.macos_tiny_candidate_source_flat.files.len == source_files.len
165 assert tiny_builder.macos_tiny_candidate_source_flat.file_name(tiny_builder.macos_tiny_candidate_source_flat.files[0]) == 'flat_main.v'
166 assert tiny_builder.macos_tiny_candidate_source_flat.string_at(tiny_builder.macos_tiny_candidate_source_flat.files[0].mod_idx) == 'main'
167}
168
169fn test_macos_tiny_candidate_native_mir_build_policy_is_sequential_only_for_candidate() {
170 mut prefs := pref.new_preferences()
171 prefs.backend = .x64
172 prefs.arch = .x64
173 prefs.target_os = 'macos'
174 prefs.no_parallel = false
175 prefs.hot_fn = ''
176 builder := new_builder(&prefs)
177
178 assert !builder.native_mir_build_sequential('')
179 assert builder.native_mir_build_sequential(macos_tiny_candidate_graph_label)
180
181 prefs.no_parallel = true
182 no_parallel_builder := new_builder(&prefs)
183 assert no_parallel_builder.native_mir_build_sequential('')
184}
185
186fn test_macos_tiny_link_command_adds_hygiene_only_for_tiny_object() {
187 normal := macos_native_link_command('/tmp/out', 'main.o', '/SDK Path', 'x86_64', false, '')
188 tiny := macos_native_link_command('/tmp/out', 'main.o', '/SDK Path', 'x86_64', true, '')
189
190 assert normal == 'ld -o ${os.quoted_path('/tmp/out')} ${os.quoted_path('main.o')} -lSystem -syslibroot ${os.quoted_path('/SDK Path')} -e _main -arch x86_64 -platform_version macos 11.0.0 11.0.0'
191 assert tiny == '${normal} -dead_strip -x -S'
192 assert !normal.contains('-dead_strip')
193 assert !normal.contains(' -x')
194 assert !normal.contains(' -S')
195}
196
197fn test_macos_sdk_path_from_xcrun_output_accepts_simple_sdk_path() {
198 output := '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk\n'
199 assert macos_sdk_path_from_xcrun_output(output)! == '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk'
200}
201
202fn test_macos_sdk_path_from_xcrun_output_ignores_diagnostics_before_sdk_path() {
203 output :=
204 '2026-06-07 16:19:11.428 xcodebuild[1002:7567] Requested but did not find extension point\n' +
205 '2026-06-07 16:19:14.880 xcodebuild[1004:7681] Requested but did not find extension point\n' +
206 '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk\n'
207 assert macos_sdk_path_from_xcrun_output(output)! == '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk'
208}
209
210fn test_macos_sdk_path_from_xcrun_output_handles_empty_lines_spaces_and_crlf() {
211 output := ' \r\n\t\r\n /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk \r\n'
212 assert macos_sdk_path_from_xcrun_output(output)! == '/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk'
213}
214
215fn test_macos_sdk_path_from_xcrun_output_rejects_missing_sdk_path() {
216 path := macos_sdk_path_from_xcrun_output('xcodebuild diagnostic only\nnot a path\n') or {
217 assert err.msg().contains('could not find a clean macOS SDK path')
218 return
219 }
220 assert false, 'expected missing SDK path error, got ${path}'
221}
222
223fn test_macos_sdk_path_from_xcrun_output_preserves_spaces_inside_path() {
224 output := '/Applications/Xcode With Spaces.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk\n'
225 assert macos_sdk_path_from_xcrun_output(output)! == '/Applications/Xcode With Spaces.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk'
226}
227
228fn test_macos_sdk_path_from_xcrun_output_rejects_relative_or_non_macos_sdk_lines() {
229 output := 'relative/MacOSX12.3.sdk\n/Applications/Xcode.app/Contents/Developer/SDKs/iPhoneOS.sdk\n/Applications/Xcode.app/Contents/Developer/SDKs/NotMacOSX.sdk\n'
230 path := macos_sdk_path_from_xcrun_output(output) or {
231 assert err.msg().contains('could not find a clean macOS SDK path')
232 return
233 }
234 assert false, 'expected invalid SDK path lines to be rejected, got ${path}'
235}
236
237fn test_macos_sdk_path_from_xcrun_output_uses_last_valid_sdk_line() {
238 output := '/Applications/Old.app/Contents/Developer/SDKs/MacOSX11.0.sdk\n' +
239 '/Applications/New.app/Contents/Developer/SDKs/MacOSX12.3.sdk\n'
240 assert macos_sdk_path_from_xcrun_output(output)! == '/Applications/New.app/Contents/Developer/SDKs/MacOSX12.3.sdk'
241}
242
243fn test_validate_macos_sdk_path_for_native_link_accepts_libsystem_tbd() {
244 tmp_dir := os.join_path(os.vtmp_dir(), 'v2_macos_sdk_tbd_${os.getpid()}')
245 sdk_path := os.join_path(tmp_dir, 'MacOSX.test.sdk')
246 lib_dir := os.join_path(sdk_path, 'usr', 'lib')
247 os.mkdir_all(lib_dir) or { panic(err) }
248 defer {
249 os.rmdir_all(tmp_dir) or {}
250 }
251 os.write_file(os.join_path(lib_dir, 'libSystem.tbd'), '') or { panic(err) }
252 validate_macos_sdk_path_for_native_link(sdk_path)!
253}
254
255fn test_validate_macos_sdk_path_for_native_link_accepts_libsystem_dylib() {
256 tmp_dir := os.join_path(os.vtmp_dir(), 'v2_macos_sdk_dylib_${os.getpid()}')
257 sdk_path := os.join_path(tmp_dir, 'MacOSX.test.sdk')
258 lib_dir := os.join_path(sdk_path, 'usr', 'lib')
259 os.mkdir_all(lib_dir) or { panic(err) }
260 defer {
261 os.rmdir_all(tmp_dir) or {}
262 }
263 os.write_file(os.join_path(lib_dir, 'libSystem.dylib'), '') or { panic(err) }
264 validate_macos_sdk_path_for_native_link(sdk_path)!
265}
266
267fn test_validate_macos_sdk_path_for_native_link_rejects_sdk_without_libsystem() {
268 tmp_dir := os.join_path(os.vtmp_dir(), 'v2_macos_sdk_missing_libsystem_${os.getpid()}')
269 sdk_path := os.join_path(tmp_dir, 'MacOSX.test.sdk')
270 os.mkdir_all(os.join_path(sdk_path, 'usr', 'lib')) or { panic(err) }
271 defer {
272 os.rmdir_all(tmp_dir) or {}
273 }
274 validate_macos_sdk_path_for_native_link(sdk_path) or {
275 assert err.msg().contains('missing usr/lib/libSystem')
276 return
277 }
278 assert false, 'expected SDK without libSystem to be rejected'
279}
280
281fn test_validate_macos_sdk_path_for_native_link_rejects_missing_sdk_dir() {
282 missing_sdk := os.join_path(os.vtmp_dir(), 'v2_missing_macos_sdk_${os.getpid()}',
283 'MacOSX.test.sdk')
284 validate_macos_sdk_path_for_native_link(missing_sdk) or {
285 assert err.msg().contains('does not exist')
286 return
287 }
288 assert false, 'expected missing SDK directory to be rejected'
289}
290
291fn test_native_link_commands_append_directive_link_flags() {
292 linux := linux_native_link_command('cc', '/tmp/out', 'main.o', '-lm')
293 macos := macos_native_link_command('/tmp/out', 'main.o', '/SDK Path', 'x86_64', false, '-lm')
294
295 assert linux == 'cc ${os.quoted_path('main.o')} -o ${os.quoted_path('/tmp/out')} -no-pie -lm'
296 assert macos == 'ld -o ${os.quoted_path('/tmp/out')} ${os.quoted_path('main.o')} -lm -lSystem -syslibroot ${os.quoted_path('/SDK Path')} -e _main -arch x86_64 -platform_version macos 11.0.0 11.0.0'
297}
298
299fn test_linux_native_link_command_uses_configured_driver_and_link_flags() {
300 cmd := linux_native_link_command('custom-cc', '/tmp/out', 'main.o', '-fopenmp')
301
302 assert cmd.starts_with('custom-cc ${os.quoted_path('main.o')}'), cmd
303 assert cmd.contains('-fopenmp'), cmd
304}
305
306fn test_native_link_commands_keep_wl_for_linux_and_translate_for_macos_ld() {
307 linux := linux_native_link_command('cc', '/tmp/out', 'main.o', '-Wl,-rpath,/tmp/lib')
308 macos := macos_native_link_command('/tmp/out', 'main.o', '/SDK Path', 'x86_64', false,
309 '-Wl,-rpath,@loader_path/lib')
310
311 assert linux.contains('-Wl,-rpath,/tmp/lib'), linux
312 assert macos.contains(' -rpath @loader_path/lib '), macos
313 assert !macos.contains('-Wl,'), macos
314}
315
316fn test_native_link_commands_translate_xlinker_for_macos_ld() {
317 macos := macos_native_link_command('/tmp/out', 'main.o', '/SDK Path', 'x86_64', false,
318 '-Xlinker -rpath -Xlinker @loader_path/lib')
319
320 assert macos.contains(' -rpath @loader_path/lib '), macos
321 assert !macos.contains('-Xlinker'), macos
322}
323
324fn test_macos_native_link_command_keeps_framework_search_paths() {
325 macos := macos_native_link_command('/tmp/out', 'main.o', '/SDK Path', 'x86_64', false,
326 '-F /tmp/Fw -F/opt/Fw -framework Foo')
327
328 assert macos.contains(' -F /tmp/Fw -F/opt/Fw -framework Foo '), macos
329}
330
331fn test_split_compile_and_link_flags_duplicates_dual_use_driver_flags() {
332 compile_flags, link_flags :=
333 split_compile_and_link_flags('-I include -fopenmp -fopenmp=libomp -pthread helper.c')
334
335 assert compile_flags == '-I include -fopenmp -fopenmp=libomp -pthread'
336 assert link_flags == '-fopenmp -fopenmp=libomp -pthread helper.c'
337}
338
339fn test_split_compile_and_link_flags_keeps_framework_search_paths_dual_use() {
340 compile_flags, link_flags :=
341 split_compile_and_link_flags('-F /tmp/Fw -F/opt/Fw -framework Foo helper.m')
342
343 assert compile_flags == '-F /tmp/Fw -F/opt/Fw'
344 assert link_flags == '-F /tmp/Fw -F/opt/Fw -framework Foo helper.m'
345}
346
347fn test_macos_native_ld_rejects_dual_use_driver_link_flags() {
348 validate_macos_native_ld_link_flags('-lm')!
349 validate_macos_native_ld_link_flags('-fopenmp') or {
350 assert err.msg().contains('macOS native ld cannot consume driver linker flags'), err.msg()
351 return
352 }
353 assert false, 'expected macOS native ld driver flag diagnostic'
354}
355
356fn test_native_linux_tiny_link_allows_runtime_system_libs_when_user_flags_are_empty() {
357 assert native_link_flags_allow_builtin_linux_tiny('', '')
358 assert native_link_flags_allow_builtin_linux_tiny(' ', '')
359 assert native_link_flags_allow_builtin_linux_tiny('-lpthread -lm -ldl -lc', '')
360 assert native_link_flags_allow_builtin_linux_tiny('-l pthread -l m -l dl -l c', '')
361}
362
363fn test_native_linux_tiny_link_blocks_user_external_link_flags() {
364 for user_link_flags in ['-lm', '-Wl,-rpath,/tmp/lib', '/tmp/helper.c', '-fopenmp', '-pthread',
365 '-F/tmp/Frameworks'] {
366 assert !native_link_flags_allow_builtin_linux_tiny('-lpthread -lm -ldl', user_link_flags), user_link_flags
367 }
368}
369
370fn test_native_linux_tiny_link_blocks_external_link_inputs_in_global_flags() {
371 assert !native_link_flags_allow_builtin_linux_tiny('-Xlinker -rpath', '')
372 assert !native_link_flags_allow_builtin_linux_tiny('-L/tmp', '')
373 assert !native_link_flags_allow_builtin_linux_tiny('/tmp/helper.o', '')
374 assert !native_link_flags_allow_builtin_linux_tiny('/tmp/libhelper.a', '')
375 assert !native_link_flags_allow_builtin_linux_tiny('-framework Foundation', '')
376 assert !native_link_flags_allow_builtin_linux_tiny('-lfoo', '')
377}
378
379fn test_native_external_link_inputs_replace_sources_with_objects_in_order() {
380 inputs := native_external_link_inputs('-L/tmp/lib /tmp/foo.c -lfoo /tmp/bar.m /tmp/baz.o',
381 '/tmp/out')!
382
383 assert inputs.source_files == ['/tmp/foo.c', '/tmp/bar.m']
384 assert inputs.object_files.len == 2
385 assert inputs.link_flags == '-L/tmp/lib ${os.quoted_path(inputs.object_files[0])} -lfoo ${os.quoted_path(inputs.object_files[1])} /tmp/baz.o'
386 assert !inputs.link_flags.contains('/tmp/foo.c')
387 assert !inputs.link_flags.contains('/tmp/bar.m')
388}
389
390fn test_native_external_link_inputs_reject_unsupported_c_family_sources() {
391 for source in ['/tmp/foo.cc', '/tmp/foo.cpp', '/tmp/foo.cxx', '/tmp/foo.mm'] {
392 native_external_link_inputs(source, '/tmp/out') or {
393 assert err.msg().starts_with('x64: unsupported backend feature: '), err.msg()
394 continue
395 }
396 assert false, 'expected ${source} source to be rejected'
397 }
398}
399
400fn test_native_external_link_inputs_reject_quoted_source_tokens() {
401 native_external_link_inputs('"foo.c"', '/tmp/out') or {
402 assert err.msg().starts_with('x64: unsupported backend feature: quoted #flag source path'), err.msg()
403
404 return
405 }
406 assert false, 'expected quoted source token to be rejected'
407}
408
409fn test_macos_native_link_command_uses_rewritten_external_objects() {
410 tmp_dir := os.real_path(os.vtmp_dir())
411 foo_c := os.join_path(tmp_dir, 'foo.c')
412 bar_m := os.join_path(tmp_dir, 'bar.m')
413 out_path := os.join_path(tmp_dir, 'out')
414 inputs := native_external_link_inputs('${foo_c} -framework Foundation ${bar_m}', out_path)!
415 cmd := macos_native_link_command(out_path, 'main.o', '/SDK Path', 'x86_64', false,
416 inputs.link_flags)
417
418 assert cmd.contains(os.quoted_path(inputs.object_files[0])), cmd
419 assert cmd.contains(os.quoted_path(inputs.object_files[1])), cmd
420 assert cmd.contains('-framework Foundation'), cmd
421 assert !cmd.contains(foo_c), cmd
422 assert !cmd.contains(bar_m), cmd
423}
424
425fn test_native_external_source_compile_command_adds_macos_sdk_and_arch() {
426 cmd := native_external_source_compile_command('cc', '/tmp/foo.c', '/tmp/foo.o',
427 '-I /tmp/include -DHELPER', '/SDK Path', 'x86_64', 'macos')
428
429 assert cmd.starts_with('cc -c '), cmd
430 assert cmd.contains('-isysroot ${os.quoted_path('/SDK Path')}'), cmd
431 assert cmd.contains('-arch x86_64'), cmd
432 assert cmd.contains('-I /tmp/include -DHELPER'), cmd
433 assert cmd.contains(os.quoted_path('/tmp/foo.c')), cmd
434 assert cmd.contains('-o ${os.quoted_path('/tmp/foo.o')}'), cmd
435}
436
437fn test_native_external_source_compile_command_keeps_linux_compile_flags() {
438 cmd := native_external_source_compile_command('cc', '/tmp/foo.c', '/tmp/foo.o',
439 '-I /tmp/include -DHELPER', '', '', 'linux')
440
441 assert cmd.starts_with('cc -c '), cmd
442 assert !cmd.contains('-isysroot'), cmd
443 assert !cmd.contains('-arch'), cmd
444 assert cmd.contains('-I /tmp/include -DHELPER'), cmd
445 assert cmd.contains(os.quoted_path('/tmp/foo.c')), cmd
446 assert cmd.contains('-o ${os.quoted_path('/tmp/foo.o')}'), cmd
447}
448
449fn test_native_external_source_compiler_uses_pref_ccompiler() {
450 mut prefs := pref.new_preferences()
451 prefs.ccompiler = 'custom-native-cc'
452 mut b := new_builder(&prefs)
453
454 assert b.native_external_source_compiler('macos') == 'custom-native-cc'
455}
456
457fn test_native_external_source_compiler_uses_v2cc_when_pref_is_empty() {
458 old_v2cc := os.getenv_opt('V2CC')
459 os.setenv('V2CC', 'env-native-cc', true)
460 defer {
461 if old := old_v2cc {
462 os.setenv('V2CC', old, true)
463 } else {
464 os.unsetenv('V2CC')
465 }
466 }
467
468 mut prefs := pref.new_preferences()
469 prefs.ccompiler = ''
470 mut b := new_builder(&prefs)
471
472 assert b.native_external_source_compiler('macos') == 'env-native-cc'
473}
474
475fn test_native_external_source_compiler_defaults_to_cc_for_macos() {
476 old_v2cc := os.getenv_opt('V2CC')
477 os.unsetenv('V2CC')
478 tmp_dir := os.join_path(os.vtmp_dir(), 'v2_builder_native_external_cc_${os.getpid()}')
479 tcc_dir := os.join_path(tmp_dir, 'thirdparty', 'tcc')
480 os.mkdir_all(tcc_dir) or { panic(err) }
481 os.write_file(os.join_path(tcc_dir, 'tcc.exe'), '') or { panic(err) }
482 defer {
483 os.rmdir_all(tmp_dir) or {}
484 if old := old_v2cc {
485 os.setenv('V2CC', old, true)
486 } else {
487 os.unsetenv('V2CC')
488 }
489 }
490
491 mut prefs := pref.Preferences{
492 vroot: tmp_dir
493 }
494 mut b := new_builder(&prefs)
495
496 assert b.native_external_source_compiler('macos') == 'cc'
497 assert b.native_external_source_compiler('darwin') == 'cc'
498}
499
500fn test_native_linux_hosted_link_compiler_pref_v2cc_default_order() {
501 old_v2cc := os.getenv_opt('V2CC')
502 tmp_dir := os.join_path(os.vtmp_dir(), 'v2_builder_native_linux_hosted_cc_${os.getpid()}')
503 tcc_dir := os.join_path(tmp_dir, 'thirdparty', 'tcc')
504 os.mkdir_all(tcc_dir) or { panic(err) }
505 os.write_file(os.join_path(tcc_dir, 'tcc.exe'), '') or { panic(err) }
506 defer {
507 os.rmdir_all(tmp_dir) or {}
508 if old := old_v2cc {
509 os.setenv('V2CC', old, true)
510 } else {
511 os.unsetenv('V2CC')
512 }
513 }
514
515 os.setenv('V2CC', 'env-hosted-cc', true)
516 mut pref_prefs := pref.new_preferences()
517 pref_prefs.ccompiler = 'pref-hosted-cc'
518 pref_builder := new_builder(&pref_prefs)
519 assert pref_builder.native_linux_hosted_link_compiler() == 'pref-hosted-cc'
520
521 mut env_prefs := pref.new_preferences()
522 env_prefs.ccompiler = ''
523 env_builder := new_builder(&env_prefs)
524 assert env_builder.native_linux_hosted_link_compiler() == 'env-hosted-cc'
525
526 os.unsetenv('V2CC')
527 mut default_prefs := pref.Preferences{
528 vroot: tmp_dir
529 }
530 default_builder := new_builder(&default_prefs)
531 assert default_builder.native_linux_hosted_link_compiler() == 'cc'
532}
533
534fn test_native_link_flags_from_sources_are_not_global() {
535 tmp_dir := os.join_path(os.vtmp_dir(), 'v2_builder_native_link_flags_${os.getpid()}')
536 os.mkdir_all(tmp_dir) or { panic(err) }
537 defer {
538 os.rmdir_all(tmp_dir) or {}
539 }
540 no_flag_path := os.join_path(tmp_dir, 'no_flag.v')
541 math_flag_path := os.join_path(tmp_dir, 'math_flag.v')
542 os.write_file(no_flag_path, 'module main\n') or { panic(err) }
543 os.write_file(math_flag_path, 'module main\n#flag -lm\n') or { panic(err) }
544
545 mut prefs := pref.new_preferences()
546 prefs.backend = .x64
547 prefs.arch = .x64
548 prefs.target_os = 'linux'
549 prefs.skip_builtin = true
550
551 mut no_flag_builder := new_builder(&prefs)
552 no_flag_builder.files = [
553 ast.File{
554 name: no_flag_path
555 },
556 ]
557 assert no_flag_builder.native_link_flags_from_sources() == ''
558
559 mut math_flag_builder := new_builder(&prefs)
560 math_flag_builder.files = [
561 ast.File{
562 name: math_flag_path
563 },
564 ]
565 assert math_flag_builder.native_link_flags_from_sources() == '-lm'
566}
567
568fn test_native_user_link_flags_ignore_internal_vlib_runtime_flags() {
569 tmp_dir := os.join_path(os.vtmp_dir(), 'v2_builder_native_user_link_flags_${os.getpid()}')
570 vlib_os_dir := os.join_path(tmp_dir, 'vlib', 'os')
571 os.mkdir_all(vlib_os_dir) or { panic(err) }
572 defer {
573 os.rmdir_all(tmp_dir) or {}
574 }
575 main_path := os.join_path(tmp_dir, 'main.v')
576 internal_path := os.join_path(vlib_os_dir, 'signal_linux.c.v')
577 os.write_file(main_path, 'module main\n#flag -lm\n') or { panic(err) }
578 os.write_file(internal_path, 'module os\n#flag -lpthread\n') or { panic(err) }
579
580 mut prefs := pref.Preferences{
581 backend: .x64
582 arch: .x64
583 target_os: 'linux'
584 vroot: tmp_dir
585 skip_builtin: true
586 }
587
588 mut b := new_builder(&prefs)
589 b.user_files = [main_path]
590 b.files = [
591 ast.File{
592 name: main_path
593 },
594 ast.File{
595 name: internal_path
596 },
597 ]
598 _, all_link_flags := b.native_compile_and_link_flags_from_sources()
599 _, user_link_flags := b.native_user_compile_and_link_flags_from_sources()
600
601 assert all_link_flags.fields().sorted() == ['-lm', '-lpthread']
602 assert user_link_flags == '-lm'
603 assert !native_link_flags_allow_builtin_linux_tiny(all_link_flags, user_link_flags)
604
605 b.user_files = []
606 b.files = [
607 ast.File{
608 name: internal_path
609 },
610 ]
611 _, internal_only_link_flags := b.native_compile_and_link_flags_from_sources()
612 _, no_user_link_flags := b.native_user_compile_and_link_flags_from_sources()
613
614 assert internal_only_link_flags == '-lpthread'
615 assert no_user_link_flags == ''
616 assert native_link_flags_allow_builtin_linux_tiny(internal_only_link_flags, no_user_link_flags)
617}
618
619fn test_native_compile_and_link_flags_from_sources_keep_compile_flags_for_source_inputs() {
620 tmp_dir := os.join_path(os.vtmp_dir(), 'v2_builder_native_source_flags_${os.getpid()}')
621 include_dir := os.join_path(tmp_dir, 'include')
622 os.mkdir_all(include_dir) or { panic(err) }
623 defer {
624 os.rmdir_all(tmp_dir) or {}
625 }
626 main_path := os.join_path(tmp_dir, 'main.v')
627 c_path := os.join_path(tmp_dir, 'helper.c')
628 os.write_file(c_path, 'int helper(void) { return 7; }\n') or { panic(err) }
629 os.write_file(main_path, 'module main
630#flag -I include -DHELPER -fopenmp -pthread helper.c -Wl,-rpath,/tmp/native-lib -lm
631') or {
632 panic(err)
633 }
634
635 mut prefs := pref.new_preferences()
636 prefs.backend = .x64
637 prefs.arch = .x64
638 prefs.target_os = 'linux'
639 prefs.skip_builtin = true
640
641 mut b := new_builder(&prefs)
642 b.files = [
643 ast.File{
644 name: main_path
645 },
646 ]
647 compile_flags, link_flags := b.native_compile_and_link_flags_from_sources()
648 expected_include_dir := os.real_path(include_dir)
649 expected_c_path := os.real_path(c_path)
650
651 assert compile_flags == '-I ${expected_include_dir} -DHELPER -fopenmp -pthread'
652 assert link_flags == '-fopenmp -pthread ${expected_c_path} -Wl,-rpath,/tmp/native-lib -lm'
653}
654
655fn test_native_x64_requires_ssa_optimization() {
656 mut prefs := pref.new_preferences()
657 assert prefs.no_optimize
658 builder := new_builder(&prefs)
659 assert builder.native_backend_requires_ssa_optimization(.x64)
660 assert !builder.native_backend_requires_ssa_optimization(.arm64)
661}
662