vxx2 / vlib / v3 / tests / c_directive_order_codegen_test.v
1052 lines · 904 sloc · 35.37 KB · 472f0acc544660088248ea27cfc9c2105b4ca665
Raw
1import os
2
3const directive_order_vexe = @VEXE
4const directive_order_tests_dir = os.dir(@FILE)
5const directive_order_v3_dir = os.dir(directive_order_tests_dir)
6const directive_order_vlib_dir = os.dir(directive_order_v3_dir)
7const directive_order_v3_src = os.join_path(directive_order_v3_dir, 'v3.v')
8
9fn directive_order_build_v3() string {
10 v3_bin := os.join_path(os.temp_dir(), 'v3_c_directive_order_test')
11 build :=
12 os.execute('${directive_order_vexe} -gc none -path "${directive_order_vlib_dir}|@vlib|@vmodules" -o ${v3_bin} ${directive_order_v3_src}')
13 assert build.exit_code == 0, build.output
14 return v3_bin
15}
16
17fn directive_order_write_file(root string, rel string, src string) {
18 path := os.join_path(root, rel)
19 os.mkdir_all(os.dir(path)) or { panic(err) }
20 os.write_file(path, src) or { panic(err) }
21}
22
23fn directive_order_gen_c(v3_bin string) string {
24 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_project')
25 os.rmdir_all(root) or {}
26 os.mkdir_all(root) or { panic(err) }
27 directive_order_write_file(root, 'v.mod', "Module { name: 'directive_order' }\n")
28 directive_order_write_file(root, 'main.v', 'module main
29
30import sokol.f as _
31
32fn main() {}
33')
34 directive_order_write_file(root, 'sokol/c/c.v', 'module c
35
36#define SOKOL_GFX_IMPL
37#include "sokol_gfx.h"
38')
39 directive_order_write_file(root, 'sokol/f/f.v', 'module f
40
41import sokol.c as _
42
43#define SOKOL_FONTSTASH_IMPL
44#include "util/sokol_fontstash.h"
45#include "sokol_gfx.h"
46#ifdef KEEP_DUPLICATE_INCLUDE
47#include "sokol_gfx.h"
48#endif
49')
50 c_out := os.join_path(os.temp_dir(), 'v3_c_directive_order.c')
51 os.rm(c_out) or {}
52 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${c_out}')
53 assert result.exit_code == 0, result.output
54 return os.read_file(c_out) or { panic(err) }
55}
56
57fn directive_order_gen_c_dotted_collision(v3_bin string) string {
58 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_dotted_collision_project')
59 os.rmdir_all(root) or {}
60 os.mkdir_all(root) or { panic(err) }
61 directive_order_write_file(root, 'v.mod',
62 "Module { name: 'directive_order_dotted_collision' }\n")
63 directive_order_write_file(root, 'main.v', 'module main
64
65import foo.user as _
66import bar as _
67
68fn main() {}
69')
70 directive_order_write_file(root, 'bar/bar.v', 'module bar
71
72#define SHORT_BAR
73')
74 directive_order_write_file(root, 'foo/bar/bar.v', 'module bar
75
76#define FOO_BAR
77')
78 directive_order_write_file(root, 'foo/user/user.v', 'module user
79
80import foo.bar as _
81
82#define FOO_USER
83')
84 c_out := os.join_path(os.temp_dir(), 'v3_c_directive_order_dotted_collision.c')
85 os.rm(c_out) or {}
86 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${c_out}')
87 assert result.exit_code == 0, result.output
88 return os.read_file(c_out) or { panic(err) }
89}
90
91fn directive_order_gen_and_run_importer_macro(v3_bin string) string {
92 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_importer_macro_project')
93 os.rmdir_all(root) or {}
94 os.mkdir_all(root) or { panic(err) }
95 directive_order_write_file(root, 'v.mod', "Module { name: 'directive_order_importer_macro' }\n")
96 directive_order_write_file(root, 'main.v', 'module main
97
98#define USE_FOO
99
100import wrapper
101
102fn main() {
103 println(wrapper.value().str())
104}
105')
106 directive_order_write_file(root, 'wrapper/wrapper.v', 'module wrapper
107
108#insert "foo.h"
109
110fn C.foo_value() int
111
112pub fn value() int {
113 return C.foo_value()
114}
115')
116 directive_order_write_file(root, 'wrapper/foo.h', '#ifndef USE_FOO
117#error "USE_FOO must be defined before foo.h"
118#endif
119
120static inline int foo_value(void) {
121 return 42;
122}
123')
124 bin_out := os.join_path(os.temp_dir(), 'v3_c_directive_order_importer_macro')
125 os.rm(bin_out) or {}
126 os.rm(bin_out + '.c') or {}
127 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${bin_out}')
128 assert result.exit_code == 0, result.output
129 run := os.execute(bin_out)
130 assert run.exit_code == 0, run.output
131 assert run.output.trim_space() == '42', run.output
132 return os.read_file(bin_out + '.c') or { panic(err) }
133}
134
135fn directive_order_gen_and_run_dir_header(v3_bin string) string {
136 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_dir_header_project')
137 os.rmdir_all(root) or {}
138 os.mkdir_all(root) or { panic(err) }
139 directive_order_write_file(root, 'v.mod', "Module { name: 'directive_order_dir_header' }\n")
140 directive_order_write_file(root, 'main.v', 'module main
141
142import wrapper
143
144fn main() {
145 println(wrapper.value().str())
146}
147')
148 directive_order_write_file(root, 'wrapper/wrapper.v', 'module wrapper
149
150#insert "@DIR/dir_value.h"
151
152fn C.dir_value() int
153
154pub fn value() int {
155 return C.dir_value()
156}
157')
158 directive_order_write_file(root, 'wrapper/dir_value.h', 'static inline int dir_value(void) {
159 return 24;
160}
161')
162 bin_out := os.join_path(os.temp_dir(), 'v3_c_directive_order_dir_header')
163 os.rm(bin_out) or {}
164 os.rm(bin_out + '.c') or {}
165 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${bin_out}')
166 assert result.exit_code == 0, result.output
167 run := os.execute(bin_out)
168 assert run.exit_code == 0, run.output
169 assert run.output.trim_space() == '24', run.output
170 return os.read_file(bin_out + '.c') or { panic(err) }
171}
172
173fn directive_order_gen_and_run_flag_include_dir_header(v3_bin string) string {
174 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_flag_include_dir_project')
175 os.rmdir_all(root) or {}
176 os.mkdir_all(root) or { panic(err) }
177 directive_order_write_file(root, 'v.mod',
178 "Module { name: 'directive_order_flag_include_dir' }\n")
179 directive_order_write_file(root, 'main.v', 'module main
180
181#flag -I @DIR/include
182#insert "flag_value.c"
183
184fn C.flag_value() int
185
186fn main() {
187 println(C.flag_value().str())
188}
189')
190 directive_order_write_file(root, 'include/flag_value.c', '#include <flag_value.h>
191
192static inline int flag_value(void) {
193 return flag_value_inner();
194}
195')
196 directive_order_write_file(root, 'include/flag_value.h', 'static inline int flag_value_inner(void) {
197 return 52;
198}
199')
200 bin_out := os.join_path(os.temp_dir(), 'v3_c_directive_order_flag_include_dir')
201 os.rm(bin_out) or {}
202 os.rm(bin_out + '.c') or {}
203 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${bin_out}')
204 assert result.exit_code == 0, result.output
205 run := os.execute(bin_out)
206 assert run.exit_code == 0, run.output
207 assert run.output.trim_space() == '52', run.output
208 return os.read_file(bin_out + '.c') or { panic(err) }
209}
210
211fn directive_order_gen_and_run_late_flag_include_dir_header(v3_bin string) string {
212 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_late_flag_include_dir_project')
213 os.rmdir_all(root) or {}
214 os.mkdir_all(root) or { panic(err) }
215 directive_order_write_file(root, 'v.mod',
216 "Module { name: 'directive_order_late_flag_include_dir' }\n")
217 directive_order_write_file(root, 'main.v', 'module main
218
219#insert "late_flag_value.c"
220#flag -I @DIR/include
221
222fn C.late_flag_value() int
223
224fn main() {
225 println(C.late_flag_value().str())
226}
227')
228 directive_order_write_file(root, 'include/late_flag_value.c', '#include <late_flag_value.h>
229
230static inline int late_flag_value(void) {
231 return late_flag_value_inner();
232}
233')
234 directive_order_write_file(root, 'include/late_flag_value.h', 'static inline int late_flag_value_inner(void) {
235 return 63;
236}
237')
238 bin_out := os.join_path(os.temp_dir(), 'v3_c_directive_order_late_flag_include_dir')
239 os.rm(bin_out) or {}
240 os.rm(bin_out + '.c') or {}
241 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${bin_out}')
242 assert result.exit_code == 0, result.output
243 run := os.execute(bin_out)
244 assert run.exit_code == 0, run.output
245 assert run.output.trim_space() == '63', run.output
246 return os.read_file(bin_out + '.c') or { panic(err) }
247}
248
249fn directive_order_gen_and_run_multiline_static_inline(v3_bin string) string {
250 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_multiline_static_inline_project')
251 os.rmdir_all(root) or {}
252 os.mkdir_all(root) or { panic(err) }
253 directive_order_write_file(root, 'v.mod',
254 "Module { name: 'directive_order_multiline_static_inline' }\n")
255 directive_order_write_file(root, 'main.v', 'module main
256
257#insert "multiline_value.h"
258
259fn C.multiline_value() int
260
261fn main() {
262 println(C.multiline_value().str())
263}
264')
265 directive_order_write_file(root, 'multiline_value.h', 'static inline
266int multiline_value(void) {
267 return 33;
268}
269')
270 bin_out := os.join_path(os.temp_dir(), 'v3_c_directive_order_multiline_static_inline')
271 os.rm(bin_out) or {}
272 os.rm(bin_out + '.c') or {}
273 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${bin_out}')
274 assert result.exit_code == 0, result.output
275 run := os.execute(bin_out)
276 assert run.exit_code == 0, run.output
277 assert run.output.trim_space() == '33', run.output
278 return os.read_file(bin_out + '.c') or { panic(err) }
279}
280
281fn directive_order_gen_c_extern_after_header(v3_bin string) string {
282 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_extern_after_header_project')
283 os.rmdir_all(root) or {}
284 os.mkdir_all(root) or { panic(err) }
285 directive_order_write_file(root, 'v.mod',
286 "Module { name: 'directive_order_extern_after_header' }\n")
287 directive_order_write_file(root, 'main.v', 'module main
288
289#insert "native_thing.h"
290
291@[typedef]
292struct C.NativeThing {
293 value int
294}
295
296fn C.native_use(item &C.NativeThing) int
297
298fn main() {
299 mut item := C.NativeThing{
300 value: 7
301 }
302 _ := C.native_use(&item)
303}
304')
305 directive_order_write_file(root, 'native_thing.h', 'typedef struct NativeThing {
306 int value;
307} NativeThing;
308')
309 c_out := os.join_path(os.temp_dir(), 'v3_c_directive_order_extern_after_header.c')
310 os.rm(c_out) or {}
311 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${c_out}')
312 assert result.exit_code == 0, result.output
313 return os.read_file(c_out) or { panic(err) }
314}
315
316fn directive_order_gen_c_header_declared_prototype(v3_bin string) string {
317 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_header_declared_proto_project')
318 os.rmdir_all(root) or {}
319 os.mkdir_all(root) or { panic(err) }
320 directive_order_write_file(root, 'v.mod',
321 "Module { name: 'directive_order_header_declared_proto' }\n")
322 directive_order_write_file(root, 'main.v', 'module main
323
324#insert "declared_proto.h"
325
326fn C.declared_text() &char
327
328fn main() {
329 _ := C.declared_text()
330}
331')
332 directive_order_write_file(root, 'declared_proto.h', 'const char* declared_text(void);
333')
334 c_out := os.join_path(os.temp_dir(), 'v3_c_directive_order_header_declared_proto.c')
335 os.rm(c_out) or {}
336 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${c_out}')
337 assert result.exit_code == 0, result.output
338 return os.read_file(c_out) or { panic(err) }
339}
340
341fn directive_order_gen_c_struct_field_after_header(v3_bin string) string {
342 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_struct_field_after_header_project')
343 os.rmdir_all(root) or {}
344 os.mkdir_all(root) or { panic(err) }
345 directive_order_write_file(root, 'v.mod',
346 "Module { name: 'directive_order_struct_field_after_header' }\n")
347 directive_order_write_file(root, 'main.v', 'module main
348
349#insert "field_thing.h"
350
351@[typedef]
352struct C.FieldThing {
353 value int
354}
355
356struct Wrap {
357 item C.FieldThing
358}
359
360fn main() {
361 _ := Wrap{}
362}
363')
364 directive_order_write_file(root, 'field_thing.h', 'typedef struct {
365 int value;
366} FieldThing;
367')
368 c_out := os.join_path(os.temp_dir(), 'v3_c_directive_order_struct_field_after_header.c')
369 os.rm(c_out) or {}
370 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${c_out}')
371 assert result.exit_code == 0, result.output
372 return os.read_file(c_out) or { panic(err) }
373}
374
375fn directive_order_gen_and_run_anonymous_typedef(v3_bin string) string {
376 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_anonymous_typedef_project')
377 os.rmdir_all(root) or {}
378 os.mkdir_all(root) or { panic(err) }
379 directive_order_write_file(root, 'v.mod',
380 "Module { name: 'directive_order_anonymous_typedef' }\n")
381 directive_order_write_file(root, 'main.v', 'module main
382
383#insert "anonymous_thing.h"
384
385@[typedef]
386struct C.AnonymousThing {
387 value int
388}
389
390fn C.anonymous_value(item &C.AnonymousThing) int
391
392fn main() {
393 mut item := C.AnonymousThing{
394 value: 31
395 }
396 println(C.anonymous_value(&item).str())
397}
398')
399 directive_order_write_file(root, 'anonymous_thing.h', 'typedef struct {
400 int value;
401} AnonymousThing;
402
403static inline int anonymous_value(AnonymousThing* item) {
404 return item->value;
405}
406')
407 bin_out := os.join_path(os.temp_dir(), 'v3_c_directive_order_anonymous_typedef')
408 os.rm(bin_out) or {}
409 os.rm(bin_out + '.c') or {}
410 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${bin_out}')
411 assert result.exit_code == 0, result.output
412 run := os.execute(bin_out)
413 assert run.exit_code == 0, run.output
414 assert run.output.trim_space() == '31', run.output
415 return os.read_file(bin_out + '.c') or { panic(err) }
416}
417
418fn directive_order_gen_and_run_tagged_typedef_alias(v3_bin string) string {
419 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_tagged_typedef_alias_project')
420 os.rmdir_all(root) or {}
421 os.mkdir_all(root) or { panic(err) }
422 directive_order_write_file(root, 'v.mod',
423 "Module { name: 'directive_order_tagged_typedef_alias' }\n")
424 directive_order_write_file(root, 'main.v', 'module main
425
426#insert "tagged_thing.h"
427
428@[typedef]
429struct C.TaggedAlias {
430 value int
431}
432
433fn C.tagged_value(item &C.TaggedAlias) int
434
435fn main() {
436 mut item := C.TaggedAlias{
437 value: 43
438 }
439 println(C.tagged_value(&item).str())
440}
441')
442 directive_order_write_file(root, 'tagged_thing.h', 'typedef struct TaggedImpl {
443 int value;
444} TaggedAlias;
445
446static inline int tagged_value(TaggedAlias* item) {
447 return item->value;
448}
449')
450 bin_out := os.join_path(os.temp_dir(), 'v3_c_directive_order_tagged_typedef_alias')
451 os.rm(bin_out) or {}
452 os.rm(bin_out + '.c') or {}
453 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${bin_out}')
454 assert result.exit_code == 0, result.output
455 run := os.execute(bin_out)
456 assert run.exit_code == 0, run.output
457 assert run.output.trim_space() == '43', run.output
458 return os.read_file(bin_out + '.c') or { panic(err) }
459}
460
461fn directive_order_gen_c_union_typedef_aliases(v3_bin string) string {
462 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_union_typedef_aliases_project')
463 os.rmdir_all(root) or {}
464 os.mkdir_all(root) or { panic(err) }
465 directive_order_write_file(root, 'v.mod',
466 "Module { name: 'directive_order_union_typedef_aliases' }\n")
467 directive_order_write_file(root, 'main.v', 'module main
468
469#insert "union_thing.h"
470
471@[typedef]
472union C.AnonymousUnion {
473 value int
474}
475
476@[typedef]
477union C.TaggedUnionAlias {
478 value int
479}
480
481struct WrapUnion {
482 anonymous C.AnonymousUnion
483 tagged C.TaggedUnionAlias
484}
485
486fn main() {
487 _ := WrapUnion{}
488}
489')
490 directive_order_write_file(root, 'union_thing.h', 'typedef union {
491 int value;
492} AnonymousUnion;
493
494typedef union TaggedUnionImpl {
495 int value;
496} TaggedUnionAlias;
497')
498 c_out := os.join_path(os.temp_dir(), 'v3_c_directive_order_union_typedef_aliases.c')
499 os.rm(c_out) or {}
500 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${c_out}')
501 assert result.exit_code == 0, result.output
502 return os.read_file(c_out) or { panic(err) }
503}
504
505fn directive_order_gen_and_run_nested_include(v3_bin string) string {
506 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_nested_include_project')
507 os.rmdir_all(root) or {}
508 os.mkdir_all(root) or { panic(err) }
509 directive_order_write_file(root, 'v.mod', "Module { name: 'directive_order_nested_include' }\n")
510 directive_order_write_file(root, 'main.v', 'module main
511
512#insert "outer.h"
513
514@[typedef]
515struct C.NestedThing {
516 value int
517}
518
519fn C.nested_value(item &C.NestedThing) int
520
521fn main() {
522 mut item := C.NestedThing{
523 value: 11
524 }
525 println(C.nested_value(&item).str())
526}
527')
528 directive_order_write_file(root, 'outer.h', '#include "types.h"
529
530static inline int nested_value(NestedThing* item) {
531 return NESTED_BIAS + item->value;
532}
533')
534 directive_order_write_file(root, 'types.h', '#include <stdint.h>
535
536#define NESTED_BIAS 5
537
538typedef struct {
539 uint32_t value;
540} NestedThing;
541')
542 bin_out := os.join_path(os.temp_dir(), 'v3_c_directive_order_nested_include')
543 os.rm(bin_out) or {}
544 os.rm(bin_out + '.c') or {}
545 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${bin_out}')
546 assert result.exit_code == 0, result.output
547 run := os.execute(bin_out)
548 assert run.exit_code == 0, run.output
549 assert run.output.trim_space() == '16', run.output
550 return os.read_file(bin_out + '.c') or { panic(err) }
551}
552
553fn directive_order_gen_c_unresolved_system_include(v3_bin string) string {
554 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_unresolved_system_include_project')
555 os.rmdir_all(root) or {}
556 os.mkdir_all(root) or { panic(err) }
557 directive_order_write_file(root, 'v.mod',
558 "Module { name: 'directive_order_unresolved_system_include' }\n")
559 directive_order_write_file(root, 'main.v', 'module main
560
561#include <platform_user_header.h>
562#define USE_DLFCN
563#define PLATFORM_API_COMPAT 7
564#ifdef USE_DLFCN
565#include <dlfcn.h>
566#endif
567#include <stdint.h>
568
569fn C.dlopen(filename &char, flags i32) voidptr
570
571fn main() {
572 nil_cstr := &char(unsafe { nil })
573 _ = C.dlopen(nil_cstr, 0)
574}
575')
576 c_out := os.join_path(os.temp_dir(), 'v3_c_directive_order_unresolved_system_include.c')
577 os.rm(c_out) or {}
578 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${c_out}')
579 assert result.exit_code == 0, result.output
580 return os.read_file(c_out) or { panic(err) }
581}
582
583fn directive_order_gen_c_nested_preserved_system_include(v3_bin string) string {
584 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_nested_preserved_include_project')
585 os.rmdir_all(root) or {}
586 os.mkdir_all(root) or { panic(err) }
587 directive_order_write_file(root, 'v.mod',
588 "Module { name: 'directive_order_nested_preserved_include' }\n")
589 directive_order_write_file(root, 'main.v', 'module main
590
591#insert "nested_preserved.h"
592
593fn main() {}
594')
595 directive_order_write_file(root, 'nested_preserved.h', '#if defined(__linux__)
596#define NESTED_PLATFORM_HEADER 1
597#include <nested_platform_header.h>
598#endif
599
600#include <stdint.h>
601
602typedef uint64_t NestedWord;
603')
604 c_out := os.join_path(os.temp_dir(), 'v3_c_directive_order_nested_preserved_include.c')
605 os.rm(c_out) or {}
606 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${c_out}')
607 assert result.exit_code == 0, result.output
608 return os.read_file(c_out) or { panic(err) }
609}
610
611fn directive_order_gen_c_preserved_x11_aggregates(v3_bin string) string {
612 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_x11_aggregates_project')
613 os.rmdir_all(root) or {}
614 os.mkdir_all(root) or { panic(err) }
615 directive_order_write_file(root, 'v.mod', "Module { name: 'directive_order_x11_aggregates' }\n")
616 directive_order_write_file(root, 'main.v', 'module main
617
618#include <X11/Xlib.h>
619
620@[typedef]
621union C.XClientMessageData {
622mut:
623 l [5]i64
624}
625
626@[typedef]
627union C.XEvent {
628mut:
629 @type int
630 xclient C.XClientMessageData
631}
632
633struct Wrap {
634 event C.XEvent
635}
636
637fn main() {
638 _ := Wrap{}
639}
640')
641 c_out := os.join_path(os.temp_dir(), 'v3_c_directive_order_x11_aggregates.c')
642 os.rm(c_out) or {}
643 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${c_out}')
644 assert result.exit_code == 0, result.output
645 return os.read_file(c_out) or { panic(err) }
646}
647
648fn directive_order_gen_c_preserved_bcrypt_fn(v3_bin string) string {
649 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_bcrypt_project')
650 os.rmdir_all(root) or {}
651 os.mkdir_all(root) or { panic(err) }
652 directive_order_write_file(root, 'v.mod', "Module { name: 'directive_order_bcrypt' }\n")
653 directive_order_write_file(root, 'main.v', 'module main
654
655#include <bcrypt.h>
656
657fn C.BCryptGenRandom(alg int, buffer voidptr, len int, flags int) int
658
659fn main() {
660 _ := C.BCryptGenRandom(0, voidptr(0), 0, 0)
661}
662')
663 c_out := os.join_path(os.temp_dir(), 'v3_c_directive_order_bcrypt.c')
664 os.rm(c_out) or {}
665 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${c_out}')
666 assert result.exit_code == 0, result.output
667 return os.read_file(c_out) or { panic(err) }
668}
669
670fn directive_order_gen_c_preserved_mach_headers(v3_bin string) string {
671 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_mach_project')
672 os.rmdir_all(root) or {}
673 os.mkdir_all(root) or { panic(err) }
674 directive_order_write_file(root, 'v.mod', "Module { name: 'directive_order_mach' }\n")
675 directive_order_write_file(root, 'main.v', 'module main
676
677#include <mach/mach.h>
678#include <mach/mach_time.h>
679
680@[typedef]
681struct C.mach_timebase_info_data_t {
682 numer u32
683 denom u32
684}
685
686fn C.mach_timebase_info(&C.mach_timebase_info_data_t)
687
688fn main() {
689 mut tb := C.mach_timebase_info_data_t{}
690 C.mach_timebase_info(&tb)
691}
692')
693 c_out := os.join_path(os.temp_dir(), 'v3_c_directive_order_mach.c')
694 os.rm(c_out) or {}
695 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${c_out}')
696 assert result.exit_code == 0, result.output
697 return os.read_file(c_out) or { panic(err) }
698}
699
700fn directive_order_gen_and_run_stdarg_header(v3_bin string) string {
701 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_stdarg_project')
702 os.rmdir_all(root) or {}
703 os.mkdir_all(root) or { panic(err) }
704 directive_order_write_file(root, 'v.mod', "Module { name: 'directive_order_stdarg' }\n")
705 directive_order_write_file(root, 'main.v', 'module main
706
707#include "stdarg_user.h"
708
709fn C.stdarg_sum(count int, ...int) int
710
711fn main() {
712 println(C.stdarg_sum(3, 1, 2, 3).str())
713}
714')
715 directive_order_write_file(root, 'stdarg_user.h', '#include <stdarg.h>
716#include <stddef.h>
717
718struct StdargThing {
719 char tag;
720 int value;
721};
722
723static inline int stdarg_sum(int count, ...) {
724 va_list ap;
725 va_start(ap, count);
726 int total = (int)offsetof(struct StdargThing, value);
727 total -= (int)offsetof(struct StdargThing, value);
728 for (int i = 0; i < count; i++) {
729 total += va_arg(ap, int);
730 }
731 va_end(ap);
732 return total;
733}
734')
735 bin_out := os.join_path(os.temp_dir(), 'v3_c_directive_order_stdarg')
736 os.rm(bin_out) or {}
737 os.rm(bin_out + '.c') or {}
738 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${bin_out}')
739 assert result.exit_code == 0, result.output
740 run := os.execute(bin_out)
741 assert run.exit_code == 0, run.output
742 assert run.output.trim_space() == '6', run.output
743 return os.read_file(bin_out + '.c') or { panic(err) }
744}
745
746fn directive_order_gen_c_rwmutex(v3_bin string) string {
747 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_rwmutex_project')
748 os.rmdir_all(root) or {}
749 os.mkdir_all(root) or { panic(err) }
750 directive_order_write_file(root, 'v.mod', "Module { name: 'directive_order_rwmutex' }\n")
751 directive_order_write_file(root, 'main.v', 'module main
752
753import sync
754
755fn main() {
756 mut m := sync.new_rwmutex()
757 m.lock()
758 m.unlock()
759}
760')
761 c_out := os.join_path(os.temp_dir(), 'v3_c_directive_order_rwmutex.c')
762 os.rm(c_out) or {}
763 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${c_out}')
764 assert result.exit_code == 0, result.output
765 return os.read_file(c_out) or { panic(err) }
766}
767
768fn directive_order_gen_c_request_extern(v3_bin string) string {
769 root := os.join_path(os.temp_dir(), 'v3_c_directive_order_request_extern_project')
770 os.rmdir_all(root) or {}
771 os.mkdir_all(root) or { panic(err) }
772 directive_order_write_file(root, 'v.mod', "Module { name: 'directive_order_request_extern' }\n")
773 directive_order_write_file(root, 'main.v', 'module main
774
775fn C.request(code int) int
776
777fn main() {
778 _ := C.request(7)
779}
780')
781 c_out := os.join_path(os.temp_dir(), 'v3_c_directive_order_request_extern.c')
782 os.rm(c_out) or {}
783 result := os.execute('${v3_bin} ${os.join_path(root, 'main.v')} -b c -o ${c_out}')
784 assert result.exit_code == 0, result.output
785 return os.read_file(c_out) or { panic(err) }
786}
787
788fn directive_order_index(c_code string, needle string) int {
789 return c_code.index(needle) or { -1 }
790}
791
792fn directive_order_count(c_code string, needle string) int {
793 mut count := 0
794 mut rest := c_code
795 for {
796 idx := rest.index(needle) or { break }
797 count++
798 rest = rest[idx + needle.len..]
799 }
800 return count
801}
802
803fn directive_order_has_include_directive(c_code string) bool {
804 for line in c_code.split_into_lines() {
805 if line.trim_space().starts_with('#include') {
806 return true
807 }
808 }
809 return false
810}
811
812fn test_c_directives_follow_import_dependency_order() {
813 c_code := directive_order_gen_c(directive_order_build_v3())
814 gfx_define := directive_order_index(c_code, '#define SOKOL_GFX_IMPL')
815 fontstash_define := directive_order_index(c_code, '#define SOKOL_FONTSTASH_IMPL')
816 block_start := directive_order_index(c_code, '#ifdef KEEP_DUPLICATE_INCLUDE')
817 assert gfx_define >= 0, c_code
818 assert fontstash_define >= 0, c_code
819 assert block_start >= 0, c_code
820 assert gfx_define < fontstash_define, c_code
821 assert !directive_order_has_include_directive(c_code), c_code
822 block_tail := c_code[block_start..]
823 block_end := directive_order_index(block_tail, '#endif')
824 assert block_end >= 0, c_code
825}
826
827fn test_c_directives_preserve_dotted_import_module_identity() {
828 c_code := directive_order_gen_c_dotted_collision(directive_order_build_v3())
829 short_bar := directive_order_index(c_code, '#define SHORT_BAR')
830 foo_bar := directive_order_index(c_code, '#define FOO_BAR')
831 foo_user := directive_order_index(c_code, '#define FOO_USER')
832 assert short_bar >= 0, c_code
833 assert foo_bar >= 0, c_code
834 assert foo_user >= 0, c_code
835 assert foo_bar < foo_user, c_code
836}
837
838fn test_importer_macro_is_emitted_before_dependency_include() {
839 c_code := directive_order_gen_and_run_importer_macro(directive_order_build_v3())
840 use_foo := directive_order_index(c_code, '#define USE_FOO')
841 foo_header := directive_order_index(c_code, 'static inline int foo_value')
842 assert use_foo >= 0, c_code
843 assert foo_header >= 0, c_code
844 assert use_foo < foo_header, c_code
845 assert !c_code.contains('int foo_value(void);'), c_code
846 assert !directive_order_has_include_directive(c_code), c_code
847}
848
849fn test_dir_include_is_expanded_before_header_probe() {
850 c_code := directive_order_gen_and_run_dir_header(directive_order_build_v3())
851 dir_header := directive_order_index(c_code, 'static inline int dir_value')
852 assert dir_header >= 0, c_code
853 assert !c_code.contains('int dir_value(void);'), c_code
854 assert !directive_order_has_include_directive(c_code), c_code
855}
856
857fn test_quoted_include_uses_flag_include_dirs() {
858 c_code := directive_order_gen_and_run_flag_include_dir_header(directive_order_build_v3())
859 flag_header := directive_order_index(c_code, 'static inline int flag_value')
860 assert flag_header >= 0, c_code
861 assert directive_order_index(c_code, 'static inline int flag_value_inner') >= 0, c_code
862 assert !c_code.contains('int flag_value(void);'), c_code
863 assert !directive_order_has_include_directive(c_code), c_code
864}
865
866fn test_quoted_include_uses_later_flag_include_dirs() {
867 c_code := directive_order_gen_and_run_late_flag_include_dir_header(directive_order_build_v3())
868 flag_header := directive_order_index(c_code, 'static inline int late_flag_value')
869 assert flag_header >= 0, c_code
870 assert directive_order_index(c_code, 'static inline int late_flag_value_inner') >= 0, c_code
871
872 assert !c_code.contains('int late_flag_value(void);'), c_code
873 assert !directive_order_has_include_directive(c_code), c_code
874}
875
876fn test_multiline_static_inline_header_is_not_redeclared() {
877 c_code := directive_order_gen_and_run_multiline_static_inline(directive_order_build_v3())
878 header_idx := directive_order_index(c_code, 'static inline\nint multiline_value')
879 assert header_idx >= 0, c_code
880 assert !c_code.contains('int multiline_value(void);'), c_code
881 assert !directive_order_has_include_directive(c_code), c_code
882}
883
884fn test_inlined_headers_are_emitted_before_extern_prototypes() {
885 c_code := directive_order_gen_c_extern_after_header(directive_order_build_v3())
886 header_idx := directive_order_index(c_code, 'typedef struct NativeThing')
887 proto_idx := directive_order_index(c_code, 'int native_use(NativeThing*')
888 assert header_idx >= 0, c_code
889 assert proto_idx >= 0, c_code
890 assert header_idx < proto_idx, c_code
891 assert !directive_order_has_include_directive(c_code), c_code
892}
893
894fn test_header_declared_prototypes_are_not_redeclared() {
895 c_code := directive_order_gen_c_header_declared_prototype(directive_order_build_v3())
896 header_idx := directive_order_index(c_code, 'const char* declared_text(void);')
897 assert header_idx >= 0, c_code
898 assert directive_order_count(c_code, 'declared_text(void);') == 1, c_code
899 assert !directive_order_has_include_directive(c_code), c_code
900}
901
902fn test_inlined_headers_are_emitted_before_type_declarations() {
903 c_code := directive_order_gen_c_struct_field_after_header(directive_order_build_v3())
904 header_idx := directive_order_index(c_code, '} FieldThing;')
905 wrap_idx := directive_order_index(c_code, 'struct Wrap {')
906 assert header_idx >= 0, c_code
907 assert wrap_idx >= 0, c_code
908 assert header_idx < wrap_idx, c_code
909 assert !c_code.contains('typedef struct FieldThing'), c_code
910 assert !directive_order_has_include_directive(c_code), c_code
911}
912
913fn test_anonymous_typedef_struct_header_is_not_duplicated() {
914 c_code := directive_order_gen_and_run_anonymous_typedef(directive_order_build_v3())
915 assert c_code.contains('} AnonymousThing;'), c_code
916 assert c_code.contains('static inline int anonymous_value'), c_code
917 assert !c_code.contains('typedef struct AnonymousThing'), c_code
918 assert !directive_order_has_include_directive(c_code), c_code
919}
920
921fn test_tagged_typedef_struct_alias_header_is_not_duplicated() {
922 c_code := directive_order_gen_and_run_tagged_typedef_alias(directive_order_build_v3())
923 assert c_code.contains('} TaggedAlias;'), c_code
924 assert c_code.contains('static inline int tagged_value'), c_code
925 assert !c_code.contains('typedef struct TaggedAlias'), c_code
926 assert !directive_order_has_include_directive(c_code), c_code
927}
928
929fn test_inlined_typedef_union_headers_are_not_duplicated() {
930 c_code := directive_order_gen_c_union_typedef_aliases(directive_order_build_v3())
931 assert c_code.contains('} AnonymousUnion;'), c_code
932 assert c_code.contains('} TaggedUnionAlias;'), c_code
933 assert !c_code.contains('typedef union AnonymousUnion'), c_code
934 assert !c_code.contains('union AnonymousUnion {\n'), c_code
935 assert !c_code.contains('typedef union TaggedUnionAlias'), c_code
936 assert !c_code.contains('union TaggedUnionAlias {\n'), c_code
937 assert !directive_order_has_include_directive(c_code), c_code
938}
939
940fn test_nested_local_header_includes_are_inlined_recursively() {
941 c_code := directive_order_gen_and_run_nested_include(directive_order_build_v3())
942 bias_idx := directive_order_index(c_code, '#define NESTED_BIAS 5')
943 stdint_idx := directive_order_index(c_code, 'typedef unsigned int uint32_t;')
944 typedef_idx := directive_order_index(c_code, '} NestedThing;')
945 outer_fn_idx := directive_order_index(c_code, 'static inline int nested_value')
946 assert bias_idx >= 0, c_code
947 assert stdint_idx >= 0, c_code
948 assert typedef_idx >= 0, c_code
949 assert outer_fn_idx >= 0, c_code
950 assert stdint_idx < typedef_idx, c_code
951 assert bias_idx < outer_fn_idx, c_code
952 assert typedef_idx < outer_fn_idx, c_code
953 assert !c_code.contains('typedef struct NestedThing'), c_code
954 assert !directive_order_has_include_directive(c_code), c_code
955}
956
957fn test_unresolved_system_include_is_preserved() {
958 c_code := directive_order_gen_c_unresolved_system_include(directive_order_build_v3())
959 assert c_code.contains('#include <platform_user_header.h>'), c_code
960 assert c_code.contains('#include <dlfcn.h>'), c_code
961 assert !c_code.contains('#include <stdint.h>'), c_code
962 assert c_code.contains('typedef unsigned int uint32_t;'), c_code
963 assert !c_code.contains('void* dlopen(char* filename, int flags);'), c_code
964 api_compat_idx := directive_order_index(c_code, '#define PLATFORM_API_COMPAT 7')
965 guard_idx := directive_order_index(c_code, '#ifdef USE_DLFCN')
966 dlfcn_idx := directive_order_index(c_code, '#include <dlfcn.h>')
967 time_t_idx := directive_order_index(c_code, 'typedef long long time_t;')
968 off_t_idx := directive_order_index(c_code, 'typedef long long off_t;')
969 wchar_idx := directive_order_index(c_code, 'typedef unsigned int wchar_t;')
970 fd_set_idx := directive_order_index(c_code, '#ifndef FD_SET')
971 assert api_compat_idx >= 0, c_code
972 assert guard_idx >= 0, c_code
973 assert dlfcn_idx >= 0, c_code
974 assert time_t_idx >= 0, c_code
975 assert off_t_idx >= 0, c_code
976 assert wchar_idx >= 0, c_code
977 assert fd_set_idx >= 0, c_code
978 assert c_code.contains('#if !defined(_TIME_T) && !defined(_TIME_T_DEFINED) && !defined(__time_t_defined)'), c_code
979 assert c_code.contains('#if !defined(_OFF_T) && !defined(_OFF_T_DEFINED) && !defined(__off_t_defined)'), c_code
980 assert api_compat_idx < dlfcn_idx, c_code
981 assert guard_idx < dlfcn_idx, c_code
982 assert dlfcn_idx < time_t_idx, c_code
983 assert dlfcn_idx < off_t_idx, c_code
984 assert dlfcn_idx < wchar_idx, c_code
985 assert dlfcn_idx < fd_set_idx, c_code
986}
987
988fn test_nested_preserved_system_include_is_lifted_before_preamble() {
989 c_code := directive_order_gen_c_nested_preserved_system_include(directive_order_build_v3())
990 include_idx := directive_order_index(c_code, '#include <nested_platform_header.h>')
991 preamble_idx := directive_order_index(c_code, 'typedef signed char i8;')
992 stdint_guard_idx := directive_order_index(c_code,
993 '#if !defined(__V_HEADERLESS_STDINT_H) && !defined(_STDINT_H)')
994 nested_word_idx := directive_order_index(c_code, 'typedef uint64_t NestedWord;')
995 assert include_idx >= 0, c_code
996 assert preamble_idx >= 0, c_code
997 assert stdint_guard_idx >= 0, c_code
998 assert nested_word_idx >= 0, c_code
999 assert include_idx < preamble_idx, c_code
1000 assert preamble_idx < stdint_guard_idx, c_code
1001 assert stdint_guard_idx < nested_word_idx, c_code
1002 assert c_code.contains('#if defined(__linux__)\n#define NESTED_PLATFORM_HEADER 1\n#include <nested_platform_header.h>\n#endif'), c_code
1003}
1004
1005fn test_preserved_system_header_aggregates_are_not_redeclared() {
1006 c_code := directive_order_gen_c_preserved_x11_aggregates(directive_order_build_v3())
1007 assert c_code.contains('#include <X11/Xlib.h>'), c_code
1008 assert !c_code.contains('typedef union XEvent XEvent;'), c_code
1009 assert !c_code.contains('union XEvent {\n'), c_code
1010 assert !c_code.contains('typedef union XClientMessageData XClientMessageData;'), c_code
1011 assert !c_code.contains('union XClientMessageData {\n'), c_code
1012}
1013
1014fn test_preserved_system_header_functions_are_not_redeclared() {
1015 c_code := directive_order_gen_c_preserved_bcrypt_fn(directive_order_build_v3())
1016 assert c_code.contains('#include <bcrypt.h>'), c_code
1017 assert directive_order_count(c_code, 'BCryptGenRandom(') == 1, c_code
1018}
1019
1020fn test_preserved_mach_headers_are_wrapped_with_panic_alias() {
1021 c_code := directive_order_gen_c_preserved_mach_headers(directive_order_build_v3())
1022 preamble_idx := directive_order_index(c_code, 'typedef signed char i8;')
1023 assert preamble_idx >= 0, c_code
1024 assert c_code.contains('#define panic mach_panic\n#include <mach/mach.h>\n#undef panic'), c_code
1025 assert c_code.contains('#define panic mach_panic\n#include <mach/mach_time.h>\n#undef panic'), c_code
1026 assert directive_order_index(c_code, '#undef panic') < preamble_idx, c_code
1027 assert !c_code.contains('typedef struct mach_timebase_info_data_t mach_timebase_info_data_t;'), c_code
1028
1029 assert directive_order_count(c_code, 'mach_timebase_info(') == 1, c_code
1030}
1031
1032fn test_stdarg_in_inlined_header_uses_headerless_va_defs() {
1033 c_code := directive_order_gen_and_run_stdarg_header(directive_order_build_v3())
1034 assert !c_code.contains('#include <stdarg.h>'), c_code
1035 assert !c_code.contains('#include <stddef.h>'), c_code
1036 assert c_code.contains('typedef __builtin_va_list va_list;'), c_code
1037 assert c_code.contains('#define va_start(ap, last) __builtin_va_start(ap, last)'), c_code
1038 assert c_code.contains('#define va_arg(ap, type) __builtin_va_arg(ap, type)'), c_code
1039 assert c_code.contains('#define offsetof(type, member) __builtin_offsetof(type, member)'), c_code
1040 assert c_code.contains('offsetof(struct StdargThing, value)'), c_code
1041 assert c_code.contains('static inline int stdarg_sum(int count, ...)'), c_code
1042}
1043
1044fn test_rwmutex_keeps_linux_rwlockattr_prototype() {
1045 c_code := directive_order_gen_c_rwmutex(directive_order_build_v3())
1046 assert c_code.contains('int pthread_rwlockattr_setkind_np('), c_code
1047}
1048
1049fn test_request_named_c_function_keeps_extern_prototype() {
1050 c_code := directive_order_gen_c_request_extern(directive_order_build_v3())
1051 assert c_code.contains('int request(int'), c_code
1052}
1053