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-15 09:47:43-07:00
log29717fefb8e951561bd51fdcea54ec62af3fd7dd
tree356c0aec74f2c53fe12f924a79f04aea3a7401ca
parentda32e05a1ccdeb9ede15405a599893b643ff474e

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 {
2929 }
3030 }
3131 } 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())) {
3333 if (is_wasm) {
3434 @export(&mainWithoutEnv, .{ .name = "__main_argc_argv" });
3535 } else if (!@typeInfo(@TypeOf(root.main)).@"fn".attrs.@"callconv".eql(.c)) {
3636 @export(&main, .{ .name = "main" });
3737 }
38 } else if (native_os == .windows and builtin.link_libc and @hasDecl(root, "wWinMain")) {
39 if (!@typeInfo(@TypeOf(root.wWinMain)).@"fn".attrs.@"callconv".eql(.c)) {
40 @export(&wWinMain, .{ .name = "wWinMain" });
41 }
42 } else if (native_os == .windows) {
43 if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
44 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
45 {
46 @export(&WinStartup, .{ .name = "wWinMainCRTStartup" });
47 } else if (@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
48 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
49 {
50 @compileError("WinMain not supported; declare wWinMain or main instead");
51 } else if (@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup") and
52 !@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup"))
53 {
54 @export(&wWinMainCRTStartup, .{ .name = "wWinMainCRTStartup" });
55 }
56 } else if (native_os == .uefi) {
57 if (!@hasDecl(root, "EfiMain")) @export(&EfiMain, .{ .name = "EfiMain" });
58 } else if (native_os == .wasi) {
59 const wasm_start_sym = switch (builtin.wasi_exec_model) {
60 .reactor => "_initialize",
61 .command => "_start",
62 };
63 if (!@hasDecl(root, wasm_start_sym) and @hasDecl(root, "main")) {
38 } else switch (native_os) {
39 .windows => {
40 if (builtin.link_libc and @hasDecl(root, "wWinMain")) {
41 if (!@typeInfo(@TypeOf(root.wWinMain)).@"fn".attrs.@"callconv".eql(.c)) {
42 @export(&wWinMain, .{ .name = "wWinMain" });
43 }
44 } else if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
45 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
46 {
47 @export(&WinStartup, .{ .name = "wWinMainCRTStartup" });
48 } else if (@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
49 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
50 {
51 @compileError("WinMain not supported; declare wWinMain or main instead");
52 } else if (@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup") and
53 !@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup"))
54 {
55 @export(&wWinMainCRTStartup, .{ .name = "wWinMainCRTStartup" });
56 }
57 },
58
59 .uefi => {
60 if (!@hasDecl(root, "EfiMain")) @export(&EfiMain, .{ .name = "EfiMain" });
61 },
62 .wasi => {
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) {
6474 // Only call main when defined. For WebAssembly it's allowed to pass `-fno-entry` in which
6575 // case it's not required to provide an entrypoint such as main.
66 @export(&startWasi, .{ .name = wasm_start_sym });
67 }
68 } else if (is_wasm and native_os == .freestanding) {
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) {
76 if (!@hasDecl(root, start_sym_name) and @hasDecl(root, "main"))
77 @export(&wasm_freestanding_start, .{ .name = start_sym_name });
78 },
7379 .other,
74 .freestanding,
7580 .vulkan,
7681 .opengl,
7782 .opencl,
......@@ -85,6 +90,7 @@ comptime {
8590 .psp,
8691 .vita,
8792 => {},
93
8894 else => if (!@hasDecl(root, start_sym_name)) @export(&_start, .{ .name = start_sym_name }),
8995 }
9096 }