Commit a0ca30ce01

Vexu <git@vexu.eu>
2019-11-30 14:39:11
move more startup code to std lib
1 parent fd7c7be
lib/std/special/start.zig
@@ -19,21 +19,52 @@ const is_mips = switch (builtin.arch) {
 };
 
 comptime {
-    if (builtin.link_libc) {
-        @export("main", main, .Strong);
-    } else if (builtin.os == .windows) {
-        @export("WinMainCRTStartup", WinMainCRTStartup, .Strong);
-    } else if (is_wasm and builtin.os == .freestanding) {
-        @export("_start", wasm_freestanding_start, .Strong);
-    } else if (builtin.os == .uefi) {
-        @export("EfiMain", EfiMain, .Strong);
-    } else if (is_mips) {
-        if (!@hasDecl(root, "__start")) @export("__start", _start, .Strong);
-    } else {
-        if (!@hasDecl(root, "_start")) @export("_start", _start, .Strong);
+    switch (builtin.output_type) {
+        .Unknown => unreachable,
+        .Exe => {
+            if (builtin.link_libc) {
+                if (!@hasDecl(root, "main") or
+                    @typeInfo(@typeOf(root.main)).Fn.calling_convention != .C)
+                {
+                    @export("main", main, .Weak);
+                }
+            } else if (builtin.os == .windows) {
+                if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup")) {
+                    @export("WinMainCRTStartup", WinMainCRTStartup, .Strong);
+                }
+            } else if (is_wasm and builtin.os == .freestanding) {
+                if (!@hasDecl(root, "_start")) @export("_start", wasm_freestanding_start, .Strong);
+            } else if (builtin.os == .uefi) {
+                if (!@hasDecl(root, "EfiMain")) @export("EfiMain", EfiMain, .Strong);
+            } else if (is_mips) {
+                if (!@hasDecl(root, "__start")) @export("__start", _start, .Strong);
+            } else {
+                if (!@hasDecl(root, "_start")) @export("_start", _start, .Strong);
+            }
+        },
+        .Lib => {
+            if (builtin.os == .windows and builtin.link_type == .Dynamic and
+                !@hasDecl(root, "_DllMainCRTStartup"))
+            {
+                @export("_DllMainCRTStartup", _DllMainCRTStartup, .Strong);
+            }
+        },
+        .Obj => {},
     }
 }
 
+stdcallcc fn _DllMainCRTStartup(
+    hinstDLL: std.os.windows.HINSTANCE,
+    fdwReason: std.os.windows.DWORD,
+    lpReserved: std.os.windows.LPVOID,
+) std.os.windows.BOOL {
+    if (@hasDecl(root, "DllMain")) {
+        return root.DllMain(hinstDLL, fdwReason, lpReserved);
+    }
+
+    return std.os.windows.TRUE;
+}
+
 extern fn wasm_freestanding_start() void {
     // This is marked inline because for some reason LLVM in release mode fails to inline it,
     // and we want fewer call frames in stack traces.
lib/std/special/start_lib.zig
@@ -1,21 +0,0 @@
-// This file is included in the compilation unit when exporting a DLL on windows.
-
-const root = @import("root");
-const std = @import("std");
-const builtin = @import("builtin");
-
-comptime {
-    @export("_DllMainCRTStartup", _DllMainCRTStartup, builtin.GlobalLinkage.Strong);
-}
-
-stdcallcc fn _DllMainCRTStartup(
-    hinstDLL: std.os.windows.HINSTANCE,
-    fdwReason: std.os.windows.DWORD,
-    lpReserved: std.os.windows.LPVOID,
-) std.os.windows.BOOL {
-    if (@hasDecl(root, "DllMain")) {
-        return root.DllMain(hinstDLL, fdwReason, lpReserved);
-    }
-
-    return std.os.windows.TRUE;
-}
lib/std/builtin.zig
@@ -348,6 +348,22 @@ pub const Endian = enum {
     Little,
 };
 
+/// This data structure is used by the Zig language code generation and
+/// therefore must be kept in sync with the compiler implementation.
+pub const OutType = enum {
+    Unknown,
+    Exe,
+    Lib,
+    Obj,
+};
+
+/// This data structure is used by the Zig language code generation and
+/// therefore must be kept in sync with the compiler implementation.
+pub const LinkType = enum {
+    Static,
+    Dynamic,
+};
+
 /// This data structure is used by the Zig language code generation and
 /// therefore must be kept in sync with the compiler implementation.
 pub const Version = struct {
src/all_types.hpp
@@ -2061,7 +2061,6 @@ struct CodeGen {
     ZigList<TldVar *> global_vars;
 
     ZigFn *cur_fn;
-    ZigFn *main_fn;
     ZigFn *panic_fn;
 
     ZigFn *largest_frame_fn;
@@ -2081,7 +2080,6 @@ struct CodeGen {
     uint32_t target_abi_index;
     uint32_t target_oformat_index;
     bool is_big_endian;
-    bool have_pub_main;
     bool have_c_main;
     bool have_winmain;
     bool have_winmain_crt_startup;
src/analyze.cpp
@@ -3304,17 +3304,6 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node) {
     return fn_entry;
 }
 
-static bool scope_is_root_decls(Scope *scope) {
-    while (scope) {
-        if (scope->id == ScopeIdDecls) {
-            ScopeDecls *scope_decls = (ScopeDecls *)scope;
-            return is_top_level_struct(scope_decls->container_type);
-        }
-        scope = scope->parent;
-    }
-    zig_unreachable();
-}
-
 ZigType *get_test_fn_type(CodeGen *g) {
     if (g->test_fn_type)
         return g->test_fn_type;
@@ -3353,7 +3342,6 @@ void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, const char *symbol_name, G
 }
 
 static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
-    ZigType *import = tld_fn->base.import;
     AstNode *source_node = tld_fn->base.source_node;
     if (source_node->type == NodeTypeFnProto) {
         AstNodeFnProto *fn_proto = &source_node->data.fn_proto;
@@ -3433,12 +3421,6 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
         if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) {
             fn_table_entry->inferred_async_node = fn_table_entry->proto_node;
         }
-
-        if (scope_is_root_decls(tld_fn->base.parent_scope) && import == g->root_import) {
-            if (g->have_pub_main && buf_eql_str(tld_fn->base.name, "main")) {
-                g->main_fn = fn_table_entry;
-            }
-        }
     } else if (source_node->type == NodeTypeTestDecl) {
         ZigFn *fn_table_entry = create_fn_raw(g, FnInlineAuto);
 
@@ -4813,26 +4795,6 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Bu
         ast_print(stderr, root_node, 0);
     }
 
-    if (source_kind == SourceKindRoot) {
-        // Look for main
-        for (size_t decl_i = 0; decl_i < root_node->data.container_decl.decls.length; decl_i += 1) {
-            AstNode *top_level_decl = root_node->data.container_decl.decls.at(decl_i);
-
-            if (top_level_decl->type == NodeTypeFnDef) {
-                AstNode *proto_node = top_level_decl->data.fn_def.fn_proto;
-                assert(proto_node->type == NodeTypeFnProto);
-                Buf *proto_name = proto_node->data.fn_proto.name;
-
-                bool is_pub = (proto_node->data.fn_proto.visib_mod == VisibModPub);
-                if (is_pub) {
-                    if (buf_eql_str(proto_name, "main")) {
-                        g->have_pub_main = true;
-                    }
-                }
-            }
-        }
-    }
-
     for (size_t decl_i = 0; decl_i < root_node->data.container_decl.decls.length; decl_i += 1) {
         AstNode *top_level_decl = root_node->data.container_decl.decls.at(decl_i);
         scan_decls(g, import_entry->data.structure.decls_scope, top_level_decl);
src/codegen.cpp
@@ -8229,7 +8229,7 @@ TargetSubsystem detect_subsystem(CodeGen *g) {
     if (g->zig_target->os == OsWindows) {
         if (g->have_dllmain_crt_startup || (g->out_type == OutTypeLib && g->is_dynamic))
             return TargetSubsystemAuto;
-        if (g->have_c_main || g->have_pub_main || g->is_test_build)
+        if (g->have_c_main || g->is_test_build)
             return TargetSubsystemConsole;
         if (g->have_winmain || g->have_winmain_crt_startup)
             return TargetSubsystemWindows;
@@ -8375,6 +8375,24 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
         const char *endian_str = g->is_big_endian ? "Endian.Big" : "Endian.Little";
         buf_appendf(contents, "pub const endian = %s;\n", endian_str);
     }
+    const char *out_type = nullptr;
+    switch (g->out_type) {
+        case OutTypeUnknown:
+            out_type = "Unknown";
+            break;
+        case OutTypeExe:
+            out_type = "Exe";
+            break;
+        case OutTypeLib:
+            out_type = "Lib";
+            break;
+        case OutTypeObj:
+            out_type = "Obj";
+            break;
+    }
+    buf_appendf(contents, "pub const output_type = OutType.%s;\n", out_type);
+    const char *link_type = g->is_dynamic ? "Dynamic" : "Static"; 
+    buf_appendf(contents, "pub const link_type = LinkType.%s;\n", link_type);
     buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build));
     buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded));
     buf_appendf(contents, "pub const os = Os.%s;\n", cur_os);
@@ -9148,38 +9166,6 @@ static Buf *get_resolved_root_src_path(CodeGen *g) {
     return resolved_path;
 }
 
-static bool want_startup_code(CodeGen *g) {
-    // Test builds get handled separately.
-    if (g->is_test_build)
-        return false;
-
-    // WASM freestanding can still have an entry point but other freestanding targets do not.
-    if (g->zig_target->os == OsFreestanding && !target_is_wasm(g->zig_target))
-        return false;
-
-    // Declaring certain export functions means skipping the start code
-    if (g->have_c_main || g->have_winmain || g->have_winmain_crt_startup)
-        return false;
-
-    // If there is a pub main in the root source file, that means we need start code.
-    if (g->have_pub_main) {
-        return true;
-    } else {
-        if (g->zig_target->os == OsUefi)
-            return false;
-    }
-
-    if (g->out_type == OutTypeExe) {
-        // For build-exe, we might add start code even though there is no pub main, so that the
-        // programmer gets the "no pub main" compile error. However if linking libc and there is
-        // a C source file, that might have main().
-        return g->c_source_files.length == 0 || g->libc_link_lib == nullptr;
-    }
-
-    // For objects and libraries, and we don't have pub main, no start code.
-    return false;
-}
-
 static void gen_root_source(CodeGen *g) {
     Buf *resolved_path = get_resolved_root_src_path(g);
     if (resolved_path == nullptr)
@@ -9241,21 +9227,14 @@ static void gen_root_source(CodeGen *g) {
         assert(g->panic_fn != nullptr);
     }
 
-
     if (!g->error_during_imports) {
         semantic_analyze(g);
     }
     report_errors_and_maybe_exit(g);
 
-    if (want_startup_code(g)) {
+    if (!g->is_test_build) {
         g->start_import = add_special_code(g, create_start_pkg(g, g->root_package), "start.zig");
     }
-    if (g->zig_target->os == OsWindows && !g->have_dllmain_crt_startup &&
-            g->out_type == OutTypeLib && g->is_dynamic)
-    {
-        g->start_import = add_special_code(g, create_start_pkg(g, g->root_package), "start_lib.zig");
-    }
-
     if (!g->error_during_imports) {
         semantic_analyze(g);
     }