authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-10-14 15:30:56-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-10-16 03:26:50+02:00
logbd51e91a9a934c915219b985549bb4fc060c0357
tree87c1042cd2e2271d7ed0109be92692acc4038cab
parent661354b8ebe0160554c08ea56383875243845f0a

start code: flatten and improve missing pub fn main message

better error message when the programmer omits `main` or fails to make it public. closes #37113

1 files changed, 41 insertions(+), 35 deletions(-)

lib/std/start.zig+41-35
...@@ -29,49 +29,54 @@ comptime {...@@ -29,49 +29,54 @@ comptime {
29 }29 }
30 }30 }
31 } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) {31 } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) {
32 if (builtin.link_libc and @hasDecl(root, "main")) {32 if (builtin.link_libc and (@hasDecl(root, "main") or std.os.requiresLibC())) {
33 if (is_wasm) {33 if (is_wasm) {
34 @export(&mainWithoutEnv, .{ .name = "__main_argc_argv" });34 @export(&mainWithoutEnv, .{ .name = "__main_argc_argv" });
35 } else if (!@typeInfo(@TypeOf(root.main)).@"fn".attrs.@"callconv".eql(.c)) {35 } else if (!@typeInfo(@TypeOf(root.main)).@"fn".attrs.@"callconv".eql(.c)) {
36 @export(&main, .{ .name = "main" });36 @export(&main, .{ .name = "main" });
37 }37 }
38 } else if (native_os == .windows and builtin.link_libc and @hasDecl(root, "wWinMain")) {38 } else switch (native_os) {
39 if (!@typeInfo(@TypeOf(root.wWinMain)).@"fn".attrs.@"callconv".eql(.c)) {39 .windows => {
40 @export(&wWinMain, .{ .name = "wWinMain" });40 if (builtin.link_libc and @hasDecl(root, "wWinMain")) {
41 }41 if (!@typeInfo(@TypeOf(root.wWinMain)).@"fn".attrs.@"callconv".eql(.c)) {
42 } else if (native_os == .windows) {42 @export(&wWinMain, .{ .name = "wWinMain" });
43 if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and43 }
44 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))44 } else if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
45 {45 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
46 @export(&WinStartup, .{ .name = "wWinMainCRTStartup" });46 {
47 } else if (@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and47 @export(&WinStartup, .{ .name = "wWinMainCRTStartup" });
48 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))48 } else if (@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
49 {49 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
50 @compileError("WinMain not supported; declare wWinMain or main instead");50 {
51 } else if (@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup") and51 @compileError("WinMain not supported; declare wWinMain or main instead");
52 !@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup"))52 } else if (@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup") and
53 {53 !@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup"))
54 @export(&wWinMainCRTStartup, .{ .name = "wWinMainCRTStartup" });54 {
55 }55 @export(&wWinMainCRTStartup, .{ .name = "wWinMainCRTStartup" });
56 } else if (native_os == .uefi) {56 }
57 if (!@hasDecl(root, "EfiMain")) @export(&EfiMain, .{ .name = "EfiMain" });57 },
58 } else if (native_os == .wasi) {58
59 const wasm_start_sym = switch (builtin.wasi_exec_model) {59 .uefi => {
60 .reactor => "_initialize",60 if (!@hasDecl(root, "EfiMain")) @export(&EfiMain, .{ .name = "EfiMain" });
61 .command => "_start",61 },
62 };62 .wasi => {
63 if (!@hasDecl(root, wasm_start_sym) and @hasDecl(root, "main")) {63 const wasm_start_sym = switch (builtin.wasi_exec_model) {
64 .reactor => "_initialize",
65 .command => "_start",
66 };
67 if (!@hasDecl(root, wasm_start_sym) and @hasDecl(root, "main")) {
68 // Only call main when defined. For WebAssembly it's allowed to pass `-fno-entry` in which
69 // case it's not required to provide an entrypoint such as main.
70 @export(&startWasi, .{ .name = wasm_start_sym });
71 }
72 },
73 .freestanding => if (is_wasm) {
64 // Only call main when defined. For WebAssembly it's allowed to pass `-fno-entry` in which74 // Only call main when defined. For WebAssembly it's allowed to pass `-fno-entry` in which
65 // case it's not required to provide an entrypoint such as main.75 // case it's not required to provide an entrypoint such as main.
66 @export(&startWasi, .{ .name = wasm_start_sym });76 if (!@hasDecl(root, start_sym_name) and @hasDecl(root, "main"))
67 }77 @export(&wasm_freestanding_start, .{ .name = start_sym_name });
68 } else if (is_wasm and native_os == .freestanding) {78 },
69 // Only call main when defined. For WebAssembly it's allowed to pass `-fno-entry` in which
70 // case it's not required to provide an entrypoint such as main.
71 if (!@hasDecl(root, start_sym_name) and @hasDecl(root, "main")) @export(&wasm_freestanding_start, .{ .name = start_sym_name });
72 } else switch (native_os) {
73 .other,79 .other,
74 .freestanding,
75 .vulkan,80 .vulkan,
76 .opengl,81 .opengl,
77 .opencl,82 .opencl,
...@@ -85,6 +90,7 @@ comptime {...@@ -85,6 +90,7 @@ comptime {
85 .psp,90 .psp,
86 .vita,91 .vita,
87 => {},92 => {},
93
88 else => if (!@hasDecl(root, start_sym_name)) @export(&_start, .{ .name = start_sym_name }),94 else => if (!@hasDecl(root, start_sym_name)) @export(&_start, .{ .name = start_sym_name }),
89 }95 }
90 }96 }