| 1 | // vtest build: macos |
| 2 | module builder |
| 3 | |
| 4 | import os |
| 5 | import v2.ast |
| 6 | import v2.pref |
| 7 | |
| 8 | fn test_get_v_files_from_dir_uses_target_os() { |
| 9 | tmp_dir := os.join_path(os.vtmp_dir(), 'v2_builder_target_os_${os.getpid()}') |
| 10 | os.mkdir_all(tmp_dir) or { panic(err) } |
| 11 | defer { |
| 12 | os.rmdir_all(tmp_dir) or {} |
| 13 | } |
| 14 | os.write_file(os.join_path(tmp_dir, 'common.v'), 'module test') or { panic(err) } |
| 15 | os.write_file(os.join_path(tmp_dir, 'platform_linux.v'), 'module test') or { panic(err) } |
| 16 | os.write_file(os.join_path(tmp_dir, 'platform_macos.v'), 'module test') or { panic(err) } |
| 17 | |
| 18 | macos_files := get_v_files_from_dir(tmp_dir, []string{}, 'mac') |
| 19 | macos_names := macos_files.map(os.file_name(it)) |
| 20 | assert 'common.v' in macos_names |
| 21 | assert 'platform_macos.v' in macos_names |
| 22 | assert 'platform_linux.v' !in macos_names |
| 23 | |
| 24 | linux_files := get_v_files_from_dir(tmp_dir, []string{}, 'linux') |
| 25 | linux_names := linux_files.map(os.file_name(it)) |
| 26 | assert 'common.v' in linux_names |
| 27 | assert 'platform_linux.v' in linux_names |
| 28 | assert 'platform_macos.v' !in linux_names |
| 29 | } |
| 30 | |
| 31 | fn test_get_v_files_from_dir_uses_d_and_notd_suffixes() { |
| 32 | tmp_dir := os.join_path(os.vtmp_dir(), 'v2_builder_define_suffix_${os.getpid()}') |
| 33 | os.mkdir_all(tmp_dir) or { panic(err) } |
| 34 | defer { |
| 35 | os.rmdir_all(tmp_dir) or {} |
| 36 | } |
| 37 | os.write_file(os.join_path(tmp_dir, 'common.v'), 'module test') or { panic(err) } |
| 38 | os.write_file(os.join_path(tmp_dir, 'ssl_d_use_openssl.v'), 'module test') or { panic(err) } |
| 39 | os.write_file(os.join_path(tmp_dir, 'ssl_notd_use_openssl.v'), 'module test') or { panic(err) } |
| 40 | |
| 41 | default_names := get_v_files_from_dir(tmp_dir, []string{}, 'mac').map(os.file_name(it)) |
| 42 | assert 'common.v' in default_names |
| 43 | assert 'ssl_d_use_openssl.v' !in default_names |
| 44 | assert 'ssl_notd_use_openssl.v' in default_names |
| 45 | |
| 46 | openssl_names := get_v_files_from_dir(tmp_dir, ['use_openssl'], 'mac').map(os.file_name(it)) |
| 47 | assert 'common.v' in openssl_names |
| 48 | assert 'ssl_d_use_openssl.v' in openssl_names |
| 49 | assert 'ssl_notd_use_openssl.v' !in openssl_names |
| 50 | } |
| 51 | |
| 52 | fn test_get_v_files_from_dir_skips_prealloc_without_prealloc_flag() { |
| 53 | tmp_dir := os.join_path(os.vtmp_dir(), 'v2_builder_prealloc_${os.getpid()}') |
| 54 | os.mkdir_all(tmp_dir) or { panic(err) } |
| 55 | defer { |
| 56 | os.rmdir_all(tmp_dir) or {} |
| 57 | } |
| 58 | os.write_file(os.join_path(tmp_dir, 'common.v'), 'module test') or { panic(err) } |
| 59 | os.write_file(os.join_path(tmp_dir, 'prealloc.c.v'), 'module test') or { panic(err) } |
| 60 | |
| 61 | default_names := get_v_files_from_dir(tmp_dir, []string{}, 'mac').map(os.file_name(it)) |
| 62 | assert 'common.v' in default_names |
| 63 | assert 'prealloc.c.v' !in default_names |
| 64 | |
| 65 | prealloc_names := get_v_files_from_dir(tmp_dir, ['prealloc'], 'mac').map(os.file_name(it)) |
| 66 | assert 'common.v' in prealloc_names |
| 67 | assert 'prealloc.c.v' in prealloc_names |
| 68 | } |
| 69 | |
| 70 | fn test_get_v_files_from_dir_returns_lexically_sorted_files() { |
| 71 | tmp_dir := os.join_path(os.vtmp_dir(), 'v2_builder_sorted_v_files_${os.getpid()}') |
| 72 | os.mkdir_all(tmp_dir) or { panic(err) } |
| 73 | defer { |
| 74 | os.rmdir_all(tmp_dir) or {} |
| 75 | } |
| 76 | os.write_file(os.join_path(tmp_dir, 'foo.v'), 'module test') or { panic(err) } |
| 77 | os.write_file(os.join_path(tmp_dir, 'foo.c.v'), 'module test') or { panic(err) } |
| 78 | os.write_file(os.join_path(tmp_dir, 'bar.v'), 'module test') or { panic(err) } |
| 79 | os.write_file(os.join_path(tmp_dir, 'ignore.txt'), 'not v') or { panic(err) } |
| 80 | |
| 81 | names := get_v_files_from_dir(tmp_dir, []string{}, 'linux').map(os.file_name(it)) |
| 82 | assert names == ['bar.v', 'foo.c.v', 'foo.v'] |
| 83 | assert names.index('foo.c.v') or { -1 } < names.index('foo.v') or { -1 } |
| 84 | } |
| 85 | |
| 86 | fn test_flag_helpers_use_target_os() { |
| 87 | assert flag_os_matches('macos', 'mac') |
| 88 | assert flag_os_matches('bsd', 'mac') |
| 89 | assert flag_os_matches('bsd', 'freebsd') |
| 90 | assert !flag_os_matches('linux', 'mac') |
| 91 | assert comptime_cond_matches('macos', 'mac') |
| 92 | assert comptime_cond_matches('linux || bsd', 'mac') |
| 93 | assert !comptime_cond_matches('linux', 'mac') |
| 94 | assert comptime_cond_matches('macos && !linux', 'mac') |
| 95 | macos_flag := parse_flag_directive_line('#flag macos -framework Cocoa', '/tmp/source.v', 'mac') or { |
| 96 | '' |
| 97 | } |
| 98 | linux_flag := parse_flag_directive_line('#flag linux -lm', '/tmp/source.v', 'mac') or { '' } |
| 99 | assert macos_flag == '-framework Cocoa' |
| 100 | assert linux_flag == '' |
| 101 | } |
| 102 | |
| 103 | fn test_flag_helpers_expand_when_first_existing() { |
| 104 | tmp_dir := os.join_path(os.vtmp_dir(), 'v2_builder_when_first_${os.getpid()}') |
| 105 | existing_dir := os.join_path(tmp_dir, 'openssl_include') |
| 106 | os.mkdir_all(existing_dir) or { panic(err) } |
| 107 | defer { |
| 108 | os.rmdir_all(tmp_dir) or {} |
| 109 | } |
| 110 | missing_dir := os.join_path(tmp_dir, 'missing') |
| 111 | flag := parse_flag_directive_line("#flag darwin -I\$when_first_existing('${missing_dir}','${existing_dir}')", os.join_path(tmp_dir, |
| 112 | 'source.v'), 'mac') or { '' } |
| 113 | assert flag == '-I${existing_dir}' |
| 114 | none_flag := parse_flag_directive_line("#flag darwin -I\$when_first_existing('${missing_dir}')", os.join_path(tmp_dir, |
| 115 | 'source.v'), 'mac') or { '' } |
| 116 | assert none_flag == '' |
| 117 | } |
| 118 | |
| 119 | fn test_split_compile_and_link_flags_moves_c_sources_to_link_step() { |
| 120 | compile_flags, link_flags := |
| 121 | split_compile_and_link_flags('-I /tmp/include -DMYFLAG thirdparty/sqlite/sqlite3.c -L/tmp/lib -lsqlite3 foo.o') |
| 122 | assert compile_flags == '-I /tmp/include -DMYFLAG' |
| 123 | assert link_flags == 'thirdparty/sqlite/sqlite3.c -L/tmp/lib -lsqlite3 foo.o' |
| 124 | } |
| 125 | |
| 126 | fn test_sanitize_header_source_preserves_public_module_storage() { |
| 127 | source := 'module state |
| 128 | |
| 129 | pub __global ( |
| 130 | mut count int |
| 131 | pub mut shared int |
| 132 | ) |
| 133 | |
| 134 | pub __global mut total int |
| 135 | ' |
| 136 | sanitized := sanitize_header_source(source, map[string]string{}) |
| 137 | assert sanitized.contains('pub __global (') |
| 138 | assert sanitized.contains('mut count int') |
| 139 | assert sanitized.contains('pub mut shared int') |
| 140 | assert sanitized.contains('pub __global mut total int') |
| 141 | } |
| 142 | |
| 143 | fn test_build_module_header_ast_preserves_module_storage_flags() { |
| 144 | mut prefs := pref.new_preferences() |
| 145 | mut b := new_builder(&prefs) |
| 146 | source_file := ast.File{ |
| 147 | mod: 'state' |
| 148 | name: 'state.v' |
| 149 | stmts: [ |
| 150 | ast.Stmt(ast.ModuleStmt{ |
| 151 | name: 'state' |
| 152 | }), |
| 153 | ast.Stmt(ast.GlobalDecl{ |
| 154 | is_public: true |
| 155 | fields: [ |
| 156 | ast.FieldDecl{ |
| 157 | name: 'private_count' |
| 158 | typ: ast.Ident{ |
| 159 | name: 'int' |
| 160 | } |
| 161 | is_mut: true |
| 162 | is_public: false |
| 163 | }, |
| 164 | ast.FieldDecl{ |
| 165 | name: 'shared_count' |
| 166 | typ: ast.Ident{ |
| 167 | name: 'int' |
| 168 | } |
| 169 | is_mut: true |
| 170 | is_public: true |
| 171 | }, |
| 172 | ] |
| 173 | }), |
| 174 | ] |
| 175 | } |
| 176 | header := b.build_module_header_ast([source_file], 'state') or { |
| 177 | panic('missing module storage header') |
| 178 | } |
| 179 | mut found := false |
| 180 | for stmt in header.stmts { |
| 181 | if stmt is ast.GlobalDecl { |
| 182 | found = true |
| 183 | assert stmt.is_public |
| 184 | assert stmt.fields.len == 2 |
| 185 | assert stmt.fields[0].name == 'private_count' |
| 186 | assert stmt.fields[0].is_mut |
| 187 | assert !stmt.fields[0].is_public |
| 188 | assert stmt.fields[1].name == 'shared_count' |
| 189 | assert stmt.fields[1].is_mut |
| 190 | assert stmt.fields[1].is_public |
| 191 | } |
| 192 | } |
| 193 | assert found |
| 194 | } |
| 195 | |
| 196 | fn test_cflags_need_objc_mode_only_for_objc_inputs() { |
| 197 | assert cflags_need_objc_mode('-framework Cocoa') |
| 198 | assert cflags_need_objc_mode('/tmp/clipboard_darwin.m -framework Foundation') |
| 199 | assert !cflags_need_objc_mode('-I /tmp/include -lssl -lcrypto /tmp/sqlite3.c') |
| 200 | assert !cflags_need_objc_mode('-I /tmp/project.m/include') |
| 201 | } |
| 202 | |
| 203 | fn test_file_has_incompatible_os_suffix_windows() { |
| 204 | assert pref.file_has_incompatible_os_suffix('time_solaris.c.v', 'windows') |
| 205 | assert pref.file_has_incompatible_os_suffix('time_freebsd.c.v', 'windows') |
| 206 | assert pref.file_has_incompatible_os_suffix('time_openbsd.c.v', 'windows') |
| 207 | assert pref.file_has_incompatible_os_suffix('time_netbsd.c.v', 'windows') |
| 208 | assert pref.file_has_incompatible_os_suffix('time_dragonfly.c.v', 'windows') |
| 209 | assert pref.file_has_incompatible_os_suffix('time_nix.c.v', 'windows') |
| 210 | assert !pref.file_has_incompatible_os_suffix('time_windows.c.v', 'windows') |
| 211 | } |
| 212 | |
| 213 | fn test_file_has_incompatible_os_suffix_non_windows_targets() { |
| 214 | assert !pref.file_has_incompatible_os_suffix('time_solaris.c.v', 'solaris') |
| 215 | assert !pref.file_has_incompatible_os_suffix('time_freebsd.c.v', 'freebsd') |
| 216 | assert !pref.file_has_incompatible_os_suffix('time_bsd.c.v', 'macos') |
| 217 | assert pref.file_has_incompatible_os_suffix('time_bsd.c.v', 'linux') |
| 218 | assert !pref.file_has_incompatible_os_suffix('time_darwin.c.v', 'macos') |
| 219 | assert !pref.file_has_incompatible_os_suffix('time_macos.c.v', 'darwin') |
| 220 | assert !pref.file_has_incompatible_os_suffix('time_android_outside_termux.c.v', 'android') |
| 221 | assert pref.file_has_incompatible_os_suffix('time_windows.c.v', 'linux') |
| 222 | assert pref.file_has_incompatible_os_suffix('time_android_outside_termux.c.v', 'linux') |
| 223 | } |
| 224 | |
| 225 | fn test_default_cc_uses_tcc_when_available() { |
| 226 | vroot := os.dir(os.dir(@FILE)) |
| 227 | tcc_path := os.join_path(vroot, 'thirdparty', 'tcc', 'tcc.exe') |
| 228 | cc := default_cc(vroot) |
| 229 | if os.exists(tcc_path) { |
| 230 | assert cc.contains('tcc') |
| 231 | } else { |
| 232 | assert cc == 'cc' |
| 233 | } |
| 234 | } |
| 235 | |
| 236 | fn test_cc_recompile_flags_from_cmd_keeps_include_paths() { |
| 237 | cmd := 'cc -I /tmp/include -I/tmp/other -Dfoo=1 -x objective-c -std=gnu11 -fwrapv "/tmp/main.c" -x none "/tmp/lib.o" -L/tmp/lib -lm -o "app"' |
| 238 | flags := cc_recompile_flags_from_cmd(cmd) |
| 239 | assert flags.contains('-I /tmp/include') |
| 240 | assert flags.contains('-I/tmp/other') |
| 241 | assert flags.contains('-Dfoo=1') |
| 242 | assert flags.contains('-x objective-c') |
| 243 | assert flags.contains('-std=gnu11') |
| 244 | assert flags.contains('-fwrapv') |
| 245 | assert !flags.contains('/tmp/lib.o') |
| 246 | assert !flags.contains('-L/tmp/lib') |
| 247 | assert !flags.contains('-lm') |
| 248 | assert !flags.contains('-o') |
| 249 | } |
| 250 | |