diff --git a/build.zig b/build.zig index 36bb1e0f73e60ac7568379ac248458f8053a876a..11d716a17ffd1610d6698a61b69a4f666a749f87 100644 --- a/build.zig +++ b/build.zig @@ -521,11 +521,10 @@ pub fn build(b: *std.Build) !void { optimization_modes, enable_macos_sdk, enable_ios_sdk, - false, enable_symlinks_windows, )); test_step.dependOn(tests.addCAbiTests(b, skip_non_native, skip_release)); - test_step.dependOn(tests.addLinkTests(b, enable_macos_sdk, enable_ios_sdk, false, enable_symlinks_windows)); + test_step.dependOn(tests.addLinkTests(b, enable_macos_sdk, enable_ios_sdk, enable_symlinks_windows)); test_step.dependOn(tests.addStackTraceTests(b, test_filters, optimization_modes)); test_step.dependOn(tests.addCliTests(b)); test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filters, optimization_modes)); diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000000000000000000000000000000000000..3b0cd4a11deee5fb4073556dfb140dbb9bb06167 --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,15 @@ +// The Zig compiler is not intended to be consumed as a package. +// The sole purpose of this manifest file is to test the compiler. +.{ + .name = "zig", + .version = "0.0.0", + .dependencies = .{ + .standalone_test_cases = .{ + .path = "test/standalone", + }, + .link_test_cases = .{ + .path = "test/link", + }, + }, + .paths = .{""}, +} diff --git a/lib/std/Build.zig b/lib/std/Build.zig index ca7c3f504550257aa9124d34763a9ee258065721..2c644ce4b03162fb1eaf77a8449f3aee7c92dce0 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -1967,25 +1967,6 @@ pub fn dependencyFromBuildZig( debug.panic("'{}' is not a build.zig struct of a dependecy in '{s}'", .{ build_zig, full_path }); } -pub fn anonymousDependency( - b: *Build, - /// The path to the directory containing the dependency's build.zig file, - /// relative to the current package's build.zig. - relative_build_root: []const u8, - /// A direct `@import` of the build.zig of the dependency. - comptime build_zig: type, - args: anytype, -) *Dependency { - const arena = b.allocator; - const build_root = b.build_root.join(arena, &.{relative_build_root}) catch @panic("OOM"); - const name = arena.dupe(u8, relative_build_root) catch @panic("OOM"); - for (name) |*byte| switch (byte.*) { - '/', '\\' => byte.* = '.', - else => continue, - }; - return dependencyInner(b, name, build_root, build_zig, "anonymous", &.{}, args); -} - fn userValuesAreSame(lhs: UserValue, rhs: UserValue) bool { switch (lhs) { .flag => {}, @@ -2033,7 +2014,7 @@ fn userValuesAreSame(lhs: UserValue, rhs: UserValue) bool { return true; } -pub fn dependencyInner( +fn dependencyInner( b: *Build, name: []const u8, build_root_string: []const u8, diff --git a/test/link.zig b/test/link.zig deleted file mode 100644 index 58b2dc9f96953e5c6b00f54cc64e39e1e298323c..0000000000000000000000000000000000000000 --- a/test/link.zig +++ /dev/null @@ -1,94 +0,0 @@ -pub const Case = struct { - build_root: []const u8, - import: type, -}; - -pub const cases = [_]Case{ - .{ - .build_root = "test/link", - .import = @import("link/link.zig"), - }, - - .{ - .build_root = "test/link/bss", - .import = @import("link/bss/build.zig"), - }, - .{ - .build_root = "test/link/common_symbols", - .import = @import("link/common_symbols/build.zig"), - }, - .{ - .build_root = "test/link/common_symbols_alignment", - .import = @import("link/common_symbols_alignment/build.zig"), - }, - .{ - .build_root = "test/link/interdependent_static_c_libs", - .import = @import("link/interdependent_static_c_libs/build.zig"), - }, - .{ - .build_root = "test/link/static_libs_from_object_files", - .import = @import("link/static_libs_from_object_files/build.zig"), - }, - .{ - .build_root = "test/link/glibc_compat", - .import = @import("link/glibc_compat/build.zig"), - }, - - // WASM Cases - .{ - .build_root = "test/link/wasm/archive", - .import = @import("link/wasm/archive/build.zig"), - }, - .{ - .build_root = "test/link/wasm/basic-features", - .import = @import("link/wasm/basic-features/build.zig"), - }, - .{ - .build_root = "test/link/wasm/bss", - .import = @import("link/wasm/bss/build.zig"), - }, - .{ - .build_root = "test/link/wasm/export", - .import = @import("link/wasm/export/build.zig"), - }, - .{ - .build_root = "test/link/wasm/export-data", - .import = @import("link/wasm/export-data/build.zig"), - }, - .{ - .build_root = "test/link/wasm/extern", - .import = @import("link/wasm/extern/build.zig"), - }, - .{ - .build_root = "test/link/wasm/extern-mangle", - .import = @import("link/wasm/extern-mangle/build.zig"), - }, - .{ - .build_root = "test/link/wasm/function-table", - .import = @import("link/wasm/function-table/build.zig"), - }, - .{ - .build_root = "test/link/wasm/infer-features", - .import = @import("link/wasm/infer-features/build.zig"), - }, - .{ - .build_root = "test/link/wasm/producers", - .import = @import("link/wasm/producers/build.zig"), - }, - .{ - .build_root = "test/link/wasm/segments", - .import = @import("link/wasm/segments/build.zig"), - }, - .{ - .build_root = "test/link/wasm/shared-memory", - .import = @import("link/wasm/shared-memory/build.zig"), - }, - .{ - .build_root = "test/link/wasm/stack_pointer", - .import = @import("link/wasm/stack_pointer/build.zig"), - }, - .{ - .build_root = "test/link/wasm/type", - .import = @import("link/wasm/type/build.zig"), - }, -}; diff --git a/test/link/build.zig b/test/link/build.zig new file mode 100644 index 0000000000000000000000000000000000000000..2774344d27787239b9b8ebbdb53ac0682c4f2628 --- /dev/null +++ b/test/link/build.zig @@ -0,0 +1,54 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const link = @import("link.zig"); + +pub fn build(b: *std.Build) void { + const step = b.step("test", "Run link test cases"); + b.default_step = step; + + const enable_ios_sdk = b.option(bool, "enable_ios_sdk", "Run tests requiring presence of iOS SDK and frameworks") orelse false; + const enable_macos_sdk = b.option(bool, "enable_macos_sdk", "Run tests requiring presence of macOS SDK and frameworks") orelse enable_ios_sdk; + const enable_symlinks_windows = b.option(bool, "enable_symlinks_windows", "Run tests requiring presence of symlinks on Windows") orelse false; + const omit_symlinks = builtin.os.tag == .windows and !enable_symlinks_windows; + + const build_opts: link.BuildOptions = .{ + .has_ios_sdk = enable_ios_sdk, + .has_macos_sdk = enable_macos_sdk, + .has_symlinks_windows = omit_symlinks, + }; + step.dependOn(@import("elf.zig").testAll(b, build_opts)); + step.dependOn(@import("macho.zig").testAll(b, build_opts)); + + add_dep_steps: for (b.available_deps) |available_dep| { + const dep_name, const dep_hash = available_dep; + + const all_pkgs = @import("root").dependencies.packages; + inline for (@typeInfo(all_pkgs).Struct.decls) |decl| { + const pkg_hash = decl.name; + if (std.mem.eql(u8, dep_hash, pkg_hash)) { + const pkg = @field(all_pkgs, pkg_hash); + if (!@hasDecl(pkg, "build_zig")) { + std.debug.panic("link test case '{s}' is missing a 'build.zig' file", .{dep_name}); + } + const requires_ios_sdk = @hasDecl(pkg.build_zig, "requires_ios_sdk") and + pkg.build_zig.requires_ios_sdk; + const requires_macos_sdk = @hasDecl(pkg.build_zig, "requires_macos_sdk") and + pkg.build_zig.requires_macos_sdk; + const requires_symlinks = @hasDecl(pkg.build_zig, "requires_symlinks") and + pkg.build_zig.requires_symlinks; + if ((requires_symlinks and omit_symlinks) or + (requires_macos_sdk and !enable_macos_sdk) or + (requires_ios_sdk and !enable_ios_sdk)) + { + continue :add_dep_steps; + } + break; + } + } else unreachable; + + const dep = b.dependency(dep_name, .{}); + const dep_step = dep.builder.default_step; + dep_step.name = b.fmt("link_test_cases.{s}", .{dep_name}); + step.dependOn(dep_step); + } +} diff --git a/test/link/build.zig.zon b/test/link/build.zig.zon new file mode 100644 index 0000000000000000000000000000000000000000..d304212c051a62531cecd7de9ff2344008cf6932 --- /dev/null +++ b/test/link/build.zig.zon @@ -0,0 +1,69 @@ +.{ + .name = "link_test_cases", + .version = "0.0.0", + .dependencies = .{ + .bss = .{ + .path = "bss", + }, + .common_symbols_alignment = .{ + .path = "common_symbols_alignment", + }, + .interdependent_static_c_libs = .{ + .path = "interdependent_static_c_libs", + }, + .static_libs_from_object_files = .{ + .path = "static_libs_from_object_files", + }, + .glibc_compat = .{ + .path = "glibc_compat", + }, + // WASM Cases + .wasm_archive = .{ + .path = "wasm/archive", + }, + .wasm_basic_features = .{ + .path = "wasm/basic-features", + }, + .wasm_bss = .{ + .path = "wasm/bss", + }, + .wasm_export = .{ + .path = "wasm/export", + }, + .wasm_export_data = .{ + .path = "wasm/export-data", + }, + .wasm_extern = .{ + .path = "wasm/extern", + }, + .wasm_extern_mangle = .{ + .path = "wasm/extern-mangle", + }, + .wasm_function_table = .{ + .path = "wasm/function-table", + }, + .wasm_infer_features = .{ + .path = "wasm/infer-features", + }, + .wasm_producers = .{ + .path = "wasm/producers", + }, + .wasm_segments = .{ + .path = "wasm/segments", + }, + .wasm_shared_memory = .{ + .path = "wasm/shared-memory", + }, + .wasm_stack_pointer = .{ + .path = "wasm/stack_pointer", + }, + .wasm_type = .{ + .path = "wasm/type", + }, + }, + .paths = .{ + "build.zig", + "build.zig.zon", + "link.zig", + }, +} diff --git a/test/standalone.zig b/test/standalone.zig deleted file mode 100644 index 2f1b7d1339a0f506d13f990038c8a65aa7593aa1..0000000000000000000000000000000000000000 --- a/test/standalone.zig +++ /dev/null @@ -1,275 +0,0 @@ -pub const SimpleCase = struct { - src_path: []const u8, - link_libc: bool = false, - all_modes: bool = false, - target: std.Target.Query = .{}, - is_test: bool = false, - is_exe: bool = true, - /// Run only on this OS. - os_filter: ?std.Target.Os.Tag = null, -}; - -pub const BuildCase = struct { - build_root: []const u8, - import: type, -}; - -pub const simple_cases = [_]SimpleCase{ - .{ - .src_path = "test/standalone/hello_world/hello.zig", - .all_modes = true, - }, - .{ - .src_path = "test/standalone/hello_world/hello_libc.zig", - .link_libc = true, - .all_modes = true, - }, - .{ - .src_path = "test/standalone/cat/main.zig", - }, - // https://github.com/ziglang/zig/issues/6025 - //.{ - // .src_path = "test/standalone/issue_9693/main.zig", - //}, - .{ - .src_path = "test/standalone/brace_expansion.zig", - .is_test = true, - }, - .{ - .src_path = "test/standalone/issue_7030.zig", - .target = .{ - .cpu_arch = .wasm32, - .os_tag = .freestanding, - }, - }, - - .{ .src_path = "test/standalone/issue_12471/main.zig" }, - .{ .src_path = "test/standalone/guess_number/main.zig" }, - .{ .src_path = "test/standalone/main_return_error/error_u8.zig" }, - .{ .src_path = "test/standalone/main_return_error/error_u8_non_zero.zig" }, - .{ .src_path = "test/standalone/noreturn_call/inline.zig" }, - .{ .src_path = "test/standalone/noreturn_call/as_arg.zig" }, - .{ .src_path = "test/standalone/std_enums_big_enums.zig" }, - - .{ - .src_path = "test/standalone/issue_9402/main.zig", - .os_filter = .windows, - .link_libc = true, - }, - - // Ensure the development tools are buildable. Alphabetically sorted. - // No need to build `tools/spirv/grammar.zig`. - .{ .src_path = "tools/gen_outline_atomics.zig" }, - .{ .src_path = "tools/gen_spirv_spec.zig" }, - .{ .src_path = "tools/gen_stubs.zig" }, - .{ .src_path = "tools/generate_linux_syscalls.zig" }, - .{ .src_path = "tools/process_headers.zig" }, - .{ .src_path = "tools/update-linux-headers.zig" }, - .{ .src_path = "tools/update_clang_options.zig" }, - .{ .src_path = "tools/update_cpu_features.zig" }, - .{ .src_path = "tools/update_glibc.zig" }, - .{ .src_path = "tools/update_spirv_features.zig" }, -}; - -pub const build_cases = [_]BuildCase{ - .{ - .build_root = "test/standalone/test_runner_path", - .import = @import("standalone/test_runner_path/build.zig"), - }, - .{ - .build_root = "test/standalone/test_runner_module_imports", - .import = @import("standalone/test_runner_module_imports/build.zig"), - }, - // https://github.com/ziglang/zig/issues/17483 - //.{ - // .build_root = "test/standalone/issue_13970", - // .import = @import("standalone/issue_13970/build.zig"), - //}, - .{ - .build_root = "test/standalone/shared_library", - .import = @import("standalone/shared_library/build.zig"), - }, - .{ - .build_root = "test/standalone/mix_o_files", - .import = @import("standalone/mix_o_files/build.zig"), - }, - .{ - .build_root = "test/standalone/mix_c_files", - .import = @import("standalone/mix_c_files/build.zig"), - }, - .{ - .build_root = "test/standalone/global_linkage", - .import = @import("standalone/global_linkage/build.zig"), - }, - .{ - .build_root = "test/standalone/static_c_lib", - .import = @import("standalone/static_c_lib/build.zig"), - }, - .{ - .build_root = "test/standalone/issue_339", - .import = @import("standalone/issue_339/build.zig"), - }, - .{ - .build_root = "test/standalone/issue_8550", - .import = @import("standalone/issue_8550/build.zig"), - }, - .{ - .build_root = "test/standalone/issue_794", - .import = @import("standalone/issue_794/build.zig"), - }, - .{ - .build_root = "test/standalone/issue_5825", - .import = @import("standalone/issue_5825/build.zig"), - }, - .{ - .build_root = "test/standalone/pkg_import", - .import = @import("standalone/pkg_import/build.zig"), - }, - .{ - .build_root = "test/standalone/use_alias", - .import = @import("standalone/use_alias/build.zig"), - }, - .{ - .build_root = "test/standalone/install_raw_hex", - .import = @import("standalone/install_raw_hex/build.zig"), - }, - // https://github.com/ziglang/zig/issues/17484 - //.{ - // .build_root = "test/standalone/emit_asm_and_bin", - // .import = @import("standalone/emit_asm_and_bin/build.zig"), - //}, - // https://github.com/ziglang/zig/issues/17484 - //.{ - // .build_root = "test/standalone/issue_12588", - // .import = @import("standalone/issue_12588/build.zig"), - //}, - .{ - .build_root = "test/standalone/child_process", - .import = @import("standalone/child_process/build.zig"), - }, - .{ - .build_root = "test/standalone/embed_generated_file", - .import = @import("standalone/embed_generated_file/build.zig"), - }, - .{ - .build_root = "test/standalone/extern", - .import = @import("standalone/extern/build.zig"), - }, - .{ - .build_root = "test/standalone/dep_diamond", - .import = @import("standalone/dep_diamond/build.zig"), - }, - .{ - .build_root = "test/standalone/dep_triangle", - .import = @import("standalone/dep_triangle/build.zig"), - }, - .{ - .build_root = "test/standalone/dep_recursive", - .import = @import("standalone/dep_recursive/build.zig"), - }, - .{ - .build_root = "test/standalone/dep_mutually_recursive", - .import = @import("standalone/dep_mutually_recursive/build.zig"), - }, - .{ - .build_root = "test/standalone/dep_shared_builtin", - .import = @import("standalone/dep_shared_builtin/build.zig"), - }, - .{ - .build_root = "test/standalone/dirname", - .import = @import("standalone/dirname/build.zig"), - }, - .{ - .build_root = "test/standalone/empty_env", - .import = @import("standalone/empty_env/build.zig"), - }, - .{ - .build_root = "test/standalone/issue_11595", - .import = @import("standalone/issue_11595/build.zig"), - }, - .{ - .build_root = "test/standalone/load_dynamic_library", - .import = @import("standalone/load_dynamic_library/build.zig"), - }, - .{ - .build_root = "test/standalone/windows_resources", - .import = @import("standalone/windows_resources/build.zig"), - }, - .{ - .build_root = "test/standalone/windows_entry_points", - .import = @import("standalone/windows_entry_points/build.zig"), - }, - .{ - .build_root = "test/standalone/windows_spawn", - .import = @import("standalone/windows_spawn/build.zig"), - }, - .{ - .build_root = "test/standalone/self_exe_symlink", - .import = @import("standalone/self_exe_symlink/build.zig"), - }, - .{ - .build_root = "test/standalone/c_compiler", - .import = @import("standalone/c_compiler/build.zig"), - }, - .{ - .build_root = "test/standalone/pie", - .import = @import("standalone/pie/build.zig"), - }, - .{ - .build_root = "test/standalone/issue_12706", - .import = @import("standalone/issue_12706/build.zig"), - }, - // TODO This test is disabled for doing naughty things in the build script. - // The logic needs to get moved to a child process instead of build.zig. - //.{ - // .build_root = "test/standalone/sigpipe", - // .import = @import("standalone/sigpipe/build.zig"), - //}, - // TODO restore this test - //.{ - // .build_root = "test/standalone/options", - // .import = @import("standalone/options/build.zig"), - //}, - .{ - .build_root = "test/standalone/strip_empty_loop", - .import = @import("standalone/strip_empty_loop/build.zig"), - }, - .{ - .build_root = "test/standalone/strip_struct_init", - .import = @import("standalone/strip_struct_init/build.zig"), - }, - .{ - .build_root = "test/standalone/cmakedefine", - .import = @import("standalone/cmakedefine/build.zig"), - }, - .{ - .build_root = "test/standalone/zerolength_check", - .import = @import("standalone/zerolength_check/build.zig"), - }, - .{ - .build_root = "test/standalone/stack_iterator", - .import = @import("standalone/stack_iterator/build.zig"), - }, - .{ - .build_root = "test/standalone/coff_dwarf", - .import = @import("standalone/coff_dwarf/build.zig"), - }, - .{ - .build_root = "test/standalone/compiler_rt_panic", - .import = @import("standalone/compiler_rt_panic/build.zig"), - }, - .{ - .build_root = "test/standalone/ios", - .import = @import("standalone/ios/build.zig"), - }, - .{ - .build_root = "test/standalone/depend_on_main_mod", - .import = @import("standalone/depend_on_main_mod/build.zig"), - }, - .{ - .build_root = "test/standalone/install_headers", - .import = @import("standalone/install_headers/build.zig"), - }, -}; - -const std = @import("std"); diff --git a/test/standalone/brace_expansion.zig b/test/standalone/brace_expansion.zig deleted file mode 100644 index 7a769f6af7435c1f782a9676febf2dd91e557e23..0000000000000000000000000000000000000000 --- a/test/standalone/brace_expansion.zig +++ /dev/null @@ -1,292 +0,0 @@ -const std = @import("std"); -const io = std.io; -const mem = std.mem; -const debug = std.debug; -const assert = debug.assert; -const testing = std.testing; -const ArrayList = std.ArrayList; -const maxInt = std.math.maxInt; - -const Token = union(enum) { - Word: []const u8, - OpenBrace, - CloseBrace, - Comma, - Eof, -}; - -var gpa = std.heap.GeneralPurposeAllocator(.{}){}; -var global_allocator = gpa.allocator(); - -fn tokenize(input: []const u8) !ArrayList(Token) { - const State = enum { - Start, - Word, - }; - - var token_list = ArrayList(Token).init(global_allocator); - errdefer token_list.deinit(); - var tok_begin: usize = undefined; - var state = State.Start; - - for (input, 0..) |b, i| { - switch (state) { - .Start => switch (b) { - 'a'...'z', 'A'...'Z' => { - state = State.Word; - tok_begin = i; - }, - '{' => try token_list.append(Token.OpenBrace), - '}' => try token_list.append(Token.CloseBrace), - ',' => try token_list.append(Token.Comma), - else => return error.InvalidInput, - }, - .Word => switch (b) { - 'a'...'z', 'A'...'Z' => {}, - '{', '}', ',' => { - try token_list.append(Token{ .Word = input[tok_begin..i] }); - switch (b) { - '{' => try token_list.append(Token.OpenBrace), - '}' => try token_list.append(Token.CloseBrace), - ',' => try token_list.append(Token.Comma), - else => unreachable, - } - state = State.Start; - }, - else => return error.InvalidInput, - }, - } - } - switch (state) { - State.Start => {}, - State.Word => try token_list.append(Token{ .Word = input[tok_begin..] }), - } - try token_list.append(Token.Eof); - return token_list; -} - -const Node = union(enum) { - Scalar: []const u8, - List: ArrayList(Node), - Combine: []Node, - - fn deinit(self: Node) void { - switch (self) { - .Scalar => {}, - .Combine => |pair| { - pair[0].deinit(); - pair[1].deinit(); - global_allocator.free(pair); - }, - .List => |list| { - for (list.items) |item| { - item.deinit(); - } - list.deinit(); - }, - } - } -}; - -const ParseError = error{ - InvalidInput, - OutOfMemory, -}; - -fn parse(tokens: *const ArrayList(Token), token_index: *usize) ParseError!Node { - const first_token = tokens.items[token_index.*]; - token_index.* += 1; - - const result_node = switch (first_token) { - .Word => |word| Node{ .Scalar = word }, - .OpenBrace => blk: { - var list = ArrayList(Node).init(global_allocator); - errdefer { - for (list.items) |node| node.deinit(); - list.deinit(); - } - while (true) { - try list.append(try parse(tokens, token_index)); - - const token = tokens.items[token_index.*]; - token_index.* += 1; - - switch (token) { - .CloseBrace => break, - .Comma => continue, - else => return error.InvalidInput, - } - } - break :blk Node{ .List = list }; - }, - else => return error.InvalidInput, - }; - - switch (tokens.items[token_index.*]) { - .Word, .OpenBrace => { - const pair = try global_allocator.alloc(Node, 2); - errdefer global_allocator.free(pair); - pair[0] = result_node; - pair[1] = try parse(tokens, token_index); - return Node{ .Combine = pair }; - }, - else => return result_node, - } -} - -fn expandString(input: []const u8, output: *ArrayList(u8)) !void { - const tokens = try tokenize(input); - defer tokens.deinit(); - if (tokens.items.len == 1) { - return output.resize(0); - } - - var token_index: usize = 0; - const root = try parse(&tokens, &token_index); - defer root.deinit(); - const last_token = tokens.items[token_index]; - switch (last_token) { - Token.Eof => {}, - else => return error.InvalidInput, - } - - var result_list = ArrayList(ArrayList(u8)).init(global_allocator); - defer { - for (result_list.items) |*buf| buf.deinit(); - result_list.deinit(); - } - - try expandNode(root, &result_list); - - try output.resize(0); - for (result_list.items, 0..) |buf, i| { - if (i != 0) { - try output.append(' '); - } - try output.appendSlice(buf.items); - } -} - -const ExpandNodeError = error{OutOfMemory}; - -fn expandNode(node: Node, output: *ArrayList(ArrayList(u8))) ExpandNodeError!void { - assert(output.items.len == 0); - switch (node) { - .Scalar => |scalar| { - var list = ArrayList(u8).init(global_allocator); - errdefer list.deinit(); - try list.appendSlice(scalar); - try output.append(list); - }, - .Combine => |pair| { - const a_node = pair[0]; - const b_node = pair[1]; - - var child_list_a = ArrayList(ArrayList(u8)).init(global_allocator); - defer { - for (child_list_a.items) |*buf| buf.deinit(); - child_list_a.deinit(); - } - try expandNode(a_node, &child_list_a); - - var child_list_b = ArrayList(ArrayList(u8)).init(global_allocator); - defer { - for (child_list_b.items) |*buf| buf.deinit(); - child_list_b.deinit(); - } - try expandNode(b_node, &child_list_b); - - for (child_list_a.items) |buf_a| { - for (child_list_b.items) |buf_b| { - var combined_buf = ArrayList(u8).init(global_allocator); - errdefer combined_buf.deinit(); - - try combined_buf.appendSlice(buf_a.items); - try combined_buf.appendSlice(buf_b.items); - try output.append(combined_buf); - } - } - }, - .List => |list| { - for (list.items) |child_node| { - var child_list = ArrayList(ArrayList(u8)).init(global_allocator); - errdefer for (child_list.items) |*buf| buf.deinit(); - defer child_list.deinit(); - - try expandNode(child_node, &child_list); - - for (child_list.items) |buf| { - try output.append(buf); - } - } - }, - } -} - -pub fn main() !void { - defer _ = gpa.deinit(); - const stdin_file = io.getStdIn(); - const stdout_file = io.getStdOut(); - - const stdin = try stdin_file.reader().readAllAlloc(global_allocator, std.math.maxInt(usize)); - defer global_allocator.free(stdin); - - var result_buf = ArrayList(u8).init(global_allocator); - defer result_buf.deinit(); - - try expandString(stdin, &result_buf); - try stdout_file.writeAll(result_buf.items); -} - -test "invalid inputs" { - global_allocator = std.testing.allocator; - - try expectError("}ABC", error.InvalidInput); - try expectError("{ABC", error.InvalidInput); - try expectError("}{", error.InvalidInput); - try expectError("{}", error.InvalidInput); - try expectError("A,B,C", error.InvalidInput); - try expectError("{A{B,C}", error.InvalidInput); - try expectError("{A,}", error.InvalidInput); - - try expectError("\n", error.InvalidInput); -} - -fn expectError(test_input: []const u8, expected_err: anyerror) !void { - var output_buf = ArrayList(u8).init(global_allocator); - defer output_buf.deinit(); - - try testing.expectError(expected_err, expandString(test_input, &output_buf)); -} - -test "valid inputs" { - global_allocator = std.testing.allocator; - - try expectExpansion("{x,y,z}", "x y z"); - try expectExpansion("{A,B}{x,y}", "Ax Ay Bx By"); - try expectExpansion("{A,B{x,y}}", "A Bx By"); - - try expectExpansion("{ABC}", "ABC"); - try expectExpansion("{A,B,C}", "A B C"); - try expectExpansion("ABC", "ABC"); - - try expectExpansion("", ""); - try expectExpansion("{A,B}{C,{x,y}}{g,h}", "ACg ACh Axg Axh Ayg Ayh BCg BCh Bxg Bxh Byg Byh"); - try expectExpansion("{A,B}{C,C{x,y}}{g,h}", "ACg ACh ACxg ACxh ACyg ACyh BCg BCh BCxg BCxh BCyg BCyh"); - try expectExpansion("{A,B}a", "Aa Ba"); - try expectExpansion("{C,{x,y}}", "C x y"); - try expectExpansion("z{C,{x,y}}", "zC zx zy"); - try expectExpansion("a{b,c{d,e{f,g}}}", "ab acd acef aceg"); - try expectExpansion("a{x,y}b", "axb ayb"); - try expectExpansion("z{{a,b}}", "za zb"); - try expectExpansion("a{b}", "ab"); -} - -fn expectExpansion(test_input: []const u8, expected_result: []const u8) !void { - var result = ArrayList(u8).init(global_allocator); - defer result.deinit(); - - expandString(test_input, &result) catch unreachable; - - try testing.expectEqualSlices(u8, expected_result, result.items); -} diff --git a/test/standalone/build.zig b/test/standalone/build.zig new file mode 100644 index 0000000000000000000000000000000000000000..673a52cedd5e07f53df1e8286ea8338e3589c7c1 --- /dev/null +++ b/test/standalone/build.zig @@ -0,0 +1,90 @@ +const std = @import("std"); +const builtin = @import("builtin"); + +pub fn build(b: *std.Build) void { + const step = b.step("test", "Run standalone test cases"); + b.default_step = step; + + const enable_ios_sdk = b.option(bool, "enable_ios_sdk", "Run tests requiring presence of iOS SDK and frameworks") orelse false; + const enable_macos_sdk = b.option(bool, "enable_macos_sdk", "Run tests requiring presence of macOS SDK and frameworks") orelse enable_ios_sdk; + const enable_symlinks_windows = b.option(bool, "enable_symlinks_windows", "Run tests requiring presence of symlinks on Windows") orelse false; + const omit_symlinks = builtin.os.tag == .windows and !enable_symlinks_windows; + + const simple_skip_debug = b.option(bool, "simple_skip_debug", "Simple tests skip debug builds") orelse false; + const simple_skip_release_safe = b.option(bool, "simple_skip_release_safe", "Simple tests skip release-safe builds") orelse false; + const simple_skip_release_fast = b.option(bool, "simple_skip_release_fast", "Simple tests skip release-fast builds") orelse false; + const simple_skip_release_small = b.option(bool, "simple_skip_release_small", "Simple tests skip release-small builds") orelse false; + + const simple_dep = b.dependency("simple", .{ + .skip_debug = simple_skip_debug, + .skip_release_safe = simple_skip_release_safe, + .skip_release_fast = simple_skip_release_fast, + .skip_release_small = simple_skip_release_small, + }); + const simple_dep_step = simple_dep.builder.default_step; + simple_dep_step.name = "standalone_test_cases.simple"; + step.dependOn(simple_dep_step); + + // Ensure the development tools are buildable. + const tools_tests_step = b.step("standalone_test_cases.tools", "Test tools"); + step.dependOn(tools_tests_step); + const tools_target = b.resolveTargetQuery(.{}); + for ([_][]const u8{ + // Alphabetically sorted. No need to build `tools/spirv/grammar.zig`. + "../../tools/gen_outline_atomics.zig", + "../../tools/gen_spirv_spec.zig", + "../../tools/gen_stubs.zig", + "../../tools/generate_linux_syscalls.zig", + "../../tools/process_headers.zig", + "../../tools/update-linux-headers.zig", + "../../tools/update_clang_options.zig", + "../../tools/update_cpu_features.zig", + "../../tools/update_glibc.zig", + "../../tools/update_spirv_features.zig", + }) |tool_src_path| { + const tool = b.addTest(.{ + .name = std.fs.path.stem(tool_src_path), + .root_source_file = .{ .path = tool_src_path }, + .optimize = .Debug, + .target = tools_target, + }); + const run = b.addRunArtifact(tool); + tools_tests_step.dependOn(&run.step); + } + + add_dep_steps: for (b.available_deps) |available_dep| { + const dep_name, const dep_hash = available_dep; + + // The 'simple' dependency was already handled manually above. + if (std.mem.eql(u8, dep_name, "simple")) continue; + + const all_pkgs = @import("root").dependencies.packages; + inline for (@typeInfo(all_pkgs).Struct.decls) |decl| { + const pkg_hash = decl.name; + if (std.mem.eql(u8, dep_hash, pkg_hash)) { + const pkg = @field(all_pkgs, pkg_hash); + if (!@hasDecl(pkg, "build_zig")) { + std.debug.panic("standalone test case '{s}' is missing a 'build.zig' file", .{dep_name}); + } + const requires_ios_sdk = @hasDecl(pkg.build_zig, "requires_ios_sdk") and + pkg.build_zig.requires_ios_sdk; + const requires_macos_sdk = @hasDecl(pkg.build_zig, "requires_macos_sdk") and + pkg.build_zig.requires_macos_sdk; + const requires_symlinks = @hasDecl(pkg.build_zig, "requires_symlinks") and + pkg.build_zig.requires_symlinks; + if ((requires_symlinks and omit_symlinks) or + (requires_macos_sdk and !enable_macos_sdk) or + (requires_ios_sdk and !enable_ios_sdk)) + { + continue :add_dep_steps; + } + break; + } + } else unreachable; + + const dep = b.dependency(dep_name, .{}); + const dep_step = dep.builder.default_step; + dep_step.name = b.fmt("standalone_test_cases.{s}", .{dep_name}); + step.dependOn(dep_step); + } +} diff --git a/test/standalone/build.zig.zon b/test/standalone/build.zig.zon new file mode 100644 index 0000000000000000000000000000000000000000..8b59f261179e6c75b6a0625bf47991b8ee2909b4 --- /dev/null +++ b/test/standalone/build.zig.zon @@ -0,0 +1,163 @@ +.{ + .name = "standalone_test_cases", + .version = "0.0.0", + .dependencies = .{ + .simple = .{ + .path = "simple", + }, + .test_runner_path = .{ + .path = "test_runner_path", + }, + .test_runner_module_imports = .{ + .path = "test_runner_module_imports", + }, + // https://github.com/ziglang/zig/issues/17483 + //.issue_13970 = .{ + // .path = "issue_13970", + //}, + .shared_library = .{ + .path = "shared_library", + }, + .mix_o_files = .{ + .path = "mix_o_files", + }, + .mix_c_files = .{ + .path = "mix_c_files", + }, + .global_linkage = .{ + .path = "global_linkage", + }, + .static_c_lib = .{ + .path = "static_c_lib", + }, + .issue_339 = .{ + .path = "issue_339", + }, + .issue_8550 = .{ + .path = "issue_8550", + }, + .issue_794 = .{ + .path = "issue_794", + }, + .issue_5825 = .{ + .path = "issue_5825", + }, + .pkg_import = .{ + .path = "pkg_import", + }, + .use_alias = .{ + .path = "use_alias", + }, + .install_raw_hex = .{ + .path = "install_raw_hex", + }, + // https://github.com/ziglang/zig/issues/17484 + //.emit_asm_and_bin = .{ + // .path = "emit_asm_and_bin", + //}, + // https://github.com/ziglang/zig/issues/17484 + //.issue_12588 = .{ + // .path = "issue_12588", + //}, + .child_process = .{ + .path = "child_process", + }, + .embed_generated_file = .{ + .path = "embed_generated_file", + }, + .@"extern" = .{ + .path = "extern", + }, + .dep_diamond = .{ + .path = "dep_diamond", + }, + .dep_triangle = .{ + .path = "dep_triangle", + }, + .dep_recursive = .{ + .path = "dep_recursive", + }, + .dep_mutually_recursive = .{ + .path = "dep_mutually_recursive", + }, + .dep_shared_builtin = .{ + .path = "dep_shared_builtin", + }, + .dirname = .{ + .path = "dirname", + }, + .empty_env = .{ + .path = "empty_env", + }, + .issue_11595 = .{ + .path = "issue_11595", + }, + .load_dynamic_library = .{ + .path = "load_dynamic_library", + }, + .windows_resources = .{ + .path = "windows_resources", + }, + .windows_entry_points = .{ + .path = "windows_entry_points", + }, + .windows_spawn = .{ + .path = "windows_spawn", + }, + .self_exe_symlink = .{ + .path = "self_exe_symlink", + }, + .c_compiler = .{ + .path = "c_compiler", + }, + .pie = .{ + .path = "pie", + }, + .issue_12706 = .{ + .path = "issue_12706", + }, + // TODO This test is disabled for doing naughty things in the build script. + // The logic needs to get moved to a child process instead of build.zig. + //.sigpipe = .{ + // .path = "sigpipe", + //}, + // TODO restore this test + //.options = .{ + // .path = "options", + //}, + .strip_empty_loop = .{ + .path = "strip_empty_loop", + }, + .strip_struct_init = .{ + .path = "strip_struct_init", + }, + .cmakedefine = .{ + .path = "cmakedefine", + }, + .zerolength_check = .{ + .path = "zerolength_check", + }, + .stack_iterator = .{ + .path = "stack_iterator", + }, + .coff_dwarf = .{ + .path = "coff_dwarf", + }, + .compiler_rt_panic = .{ + .path = "compiler_rt_panic", + }, + .ios = .{ + .path = "ios", + }, + .depend_on_main_mod = .{ + .path = "depend_on_main_mod", + }, + .install_headers = .{ + .path = "install_headers", + }, + }, + .paths = .{ + "build.zig", + "build.zig.zon", + }, +} diff --git a/test/standalone/cat/main.zig b/test/standalone/cat/main.zig deleted file mode 100644 index 740e73a33e21e027c5f7a2c87db83547e6cc152b..0000000000000000000000000000000000000000 --- a/test/standalone/cat/main.zig +++ /dev/null @@ -1,46 +0,0 @@ -const std = @import("std"); -const io = std.io; -const process = std.process; -const fs = std.fs; -const mem = std.mem; -const warn = std.log.warn; - -pub fn main() !void { - var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator); - defer arena_instance.deinit(); - const arena = arena_instance.allocator(); - - const args = try process.argsAlloc(arena); - - const exe = args[0]; - var catted_anything = false; - const stdout_file = io.getStdOut(); - - const cwd = fs.cwd(); - - for (args[1..]) |arg| { - if (mem.eql(u8, arg, "-")) { - catted_anything = true; - try stdout_file.writeFileAll(io.getStdIn(), .{}); - } else if (mem.startsWith(u8, arg, "-")) { - return usage(exe); - } else { - const file = cwd.openFile(arg, .{}) catch |err| { - warn("Unable to open file: {s}\n", .{@errorName(err)}); - return err; - }; - defer file.close(); - - catted_anything = true; - try stdout_file.writeFileAll(file, .{}); - } - } - if (!catted_anything) { - try stdout_file.writeFileAll(io.getStdIn(), .{}); - } -} - -fn usage(exe: []const u8) !void { - warn("Usage: {s} [FILE]...\n", .{exe}); - return error.Invalid; -} diff --git a/test/standalone/guess_number/main.zig b/test/standalone/guess_number/main.zig deleted file mode 100644 index ad848608703fd5eafc992c09259ebcc9463702d4..0000000000000000000000000000000000000000 --- a/test/standalone/guess_number/main.zig +++ /dev/null @@ -1,38 +0,0 @@ -const builtin = @import("builtin"); -const std = @import("std"); -const io = std.io; -const fmt = std.fmt; - -pub fn main() !void { - const stdout = io.getStdOut().writer(); - const stdin = io.getStdIn(); - - try stdout.print("Welcome to the Guess Number Game in Zig.\n", .{}); - - const answer = std.crypto.random.intRangeLessThan(u8, 0, 100) + 1; - - while (true) { - try stdout.print("\nGuess a number between 1 and 100: ", .{}); - var line_buf: [20]u8 = undefined; - - const amt = try stdin.read(&line_buf); - if (amt == line_buf.len) { - try stdout.print("Input too long.\n", .{}); - continue; - } - const line = std.mem.trimRight(u8, line_buf[0..amt], "\r\n"); - - const guess = fmt.parseUnsigned(u8, line, 10) catch { - try stdout.print("Invalid number.\n", .{}); - continue; - }; - if (guess > answer) { - try stdout.print("Guess lower.\n", .{}); - } else if (guess < answer) { - try stdout.print("Guess higher.\n", .{}); - } else { - try stdout.print("You win!\n", .{}); - return; - } - } -} diff --git a/test/standalone/hello_world/hello.zig b/test/standalone/hello_world/hello.zig deleted file mode 100644 index eabb226eb2ccd93b053baaa73d68f1c63dc46f5e..0000000000000000000000000000000000000000 --- a/test/standalone/hello_world/hello.zig +++ /dev/null @@ -1,5 +0,0 @@ -const std = @import("std"); - -pub fn main() !void { - try std.io.getStdOut().writeAll("Hello, World!\n"); -} diff --git a/test/standalone/hello_world/hello_libc.zig b/test/standalone/hello_world/hello_libc.zig deleted file mode 100644 index 992afd736e76f7e52bb71c3eb482f98a0526a2a9..0000000000000000000000000000000000000000 --- a/test/standalone/hello_world/hello_libc.zig +++ /dev/null @@ -1,15 +0,0 @@ -const c = @cImport({ - // See https://github.com/ziglang/zig/issues/515 - @cDefine("_NO_CRT_STDIO_INLINE", "1"); - @cInclude("stdio.h"); - @cInclude("string.h"); -}); - -const msg = "Hello, world!\n"; - -pub export fn main(argc: c_int, argv: **u8) c_int { - _ = argv; - _ = argc; - if (c.printf(msg) != @as(c_int, @intCast(c.strlen(msg)))) return -1; - return 0; -} diff --git a/test/standalone/issue_12471/main.zig b/test/standalone/issue_12471/main.zig deleted file mode 100644 index 08be1fd4713563e0e6051739aed33630f8c65501..0000000000000000000000000000000000000000 --- a/test/standalone/issue_12471/main.zig +++ /dev/null @@ -1,12 +0,0 @@ -const c = @cImport({ - @cDefine("FOO", "FOO"); - @cDefine("BAR", "FOO"); - - @cDefine("BAZ", "QUX"); - @cDefine("QUX", "QUX"); -}); - -pub fn main() u8 { - _ = c; - return 0; -} diff --git a/test/standalone/issue_7030.zig b/test/standalone/issue_7030.zig deleted file mode 100644 index 4d4a7279f6b19faf05bb479bb219a70e3dae382d..0000000000000000000000000000000000000000 --- a/test/standalone/issue_7030.zig +++ /dev/null @@ -1,21 +0,0 @@ -const std = @import("std"); - -pub const std_options = .{ - .logFn = log, -}; - -pub fn log( - comptime message_level: std.log.Level, - comptime scope: @Type(.EnumLiteral), - comptime format: []const u8, - args: anytype, -) void { - _ = message_level; - _ = scope; - _ = format; - _ = args; -} - -pub fn main() anyerror!void { - std.log.info("All your codebase are belong to us.", .{}); -} diff --git a/test/standalone/issue_9402/main.zig b/test/standalone/issue_9402/main.zig deleted file mode 100644 index eea6bbf4b5e145b7a62b525a2f66bb4cb92b08a5..0000000000000000000000000000000000000000 --- a/test/standalone/issue_9402/main.zig +++ /dev/null @@ -1,14 +0,0 @@ -const FILE = extern struct { - dummy_field: u8, -}; - -extern fn _ftelli64([*c]FILE) i64; -extern fn _fseeki64([*c]FILE, i64, c_int) c_int; - -pub export fn main(argc: c_int, argv: **u8) c_int { - _ = argv; - _ = argc; - _ = _ftelli64(null); - _ = _fseeki64(null, 123, 2); - return 0; -} diff --git a/test/standalone/main_return_error/error_u8.zig b/test/standalone/main_return_error/error_u8.zig deleted file mode 100644 index 8fbe1e8f6595e350964d9ba61e4c94091988fe9c..0000000000000000000000000000000000000000 --- a/test/standalone/main_return_error/error_u8.zig +++ /dev/null @@ -1,5 +0,0 @@ -const Err = error{Foo}; - -pub fn main() !u8 { - return Err.Foo; -} diff --git a/test/standalone/main_return_error/error_u8_non_zero.zig b/test/standalone/main_return_error/error_u8_non_zero.zig deleted file mode 100644 index 47fe7946ec1e4ce6fdd33a749fc11d313eb3f3ab..0000000000000000000000000000000000000000 --- a/test/standalone/main_return_error/error_u8_non_zero.zig +++ /dev/null @@ -1,10 +0,0 @@ -const Err = error{Foo}; - -fn foo() u8 { - return @intCast(9); -} - -pub fn main() !u8 { - if (foo() == 7) return Err.Foo; - return 123; -} diff --git a/test/standalone/noreturn_call/as_arg.zig b/test/standalone/noreturn_call/as_arg.zig deleted file mode 100644 index 08a4f0bd75803280775cd7644bec88b850e0b344..0000000000000000000000000000000000000000 --- a/test/standalone/noreturn_call/as_arg.zig +++ /dev/null @@ -1,8 +0,0 @@ -const std = @import("std"); -fn foo() noreturn { - std.process.exit(0); -} -fn bar(_: u8, _: u8) void {} -pub fn main() void { - bar(foo(), @compileError("bad")); -} diff --git a/test/standalone/noreturn_call/inline.zig b/test/standalone/noreturn_call/inline.zig deleted file mode 100644 index 436d97896a774f5a84fa344822c9668026c4a432..0000000000000000000000000000000000000000 --- a/test/standalone/noreturn_call/inline.zig +++ /dev/null @@ -1,10 +0,0 @@ -pub fn main() void { - _ = bar(); -} -inline fn bar() u8 { - noret(); -} -const std = @import("std"); -inline fn noret() noreturn { - std.process.exit(0); -} diff --git a/test/standalone/simple/brace_expansion.zig b/test/standalone/simple/brace_expansion.zig new file mode 100644 index 0000000000000000000000000000000000000000..7a769f6af7435c1f782a9676febf2dd91e557e23 --- /dev/null +++ b/test/standalone/simple/brace_expansion.zig @@ -0,0 +1,292 @@ +const std = @import("std"); +const io = std.io; +const mem = std.mem; +const debug = std.debug; +const assert = debug.assert; +const testing = std.testing; +const ArrayList = std.ArrayList; +const maxInt = std.math.maxInt; + +const Token = union(enum) { + Word: []const u8, + OpenBrace, + CloseBrace, + Comma, + Eof, +}; + +var gpa = std.heap.GeneralPurposeAllocator(.{}){}; +var global_allocator = gpa.allocator(); + +fn tokenize(input: []const u8) !ArrayList(Token) { + const State = enum { + Start, + Word, + }; + + var token_list = ArrayList(Token).init(global_allocator); + errdefer token_list.deinit(); + var tok_begin: usize = undefined; + var state = State.Start; + + for (input, 0..) |b, i| { + switch (state) { + .Start => switch (b) { + 'a'...'z', 'A'...'Z' => { + state = State.Word; + tok_begin = i; + }, + '{' => try token_list.append(Token.OpenBrace), + '}' => try token_list.append(Token.CloseBrace), + ',' => try token_list.append(Token.Comma), + else => return error.InvalidInput, + }, + .Word => switch (b) { + 'a'...'z', 'A'...'Z' => {}, + '{', '}', ',' => { + try token_list.append(Token{ .Word = input[tok_begin..i] }); + switch (b) { + '{' => try token_list.append(Token.OpenBrace), + '}' => try token_list.append(Token.CloseBrace), + ',' => try token_list.append(Token.Comma), + else => unreachable, + } + state = State.Start; + }, + else => return error.InvalidInput, + }, + } + } + switch (state) { + State.Start => {}, + State.Word => try token_list.append(Token{ .Word = input[tok_begin..] }), + } + try token_list.append(Token.Eof); + return token_list; +} + +const Node = union(enum) { + Scalar: []const u8, + List: ArrayList(Node), + Combine: []Node, + + fn deinit(self: Node) void { + switch (self) { + .Scalar => {}, + .Combine => |pair| { + pair[0].deinit(); + pair[1].deinit(); + global_allocator.free(pair); + }, + .List => |list| { + for (list.items) |item| { + item.deinit(); + } + list.deinit(); + }, + } + } +}; + +const ParseError = error{ + InvalidInput, + OutOfMemory, +}; + +fn parse(tokens: *const ArrayList(Token), token_index: *usize) ParseError!Node { + const first_token = tokens.items[token_index.*]; + token_index.* += 1; + + const result_node = switch (first_token) { + .Word => |word| Node{ .Scalar = word }, + .OpenBrace => blk: { + var list = ArrayList(Node).init(global_allocator); + errdefer { + for (list.items) |node| node.deinit(); + list.deinit(); + } + while (true) { + try list.append(try parse(tokens, token_index)); + + const token = tokens.items[token_index.*]; + token_index.* += 1; + + switch (token) { + .CloseBrace => break, + .Comma => continue, + else => return error.InvalidInput, + } + } + break :blk Node{ .List = list }; + }, + else => return error.InvalidInput, + }; + + switch (tokens.items[token_index.*]) { + .Word, .OpenBrace => { + const pair = try global_allocator.alloc(Node, 2); + errdefer global_allocator.free(pair); + pair[0] = result_node; + pair[1] = try parse(tokens, token_index); + return Node{ .Combine = pair }; + }, + else => return result_node, + } +} + +fn expandString(input: []const u8, output: *ArrayList(u8)) !void { + const tokens = try tokenize(input); + defer tokens.deinit(); + if (tokens.items.len == 1) { + return output.resize(0); + } + + var token_index: usize = 0; + const root = try parse(&tokens, &token_index); + defer root.deinit(); + const last_token = tokens.items[token_index]; + switch (last_token) { + Token.Eof => {}, + else => return error.InvalidInput, + } + + var result_list = ArrayList(ArrayList(u8)).init(global_allocator); + defer { + for (result_list.items) |*buf| buf.deinit(); + result_list.deinit(); + } + + try expandNode(root, &result_list); + + try output.resize(0); + for (result_list.items, 0..) |buf, i| { + if (i != 0) { + try output.append(' '); + } + try output.appendSlice(buf.items); + } +} + +const ExpandNodeError = error{OutOfMemory}; + +fn expandNode(node: Node, output: *ArrayList(ArrayList(u8))) ExpandNodeError!void { + assert(output.items.len == 0); + switch (node) { + .Scalar => |scalar| { + var list = ArrayList(u8).init(global_allocator); + errdefer list.deinit(); + try list.appendSlice(scalar); + try output.append(list); + }, + .Combine => |pair| { + const a_node = pair[0]; + const b_node = pair[1]; + + var child_list_a = ArrayList(ArrayList(u8)).init(global_allocator); + defer { + for (child_list_a.items) |*buf| buf.deinit(); + child_list_a.deinit(); + } + try expandNode(a_node, &child_list_a); + + var child_list_b = ArrayList(ArrayList(u8)).init(global_allocator); + defer { + for (child_list_b.items) |*buf| buf.deinit(); + child_list_b.deinit(); + } + try expandNode(b_node, &child_list_b); + + for (child_list_a.items) |buf_a| { + for (child_list_b.items) |buf_b| { + var combined_buf = ArrayList(u8).init(global_allocator); + errdefer combined_buf.deinit(); + + try combined_buf.appendSlice(buf_a.items); + try combined_buf.appendSlice(buf_b.items); + try output.append(combined_buf); + } + } + }, + .List => |list| { + for (list.items) |child_node| { + var child_list = ArrayList(ArrayList(u8)).init(global_allocator); + errdefer for (child_list.items) |*buf| buf.deinit(); + defer child_list.deinit(); + + try expandNode(child_node, &child_list); + + for (child_list.items) |buf| { + try output.append(buf); + } + } + }, + } +} + +pub fn main() !void { + defer _ = gpa.deinit(); + const stdin_file = io.getStdIn(); + const stdout_file = io.getStdOut(); + + const stdin = try stdin_file.reader().readAllAlloc(global_allocator, std.math.maxInt(usize)); + defer global_allocator.free(stdin); + + var result_buf = ArrayList(u8).init(global_allocator); + defer result_buf.deinit(); + + try expandString(stdin, &result_buf); + try stdout_file.writeAll(result_buf.items); +} + +test "invalid inputs" { + global_allocator = std.testing.allocator; + + try expectError("}ABC", error.InvalidInput); + try expectError("{ABC", error.InvalidInput); + try expectError("}{", error.InvalidInput); + try expectError("{}", error.InvalidInput); + try expectError("A,B,C", error.InvalidInput); + try expectError("{A{B,C}", error.InvalidInput); + try expectError("{A,}", error.InvalidInput); + + try expectError("\n", error.InvalidInput); +} + +fn expectError(test_input: []const u8, expected_err: anyerror) !void { + var output_buf = ArrayList(u8).init(global_allocator); + defer output_buf.deinit(); + + try testing.expectError(expected_err, expandString(test_input, &output_buf)); +} + +test "valid inputs" { + global_allocator = std.testing.allocator; + + try expectExpansion("{x,y,z}", "x y z"); + try expectExpansion("{A,B}{x,y}", "Ax Ay Bx By"); + try expectExpansion("{A,B{x,y}}", "A Bx By"); + + try expectExpansion("{ABC}", "ABC"); + try expectExpansion("{A,B,C}", "A B C"); + try expectExpansion("ABC", "ABC"); + + try expectExpansion("", ""); + try expectExpansion("{A,B}{C,{x,y}}{g,h}", "ACg ACh Axg Axh Ayg Ayh BCg BCh Bxg Bxh Byg Byh"); + try expectExpansion("{A,B}{C,C{x,y}}{g,h}", "ACg ACh ACxg ACxh ACyg ACyh BCg BCh BCxg BCxh BCyg BCyh"); + try expectExpansion("{A,B}a", "Aa Ba"); + try expectExpansion("{C,{x,y}}", "C x y"); + try expectExpansion("z{C,{x,y}}", "zC zx zy"); + try expectExpansion("a{b,c{d,e{f,g}}}", "ab acd acef aceg"); + try expectExpansion("a{x,y}b", "axb ayb"); + try expectExpansion("z{{a,b}}", "za zb"); + try expectExpansion("a{b}", "ab"); +} + +fn expectExpansion(test_input: []const u8, expected_result: []const u8) !void { + var result = ArrayList(u8).init(global_allocator); + defer result.deinit(); + + expandString(test_input, &result) catch unreachable; + + try testing.expectEqualSlices(u8, expected_result, result.items); +} diff --git a/test/standalone/simple/build.zig b/test/standalone/simple/build.zig new file mode 100644 index 0000000000000000000000000000000000000000..8bcfbe0fcac24d5329070b0fb68198d3b58ee481 --- /dev/null +++ b/test/standalone/simple/build.zig @@ -0,0 +1,123 @@ +const std = @import("std"); +const builtin = @import("builtin"); + +pub fn build(b: *std.Build) void { + const step = b.step("test", "Run simple standalone test cases"); + b.default_step = step; + + const skip_debug = b.option(bool, "skip_debug", "Skip debug builds") orelse false; + const skip_release_safe = b.option(bool, "skip_release_safe", "Skip release-safe builds") orelse false; + const skip_release_fast = b.option(bool, "skip_release_fast", "Skip release-fast builds") orelse false; + const skip_release_small = b.option(bool, "skip_release_small", "Skip release-small builds") orelse false; + + var optimize_modes_buf: [4]std.builtin.OptimizeMode = undefined; + var optimize_modes_len: usize = 0; + if (!skip_debug) { + optimize_modes_buf[optimize_modes_len] = .Debug; + optimize_modes_len += 1; + } + if (!skip_release_safe) { + optimize_modes_buf[optimize_modes_len] = .ReleaseSafe; + optimize_modes_len += 1; + } + if (!skip_release_fast) { + optimize_modes_buf[optimize_modes_len] = .ReleaseFast; + optimize_modes_len += 1; + } + if (!skip_release_small) { + optimize_modes_buf[optimize_modes_len] = .ReleaseSmall; + optimize_modes_len += 1; + } + const optimize_modes = optimize_modes_buf[0..optimize_modes_len]; + + for (cases) |case| { + for (optimize_modes) |optimize| { + if (!case.all_modes and optimize != .Debug) continue; + if (case.os_filter) |os_tag| { + if (os_tag != builtin.os.tag) continue; + } + + const resolved_target = b.resolveTargetQuery(case.target); + + if (case.is_exe) { + const exe = b.addExecutable(.{ + .name = std.fs.path.stem(case.src_path), + .root_source_file = .{ .path = case.src_path }, + .optimize = optimize, + .target = resolved_target, + }); + if (case.link_libc) exe.linkLibC(); + + _ = exe.getEmittedBin(); + + step.dependOn(&exe.step); + } + + if (case.is_test) { + const exe = b.addTest(.{ + .name = std.fs.path.stem(case.src_path), + .root_source_file = .{ .path = case.src_path }, + .optimize = optimize, + .target = resolved_target, + }); + if (case.link_libc) exe.linkLibC(); + + const run = b.addRunArtifact(exe); + step.dependOn(&run.step); + } + } + } +} + +const Case = struct { + src_path: []const u8, + link_libc: bool = false, + all_modes: bool = false, + target: std.Target.Query = .{}, + is_test: bool = false, + is_exe: bool = true, + /// Run only on this OS. + os_filter: ?std.Target.Os.Tag = null, +}; + +const cases = [_]Case{ + .{ + .src_path = "hello_world/hello.zig", + .all_modes = true, + }, + .{ + .src_path = "hello_world/hello_libc.zig", + .link_libc = true, + .all_modes = true, + }, + .{ + .src_path = "cat/main.zig", + }, + // https://github.com/ziglang/zig/issues/6025 + //.{ + // .src_path = "issue_9693/main.zig", + //}, + .{ + .src_path = "brace_expansion.zig", + .is_test = true, + }, + .{ + .src_path = "issue_7030.zig", + .target = .{ + .cpu_arch = .wasm32, + .os_tag = .freestanding, + }, + }, + .{ .src_path = "issue_12471/main.zig" }, + .{ .src_path = "guess_number/main.zig" }, + .{ .src_path = "main_return_error/error_u8.zig" }, + .{ .src_path = "main_return_error/error_u8_non_zero.zig" }, + .{ .src_path = "noreturn_call/inline.zig" }, + .{ .src_path = "noreturn_call/as_arg.zig" }, + .{ .src_path = "std_enums_big_enums.zig" }, + .{ + .src_path = "issue_9402/main.zig", + .os_filter = .windows, + .link_libc = true, + }, +}; diff --git a/test/standalone/simple/cat/main.zig b/test/standalone/simple/cat/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..740e73a33e21e027c5f7a2c87db83547e6cc152b --- /dev/null +++ b/test/standalone/simple/cat/main.zig @@ -0,0 +1,46 @@ +const std = @import("std"); +const io = std.io; +const process = std.process; +const fs = std.fs; +const mem = std.mem; +const warn = std.log.warn; + +pub fn main() !void { + var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer arena_instance.deinit(); + const arena = arena_instance.allocator(); + + const args = try process.argsAlloc(arena); + + const exe = args[0]; + var catted_anything = false; + const stdout_file = io.getStdOut(); + + const cwd = fs.cwd(); + + for (args[1..]) |arg| { + if (mem.eql(u8, arg, "-")) { + catted_anything = true; + try stdout_file.writeFileAll(io.getStdIn(), .{}); + } else if (mem.startsWith(u8, arg, "-")) { + return usage(exe); + } else { + const file = cwd.openFile(arg, .{}) catch |err| { + warn("Unable to open file: {s}\n", .{@errorName(err)}); + return err; + }; + defer file.close(); + + catted_anything = true; + try stdout_file.writeFileAll(file, .{}); + } + } + if (!catted_anything) { + try stdout_file.writeFileAll(io.getStdIn(), .{}); + } +} + +fn usage(exe: []const u8) !void { + warn("Usage: {s} [FILE]...\n", .{exe}); + return error.Invalid; +} diff --git a/test/standalone/simple/guess_number/main.zig b/test/standalone/simple/guess_number/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..ad848608703fd5eafc992c09259ebcc9463702d4 --- /dev/null +++ b/test/standalone/simple/guess_number/main.zig @@ -0,0 +1,38 @@ +const builtin = @import("builtin"); +const std = @import("std"); +const io = std.io; +const fmt = std.fmt; + +pub fn main() !void { + const stdout = io.getStdOut().writer(); + const stdin = io.getStdIn(); + + try stdout.print("Welcome to the Guess Number Game in Zig.\n", .{}); + + const answer = std.crypto.random.intRangeLessThan(u8, 0, 100) + 1; + + while (true) { + try stdout.print("\nGuess a number between 1 and 100: ", .{}); + var line_buf: [20]u8 = undefined; + + const amt = try stdin.read(&line_buf); + if (amt == line_buf.len) { + try stdout.print("Input too long.\n", .{}); + continue; + } + const line = std.mem.trimRight(u8, line_buf[0..amt], "\r\n"); + + const guess = fmt.parseUnsigned(u8, line, 10) catch { + try stdout.print("Invalid number.\n", .{}); + continue; + }; + if (guess > answer) { + try stdout.print("Guess lower.\n", .{}); + } else if (guess < answer) { + try stdout.print("Guess higher.\n", .{}); + } else { + try stdout.print("You win!\n", .{}); + return; + } + } +} diff --git a/test/standalone/simple/hello_world/hello.zig b/test/standalone/simple/hello_world/hello.zig new file mode 100644 index 0000000000000000000000000000000000000000..eabb226eb2ccd93b053baaa73d68f1c63dc46f5e --- /dev/null +++ b/test/standalone/simple/hello_world/hello.zig @@ -0,0 +1,5 @@ +const std = @import("std"); + +pub fn main() !void { + try std.io.getStdOut().writeAll("Hello, World!\n"); +} diff --git a/test/standalone/simple/hello_world/hello_libc.zig b/test/standalone/simple/hello_world/hello_libc.zig new file mode 100644 index 0000000000000000000000000000000000000000..992afd736e76f7e52bb71c3eb482f98a0526a2a9 --- /dev/null +++ b/test/standalone/simple/hello_world/hello_libc.zig @@ -0,0 +1,15 @@ +const c = @cImport({ + // See https://github.com/ziglang/zig/issues/515 + @cDefine("_NO_CRT_STDIO_INLINE", "1"); + @cInclude("stdio.h"); + @cInclude("string.h"); +}); + +const msg = "Hello, world!\n"; + +pub export fn main(argc: c_int, argv: **u8) c_int { + _ = argv; + _ = argc; + if (c.printf(msg) != @as(c_int, @intCast(c.strlen(msg)))) return -1; + return 0; +} diff --git a/test/standalone/simple/issue_12471/main.zig b/test/standalone/simple/issue_12471/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..08be1fd4713563e0e6051739aed33630f8c65501 --- /dev/null +++ b/test/standalone/simple/issue_12471/main.zig @@ -0,0 +1,12 @@ +const c = @cImport({ + @cDefine("FOO", "FOO"); + @cDefine("BAR", "FOO"); + + @cDefine("BAZ", "QUX"); + @cDefine("QUX", "QUX"); +}); + +pub fn main() u8 { + _ = c; + return 0; +} diff --git a/test/standalone/simple/issue_7030.zig b/test/standalone/simple/issue_7030.zig new file mode 100644 index 0000000000000000000000000000000000000000..4d4a7279f6b19faf05bb479bb219a70e3dae382d --- /dev/null +++ b/test/standalone/simple/issue_7030.zig @@ -0,0 +1,21 @@ +const std = @import("std"); + +pub const std_options = .{ + .logFn = log, +}; + +pub fn log( + comptime message_level: std.log.Level, + comptime scope: @Type(.EnumLiteral), + comptime format: []const u8, + args: anytype, +) void { + _ = message_level; + _ = scope; + _ = format; + _ = args; +} + +pub fn main() anyerror!void { + std.log.info("All your codebase are belong to us.", .{}); +} diff --git a/test/standalone/simple/issue_9402/main.zig b/test/standalone/simple/issue_9402/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..eea6bbf4b5e145b7a62b525a2f66bb4cb92b08a5 --- /dev/null +++ b/test/standalone/simple/issue_9402/main.zig @@ -0,0 +1,14 @@ +const FILE = extern struct { + dummy_field: u8, +}; + +extern fn _ftelli64([*c]FILE) i64; +extern fn _fseeki64([*c]FILE, i64, c_int) c_int; + +pub export fn main(argc: c_int, argv: **u8) c_int { + _ = argv; + _ = argc; + _ = _ftelli64(null); + _ = _fseeki64(null, 123, 2); + return 0; +} diff --git a/test/standalone/simple/main_return_error/error_u8.zig b/test/standalone/simple/main_return_error/error_u8.zig new file mode 100644 index 0000000000000000000000000000000000000000..8fbe1e8f6595e350964d9ba61e4c94091988fe9c --- /dev/null +++ b/test/standalone/simple/main_return_error/error_u8.zig @@ -0,0 +1,5 @@ +const Err = error{Foo}; + +pub fn main() !u8 { + return Err.Foo; +} diff --git a/test/standalone/simple/main_return_error/error_u8_non_zero.zig b/test/standalone/simple/main_return_error/error_u8_non_zero.zig new file mode 100644 index 0000000000000000000000000000000000000000..47fe7946ec1e4ce6fdd33a749fc11d313eb3f3ab --- /dev/null +++ b/test/standalone/simple/main_return_error/error_u8_non_zero.zig @@ -0,0 +1,10 @@ +const Err = error{Foo}; + +fn foo() u8 { + return @intCast(9); +} + +pub fn main() !u8 { + if (foo() == 7) return Err.Foo; + return 123; +} diff --git a/test/standalone/simple/noreturn_call/as_arg.zig b/test/standalone/simple/noreturn_call/as_arg.zig new file mode 100644 index 0000000000000000000000000000000000000000..08a4f0bd75803280775cd7644bec88b850e0b344 --- /dev/null +++ b/test/standalone/simple/noreturn_call/as_arg.zig @@ -0,0 +1,8 @@ +const std = @import("std"); +fn foo() noreturn { + std.process.exit(0); +} +fn bar(_: u8, _: u8) void {} +pub fn main() void { + bar(foo(), @compileError("bad")); +} diff --git a/test/standalone/simple/noreturn_call/inline.zig b/test/standalone/simple/noreturn_call/inline.zig new file mode 100644 index 0000000000000000000000000000000000000000..436d97896a774f5a84fa344822c9668026c4a432 --- /dev/null +++ b/test/standalone/simple/noreturn_call/inline.zig @@ -0,0 +1,10 @@ +pub fn main() void { + _ = bar(); +} +inline fn bar() u8 { + noret(); +} +const std = @import("std"); +inline fn noret() noreturn { + std.process.exit(0); +} diff --git a/test/standalone/simple/std_enums_big_enums.zig b/test/standalone/simple/std_enums_big_enums.zig new file mode 100644 index 0000000000000000000000000000000000000000..76237d3447a06a5125b1fe03cd1305aa2f8cc198 --- /dev/null +++ b/test/standalone/simple/std_enums_big_enums.zig @@ -0,0 +1,38 @@ +const std = @import("std"); + +// big enums should not hit the eval branch quota +pub fn main() void { + const big = struct { + const Big = @Type(@as(std.builtin.Type, .{ + .Enum = .{ + .tag_type = u16, + .fields = make_fields: { + var fields: [1001]std.builtin.Type.EnumField = undefined; + for (&fields, 0..) |*field, i| { + field.* = .{ .name = std.fmt.comptimePrint("field_{d}", .{i}), .value = i }; + } + fields[1000] = .{ .name = "field_9999", .value = 9999 }; + break :make_fields &fields; + }, + .decls = &.{}, + .is_exhaustive = true, + }, + })); + }; + + var set = std.enums.EnumSet(big.Big).init(.{}); + _ = &set; + + var map = std.enums.EnumMap(big.Big, u8).init(undefined); + map = std.enums.EnumMap(big.Big, u8).initFullWith(undefined); + map = std.enums.EnumMap(big.Big, u8).initFullWithDefault(123, .{}); + + var multiset = std.enums.EnumMultiset(big.Big).init(.{}); + _ = &multiset; + + var bounded_multiset = std.enums.BoundedEnumMultiset(big.Big, u8).init(.{}); + _ = &bounded_multiset; + + var array = std.enums.EnumArray(big.Big, u8).init(undefined); + array = std.enums.EnumArray(big.Big, u8).initDefault(123, .{}); +} diff --git a/test/standalone/std_enums_big_enums.zig b/test/standalone/std_enums_big_enums.zig deleted file mode 100644 index 76237d3447a06a5125b1fe03cd1305aa2f8cc198..0000000000000000000000000000000000000000 --- a/test/standalone/std_enums_big_enums.zig +++ /dev/null @@ -1,38 +0,0 @@ -const std = @import("std"); - -// big enums should not hit the eval branch quota -pub fn main() void { - const big = struct { - const Big = @Type(@as(std.builtin.Type, .{ - .Enum = .{ - .tag_type = u16, - .fields = make_fields: { - var fields: [1001]std.builtin.Type.EnumField = undefined; - for (&fields, 0..) |*field, i| { - field.* = .{ .name = std.fmt.comptimePrint("field_{d}", .{i}), .value = i }; - } - fields[1000] = .{ .name = "field_9999", .value = 9999 }; - break :make_fields &fields; - }, - .decls = &.{}, - .is_exhaustive = true, - }, - })); - }; - - var set = std.enums.EnumSet(big.Big).init(.{}); - _ = &set; - - var map = std.enums.EnumMap(big.Big, u8).init(undefined); - map = std.enums.EnumMap(big.Big, u8).initFullWith(undefined); - map = std.enums.EnumMap(big.Big, u8).initFullWithDefault(123, .{}); - - var multiset = std.enums.EnumMultiset(big.Big).init(.{}); - _ = &multiset; - - var bounded_multiset = std.enums.BoundedEnumMultiset(big.Big, u8).init(.{}); - _ = &bounded_multiset; - - var array = std.enums.EnumArray(big.Big, u8).init(undefined); - array = std.enums.EnumArray(big.Big, u8).initDefault(123, .{}); -} diff --git a/test/tests.zig b/test/tests.zig index 0c847e6e7faca6fcea121c7f837b47c8c6c8f679..286ac7e91ce69c2f674d81bfcaa8996583f89bd5 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -7,12 +7,10 @@ const Step = std.Build.Step; // Cases const compare_output = @import("compare_output.zig"); -const standalone = @import("standalone.zig"); const stack_traces = @import("stack_traces.zig"); const assemble_and_link = @import("assemble_and_link.zig"); const translate_c = @import("translate_c.zig"); const run_translated_c = @import("run_translated_c.zig"); -const link = @import("link.zig"); // Implementations pub const TranslateCContext = @import("src/TranslateC.zig"); @@ -663,79 +661,35 @@ pub fn addStackTraceTests( return cases.step; } +fn compilerHasPackageManager(b: *std.Build) bool { + // We can only use dependencies if the compiler was built with support for package management. + // (zig2 doesn't support it, but we still need to construct a build graph to build stage3.) + return b.available_deps.len != 0; +} + pub fn addStandaloneTests( b: *std.Build, optimize_modes: []const OptimizeMode, enable_macos_sdk: bool, enable_ios_sdk: bool, - omit_stage2: bool, enable_symlinks_windows: bool, ) *Step { const step = b.step("test-standalone", "Run the standalone tests"); - const omit_symlinks = builtin.os.tag == .windows and !enable_symlinks_windows; - - for (standalone.simple_cases) |case| { - for (optimize_modes) |optimize| { - if (!case.all_modes and optimize != .Debug) continue; - if (case.os_filter) |os_tag| { - if (os_tag != builtin.os.tag) continue; - } - - const resolved_target = b.resolveTargetQuery(case.target); - - if (case.is_exe) { - const exe = b.addExecutable(.{ - .name = std.fs.path.stem(case.src_path), - .root_source_file = .{ .path = case.src_path }, - .optimize = optimize, - .target = resolved_target, - }); - if (case.link_libc) exe.linkLibC(); - - _ = exe.getEmittedBin(); - - step.dependOn(&exe.step); - } - - if (case.is_test) { - const exe = b.addTest(.{ - .name = std.fs.path.stem(case.src_path), - .root_source_file = .{ .path = case.src_path }, - .optimize = optimize, - .target = resolved_target, - }); - if (case.link_libc) exe.linkLibC(); - - const run = b.addRunArtifact(exe); - step.dependOn(&run.step); - } - } + if (compilerHasPackageManager(b)) { + const test_cases_dep_name = "standalone_test_cases"; + const test_cases_dep = b.dependency(test_cases_dep_name, .{ + .enable_ios_sdk = enable_ios_sdk, + .enable_macos_sdk = enable_macos_sdk, + .enable_symlinks_windows = enable_symlinks_windows, + .simple_skip_debug = mem.indexOfScalar(OptimizeMode, optimize_modes, .Debug) == null, + .simple_skip_release_safe = mem.indexOfScalar(OptimizeMode, optimize_modes, .ReleaseSafe) == null, + .simple_skip_release_fast = mem.indexOfScalar(OptimizeMode, optimize_modes, .ReleaseFast) == null, + .simple_skip_release_small = mem.indexOfScalar(OptimizeMode, optimize_modes, .ReleaseSmall) == null, + }); + const test_cases_dep_step = test_cases_dep.builder.default_step; + test_cases_dep_step.name = b.dupe(test_cases_dep_name); + step.dependOn(test_cases_dep.builder.default_step); } - - inline for (standalone.build_cases) |case| { - const requires_stage2 = @hasDecl(case.import, "requires_stage2") and - case.import.requires_stage2; - const requires_symlinks = @hasDecl(case.import, "requires_symlinks") and - case.import.requires_symlinks; - const requires_macos_sdk = @hasDecl(case.import, "requires_macos_sdk") and - case.import.requires_macos_sdk; - const requires_ios_sdk = @hasDecl(case.import, "requires_ios_sdk") and - case.import.requires_ios_sdk; - const bad = - (requires_stage2 and omit_stage2) or - (requires_symlinks and omit_symlinks) or - (requires_macos_sdk and !enable_macos_sdk) or - (requires_ios_sdk and !enable_ios_sdk); - if (!bad) { - const dep = b.anonymousDependency(case.build_root, case.import, .{}); - const dep_step = dep.builder.default_step; - assert(mem.startsWith(u8, dep.builder.dep_prefix, "test.")); - const dep_prefix_adjusted = dep.builder.dep_prefix["test.".len..]; - dep_step.name = b.fmt("{s}{s}", .{ dep_prefix_adjusted, dep_step.name }); - step.dependOn(dep_step); - } - } - return step; } @@ -743,49 +697,20 @@ pub fn addLinkTests( b: *std.Build, enable_macos_sdk: bool, enable_ios_sdk: bool, - omit_stage2: bool, enable_symlinks_windows: bool, ) *Step { const step = b.step("test-link", "Run the linker tests"); - const omit_symlinks = builtin.os.tag == .windows and !enable_symlinks_windows; - - inline for (link.cases) |case| { - if (mem.eql(u8, @typeName(case.import), "test.link.link")) { - const dep = b.anonymousDependency(case.build_root, case.import, .{ - .has_macos_sdk = enable_macos_sdk, - .has_ios_sdk = enable_ios_sdk, - .has_symlinks_windows = !omit_symlinks, - }); - const dep_step = dep.builder.default_step; - assert(mem.startsWith(u8, dep.builder.dep_prefix, "test.")); - const dep_prefix_adjusted = dep.builder.dep_prefix["test.".len..]; - dep_step.name = b.fmt("{s}{s}", .{ dep_prefix_adjusted, dep_step.name }); - step.dependOn(dep_step); - } else { - const requires_stage2 = @hasDecl(case.import, "requires_stage2") and - case.import.requires_stage2; - const requires_symlinks = @hasDecl(case.import, "requires_symlinks") and - case.import.requires_symlinks; - const requires_macos_sdk = @hasDecl(case.import, "requires_macos_sdk") and - case.import.requires_macos_sdk; - const requires_ios_sdk = @hasDecl(case.import, "requires_ios_sdk") and - case.import.requires_ios_sdk; - const bad = - (requires_stage2 and omit_stage2) or - (requires_symlinks and omit_symlinks) or - (requires_macos_sdk and !enable_macos_sdk) or - (requires_ios_sdk and !enable_ios_sdk); - if (!bad) { - const dep = b.anonymousDependency(case.build_root, case.import, .{}); - const dep_step = dep.builder.default_step; - assert(mem.startsWith(u8, dep.builder.dep_prefix, "test.")); - const dep_prefix_adjusted = dep.builder.dep_prefix["test.".len..]; - dep_step.name = b.fmt("{s}{s}", .{ dep_prefix_adjusted, dep_step.name }); - step.dependOn(dep_step); - } - } + if (compilerHasPackageManager(b)) { + const test_cases_dep_name = "link_test_cases"; + const test_cases_dep = b.dependency(test_cases_dep_name, .{ + .enable_ios_sdk = enable_ios_sdk, + .enable_macos_sdk = enable_macos_sdk, + .enable_symlinks_windows = enable_symlinks_windows, + }); + const test_cases_dep_step = test_cases_dep.builder.default_step; + test_cases_dep_step.name = b.dupe(test_cases_dep_name); + step.dependOn(test_cases_dep.builder.default_step); } - return step; }