Skip to content

Commit 38791ac

Browse files
committed
Merge branch 'Vexu-build-start'
closes #3810 closes #3793 closes #3798
2 parents fd7c7be + 521744b commit 38791ac

File tree

10 files changed

+87
-124
lines changed

10 files changed

+87
-124
lines changed

lib/std/builtin.zig

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ pub const subsystem: ?SubSystem = blk: {
2626
if (is_test) {
2727
break :blk SubSystem.Console;
2828
}
29-
if (@hasDecl(root, "WinMain") or
29+
if (@hasDecl(root, "main") or
30+
@hasDecl(root, "WinMain") or
3031
@hasDecl(root, "wWinMain") or
3132
@hasDecl(root, "WinMainCRTStartup") or
3233
@hasDecl(root, "wWinMainCRTStartup"))
@@ -348,6 +349,21 @@ pub const Endian = enum {
348349
Little,
349350
};
350351

352+
/// This data structure is used by the Zig language code generation and
353+
/// therefore must be kept in sync with the compiler implementation.
354+
pub const OutputMode = enum {
355+
Exe,
356+
Lib,
357+
Obj,
358+
};
359+
360+
/// This data structure is used by the Zig language code generation and
361+
/// therefore must be kept in sync with the compiler implementation.
362+
pub const LinkMode = enum {
363+
Static,
364+
Dynamic,
365+
};
366+
351367
/// This data structure is used by the Zig language code generation and
352368
/// therefore must be kept in sync with the compiler implementation.
353369
pub const Version = struct {

lib/std/special/start.zig

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,43 @@ const is_mips = switch (builtin.arch) {
1919
};
2020

2121
comptime {
22-
if (builtin.link_libc) {
23-
@export("main", main, .Strong);
24-
} else if (builtin.os == .windows) {
25-
@export("WinMainCRTStartup", WinMainCRTStartup, .Strong);
26-
} else if (is_wasm and builtin.os == .freestanding) {
27-
@export("_start", wasm_freestanding_start, .Strong);
28-
} else if (builtin.os == .uefi) {
29-
@export("EfiMain", EfiMain, .Strong);
30-
} else if (is_mips) {
31-
if (!@hasDecl(root, "__start")) @export("__start", _start, .Strong);
32-
} else {
33-
if (!@hasDecl(root, "_start")) @export("_start", _start, .Strong);
22+
if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) {
23+
if (builtin.os == .windows and !@hasDecl(root, "_DllMainCRTStartup")) {
24+
@export("_DllMainCRTStartup", _DllMainCRTStartup, .Strong);
25+
}
26+
} else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) {
27+
if (builtin.link_libc and @hasDecl(root, "main")) {
28+
if (@typeInfo(@typeOf(root.main)).Fn.calling_convention != .C) {
29+
@export("main", main, .Weak);
30+
}
31+
} else if (builtin.os == .windows) {
32+
if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup")) {
33+
@export("WinMainCRTStartup", WinMainCRTStartup, .Strong);
34+
}
35+
} else if (is_wasm and builtin.os == .freestanding) {
36+
if (!@hasDecl(root, "_start")) @export("_start", wasm_freestanding_start, .Strong);
37+
} else if (builtin.os == .uefi) {
38+
if (!@hasDecl(root, "EfiMain")) @export("EfiMain", EfiMain, .Strong);
39+
} else if (is_mips) {
40+
if (!@hasDecl(root, "__start")) @export("__start", _start, .Strong);
41+
} else {
42+
if (!@hasDecl(root, "_start")) @export("_start", _start, .Strong);
43+
}
3444
}
3545
}
3646

47+
stdcallcc fn _DllMainCRTStartup(
48+
hinstDLL: std.os.windows.HINSTANCE,
49+
fdwReason: std.os.windows.DWORD,
50+
lpReserved: std.os.windows.LPVOID,
51+
) std.os.windows.BOOL {
52+
if (@hasDecl(root, "DllMain")) {
53+
return root.DllMain(hinstDLL, fdwReason, lpReserved);
54+
}
55+
56+
return std.os.windows.TRUE;
57+
}
58+
3759
extern fn wasm_freestanding_start() void {
3860
// This is marked inline because for some reason LLVM in release mode fails to inline it,
3961
// and we want fewer call frames in stack traces.
@@ -106,7 +128,7 @@ nakedcc fn _start() noreturn {
106128
@noInlineCall(posixCallMainAndExit);
107129
}
108130

109-
extern fn WinMainCRTStartup() noreturn {
131+
stdcallcc fn WinMainCRTStartup() noreturn {
110132
@setAlignStack(16);
111133
if (!builtin.single_threaded) {
112134
_ = @import("start_windows_tls.zig");

lib/std/special/start_lib.zig

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/all_types.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2061,7 +2061,6 @@ struct CodeGen {
20612061
ZigList<TldVar *> global_vars;
20622062

20632063
ZigFn *cur_fn;
2064-
ZigFn *main_fn;
20652064
ZigFn *panic_fn;
20662065

20672066
ZigFn *largest_frame_fn;
@@ -2081,7 +2080,6 @@ struct CodeGen {
20812080
uint32_t target_abi_index;
20822081
uint32_t target_oformat_index;
20832082
bool is_big_endian;
2084-
bool have_pub_main;
20852083
bool have_c_main;
20862084
bool have_winmain;
20872085
bool have_winmain_crt_startup;

src/analyze.cpp

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3304,17 +3304,6 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node) {
33043304
return fn_entry;
33053305
}
33063306

3307-
static bool scope_is_root_decls(Scope *scope) {
3308-
while (scope) {
3309-
if (scope->id == ScopeIdDecls) {
3310-
ScopeDecls *scope_decls = (ScopeDecls *)scope;
3311-
return is_top_level_struct(scope_decls->container_type);
3312-
}
3313-
scope = scope->parent;
3314-
}
3315-
zig_unreachable();
3316-
}
3317-
33183307
ZigType *get_test_fn_type(CodeGen *g) {
33193308
if (g->test_fn_type)
33203309
return g->test_fn_type;
@@ -3353,7 +3342,6 @@ void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, const char *symbol_name, G
33533342
}
33543343

33553344
static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
3356-
ZigType *import = tld_fn->base.import;
33573345
AstNode *source_node = tld_fn->base.source_node;
33583346
if (source_node->type == NodeTypeFnProto) {
33593347
AstNodeFnProto *fn_proto = &source_node->data.fn_proto;
@@ -3433,12 +3421,6 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
34333421
if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) {
34343422
fn_table_entry->inferred_async_node = fn_table_entry->proto_node;
34353423
}
3436-
3437-
if (scope_is_root_decls(tld_fn->base.parent_scope) && import == g->root_import) {
3438-
if (g->have_pub_main && buf_eql_str(tld_fn->base.name, "main")) {
3439-
g->main_fn = fn_table_entry;
3440-
}
3441-
}
34423424
} else if (source_node->type == NodeTypeTestDecl) {
34433425
ZigFn *fn_table_entry = create_fn_raw(g, FnInlineAuto);
34443426

@@ -4813,26 +4795,6 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Bu
48134795
ast_print(stderr, root_node, 0);
48144796
}
48154797

4816-
if (source_kind == SourceKindRoot) {
4817-
// Look for main
4818-
for (size_t decl_i = 0; decl_i < root_node->data.container_decl.decls.length; decl_i += 1) {
4819-
AstNode *top_level_decl = root_node->data.container_decl.decls.at(decl_i);
4820-
4821-
if (top_level_decl->type == NodeTypeFnDef) {
4822-
AstNode *proto_node = top_level_decl->data.fn_def.fn_proto;
4823-
assert(proto_node->type == NodeTypeFnProto);
4824-
Buf *proto_name = proto_node->data.fn_proto.name;
4825-
4826-
bool is_pub = (proto_node->data.fn_proto.visib_mod == VisibModPub);
4827-
if (is_pub) {
4828-
if (buf_eql_str(proto_name, "main")) {
4829-
g->have_pub_main = true;
4830-
}
4831-
}
4832-
}
4833-
}
4834-
}
4835-
48364798
for (size_t decl_i = 0; decl_i < root_node->data.container_decl.decls.length; decl_i += 1) {
48374799
AstNode *top_level_decl = root_node->data.container_decl.decls.at(decl_i);
48384800
scan_decls(g, import_entry->data.structure.decls_scope, top_level_decl);

src/codegen.cpp

Lines changed: 21 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -8229,9 +8229,9 @@ TargetSubsystem detect_subsystem(CodeGen *g) {
82298229
if (g->zig_target->os == OsWindows) {
82308230
if (g->have_dllmain_crt_startup || (g->out_type == OutTypeLib && g->is_dynamic))
82318231
return TargetSubsystemAuto;
8232-
if (g->have_c_main || g->have_pub_main || g->is_test_build)
8232+
if (g->have_c_main || g->is_test_build || g->have_winmain_crt_startup)
82338233
return TargetSubsystemConsole;
8234-
if (g->have_winmain || g->have_winmain_crt_startup)
8234+
if (g->have_winmain)
82358235
return TargetSubsystemWindows;
82368236
} else if (g->zig_target->os == OsUefi) {
82378237
return TargetSubsystemEfiApplication;
@@ -8375,6 +8375,22 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
83758375
const char *endian_str = g->is_big_endian ? "Endian.Big" : "Endian.Little";
83768376
buf_appendf(contents, "pub const endian = %s;\n", endian_str);
83778377
}
8378+
const char *out_type = nullptr;
8379+
switch (g->out_type) {
8380+
case OutTypeExe:
8381+
out_type = "Exe";
8382+
break;
8383+
case OutTypeLib:
8384+
out_type = "Lib";
8385+
break;
8386+
case OutTypeObj:
8387+
case OutTypeUnknown: // This happens when running the `zig builtin` command.
8388+
out_type = "Obj";
8389+
break;
8390+
}
8391+
buf_appendf(contents, "pub const output_mode = OutputMode.%s;\n", out_type);
8392+
const char *link_type = g->is_dynamic ? "Dynamic" : "Static";
8393+
buf_appendf(contents, "pub const link_mode = LinkMode.%s;\n", link_type);
83788394
buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build));
83798395
buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded));
83808396
buf_appendf(contents, "pub const os = Os.%s;\n", cur_os);
@@ -8441,6 +8457,8 @@ static Error define_builtin_compile_vars(CodeGen *g) {
84418457
cache_buf(&cache_hash, compiler_id);
84428458
cache_int(&cache_hash, g->build_mode);
84438459
cache_bool(&cache_hash, g->strip_debug_symbols);
8460+
cache_int(&cache_hash, g->out_type);
8461+
cache_bool(&cache_hash, g->is_dynamic);
84448462
cache_bool(&cache_hash, g->is_test_build);
84458463
cache_bool(&cache_hash, g->is_single_threaded);
84468464
cache_int(&cache_hash, g->zig_target->is_native);
@@ -9148,38 +9166,6 @@ static Buf *get_resolved_root_src_path(CodeGen *g) {
91489166
return resolved_path;
91499167
}
91509168

9151-
static bool want_startup_code(CodeGen *g) {
9152-
// Test builds get handled separately.
9153-
if (g->is_test_build)
9154-
return false;
9155-
9156-
// WASM freestanding can still have an entry point but other freestanding targets do not.
9157-
if (g->zig_target->os == OsFreestanding && !target_is_wasm(g->zig_target))
9158-
return false;
9159-
9160-
// Declaring certain export functions means skipping the start code
9161-
if (g->have_c_main || g->have_winmain || g->have_winmain_crt_startup)
9162-
return false;
9163-
9164-
// If there is a pub main in the root source file, that means we need start code.
9165-
if (g->have_pub_main) {
9166-
return true;
9167-
} else {
9168-
if (g->zig_target->os == OsUefi)
9169-
return false;
9170-
}
9171-
9172-
if (g->out_type == OutTypeExe) {
9173-
// For build-exe, we might add start code even though there is no pub main, so that the
9174-
// programmer gets the "no pub main" compile error. However if linking libc and there is
9175-
// a C source file, that might have main().
9176-
return g->c_source_files.length == 0 || g->libc_link_lib == nullptr;
9177-
}
9178-
9179-
// For objects and libraries, and we don't have pub main, no start code.
9180-
return false;
9181-
}
9182-
91839169
static void gen_root_source(CodeGen *g) {
91849170
Buf *resolved_path = get_resolved_root_src_path(g);
91859171
if (resolved_path == nullptr)
@@ -9241,21 +9227,14 @@ static void gen_root_source(CodeGen *g) {
92419227
assert(g->panic_fn != nullptr);
92429228
}
92439229

9244-
92459230
if (!g->error_during_imports) {
92469231
semantic_analyze(g);
92479232
}
92489233
report_errors_and_maybe_exit(g);
92499234

9250-
if (want_startup_code(g)) {
9235+
if (!g->is_test_build) {
92519236
g->start_import = add_special_code(g, create_start_pkg(g, g->root_package), "start.zig");
92529237
}
9253-
if (g->zig_target->os == OsWindows && !g->have_dllmain_crt_startup &&
9254-
g->out_type == OutTypeLib && g->is_dynamic)
9255-
{
9256-
g->start_import = add_special_code(g, create_start_pkg(g, g->root_package), "start_lib.zig");
9257-
}
9258-
92599238
if (!g->error_during_imports) {
92609239
semantic_analyze(g);
92619240
}

test/compare_output.zig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const tests = @import("tests.zig");
66
pub fn addCases(cases: *tests.CompareOutputContext) void {
77
cases.addC("hello world with libc",
88
\\const c = @cImport(@cInclude("stdio.h"));
9-
\\export fn main(argc: c_int, argv: [*][*]u8) c_int {
9+
\\pub export fn main(argc: c_int, argv: [*][*]u8) c_int {
1010
\\ _ = c.puts("Hello, world!");
1111
\\ return 0;
1212
\\}
@@ -139,7 +139,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
139139
\\ @cInclude("stdio.h");
140140
\\});
141141
\\
142-
\\export fn main(argc: c_int, argv: [*][*]u8) c_int {
142+
\\pub export fn main(argc: c_int, argv: [*][*]u8) c_int {
143143
\\ if (is_windows) {
144144
\\ // we want actual \n, not \r\n
145145
\\ _ = c._setmode(1, c._O_BINARY);
@@ -286,7 +286,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
286286
\\ }
287287
\\}
288288
\\
289-
\\export fn main() c_int {
289+
\\pub export fn main() c_int {
290290
\\ var array = [_]u32{ 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 };
291291
\\
292292
\\ c.qsort(@ptrCast(?*c_void, array[0..].ptr), @intCast(c_ulong, array.len), @sizeOf(i32), compare_fn);
@@ -314,7 +314,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
314314
\\ @cInclude("stdio.h");
315315
\\});
316316
\\
317-
\\export fn main(argc: c_int, argv: [*][*]u8) c_int {
317+
\\pub export fn main(argc: c_int, argv: [*][*]u8) c_int {
318318
\\ if (is_windows) {
319319
\\ // we want actual \n, not \r\n
320320
\\ _ = c._setmode(1, c._O_BINARY);

test/compile_errors.zig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
66
\\export async fn foo() void {}
77
, "tmp.zig:1:1: error: exported function cannot be async");
88

9+
cases.addExe(
10+
"main missing name",
11+
\\pub fn (main) void {}
12+
,
13+
"tmp.zig:1:5: error: missing function name",
14+
);
15+
916
cases.addCase(x: {
1017
var tc = cases.create("@newStackCall on unsupported target",
1118
\\export fn entry() void {

test/stage2/compare_output.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pub fn addCases(ctx: *TestContext) !void {
55
// hello world
66
try ctx.testCompareOutputLibC(
77
\\extern fn puts([*]const u8) void;
8-
\\export fn main() c_int {
8+
\\pub export fn main() c_int {
99
\\ puts("Hello, world!");
1010
\\ return 0;
1111
\\}
@@ -14,7 +14,7 @@ pub fn addCases(ctx: *TestContext) !void {
1414
// function calling another function
1515
try ctx.testCompareOutputLibC(
1616
\\extern fn puts(s: [*]const u8) void;
17-
\\export fn main() c_int {
17+
\\pub export fn main() c_int {
1818
\\ return foo("OK");
1919
\\}
2020
\\fn foo(s: [*]const u8) c_int {

test/standalone/hello_world/hello_libc.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const c = @cImport({
77

88
const msg = "Hello, world!\n";
99

10-
export fn main(argc: c_int, argv: **u8) c_int {
10+
pub export fn main(argc: c_int, argv: **u8) c_int {
1111
if (c.printf(msg) != @intCast(c_int, c.strlen(msg))) return -1;
1212
return 0;
1313
}

0 commit comments

Comments
 (0)