Commit c893f83715

Luuk de Gram <luuk@degram.dev>
2023-11-02 19:06:19
cli: consolidate entry point flags
1 parent 5b2ee5e
Changed files (21)
lib
std
Build
src
test
link
macho
entry
entry_in_dylib
wasm
archive
basic-features
bss
export
export-data
extern-mangle
function-table
infer-features
producers
segments
shared-memory
stack_pointer
type
lib/std/Build/Step/Compile.zig
@@ -64,8 +64,6 @@ initial_memory: ?u64 = null,
 max_memory: ?u64 = null,
 shared_memory: bool = false,
 global_base: ?u64 = null,
-/// For WebAssembly only. Tells the linker to not output an entry point.
-no_entry: ?bool = null,
 c_std: std.Build.CStd,
 /// Set via options; intended to be read-only after that.
 zig_lib_dir: ?LazyPath,
@@ -191,7 +189,8 @@ dll_export_fns: ?bool = null,
 
 subsystem: ?std.Target.SubSystem = null,
 
-entry_symbol_name: ?[]const u8 = null,
+/// How the linker must handle the entry point of the executable.
+entry: Entry = .default,
 
 /// List of symbols forced as undefined in the symbol table
 /// thus forcing their resolution by the linker.
@@ -306,6 +305,18 @@ const FrameworkLinkInfo = struct {
     weak: bool = false,
 };
 
+const Entry = union(enum) {
+    /// Let the compiler decide whether to make an entry point and what to name
+    /// it.
+    default,
+    /// The executable will have no entry point.
+    disabled,
+    /// The executable will have an entry point with the default symbol name.
+    enabled,
+    /// The executable will have an entry point with the specified symbol name.
+    symbol_name: []const u8,
+};
+
 pub const IncludeDir = union(enum) {
     path: LazyPath,
     path_system: LazyPath,
@@ -1420,9 +1431,13 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
         try zig_args.append(try std.fmt.allocPrint(b.allocator, "-ofmt={s}", .{@tagName(ofmt)}));
     }
 
-    if (self.entry_symbol_name) |entry| {
-        try zig_args.append("--entry");
-        try zig_args.append(entry);
+    switch (self.entry) {
+        .default => {},
+        .disabled => try zig_args.append("-fno-entry"),
+        .enabled => try zig_args.append("-fentry"),
+        .symbol_name => |entry_name| {
+            try zig_args.append(try std.fmt.allocPrint(b.allocator, "-fentry={s}", .{entry_name}));
+        },
     }
 
     {
@@ -1853,11 +1868,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
     if (self.global_base) |global_base| {
         try zig_args.append(b.fmt("--global-base={d}", .{global_base}));
     }
-    // invert the value due to naming so when `no_entry` is set to 'true'
-    // we actually emit the flag `-fno_entry`.
-    if (self.no_entry) |no_entry| {
-        try addFlag(&zig_args, "entry", !no_entry);
-    }
 
     if (self.code_model != .default) {
         try zig_args.append("-mcmodel");
src/link/Wasm.zig
@@ -2817,11 +2817,11 @@ fn setupExports(wasm: *Wasm) !void {
 }
 
 fn setupStart(wasm: *Wasm) !void {
-    if (wasm.base.options.no_entry) return;
-    const entry_name = wasm.base.options.entry orelse "_start";
+    // do not export entry point if user set none or no default was set.
+    const entry_name = wasm.base.options.entry orelse return;
 
     const symbol_loc = wasm.findGlobalSymbol(entry_name) orelse {
-        log.err("Entry symbol '{s}' missing", .{entry_name});
+        log.err("Entry symbol '{s}' missing, use '-fno-entry' to suppress", .{entry_name});
         return error.MissingSymbol;
     };
 
@@ -4531,6 +4531,8 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
         if (wasm.base.options.entry) |entry| {
             try argv.append("--entry");
             try argv.append(entry);
+        } else {
+            try argv.append("--no-entry");
         }
 
         // Increase the default stack size to a more reasonable value of 1MB instead of
@@ -4544,10 +4546,6 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
             try argv.append("--allow-undefined");
         }
 
-        if (wasm.base.options.no_entry) {
-            try argv.append("--no-entry");
-        }
-
         if (wasm.base.options.output_mode == .Lib and wasm.base.options.link_mode == .Dynamic) {
             try argv.append("--shared");
         }
src/Compilation.zig
@@ -643,7 +643,6 @@ pub const InitOptions = struct {
     linker_import_symbols: bool = false,
     linker_import_table: bool = false,
     linker_export_table: bool = false,
-    linker_no_entry: bool = false,
     linker_initial_memory: ?u64 = null,
     linker_max_memory: ?u64 = null,
     linker_shared_memory: bool = false,
@@ -1615,7 +1614,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
             .import_symbols = options.linker_import_symbols,
             .import_table = options.linker_import_table,
             .export_table = options.linker_export_table,
-            .no_entry = options.linker_no_entry,
             .initial_memory = options.linker_initial_memory,
             .max_memory = options.linker_max_memory,
             .shared_memory = options.linker_shared_memory,
@@ -2579,7 +2577,6 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
     man.hash.addOptional(comp.bin_file.options.max_memory);
     man.hash.add(comp.bin_file.options.shared_memory);
     man.hash.addOptional(comp.bin_file.options.global_base);
-    man.hash.add(comp.bin_file.options.no_entry);
 
     // Mach-O specific stuff
     man.hash.addListOfBytes(comp.bin_file.options.framework_dirs);
src/link.zig
@@ -166,7 +166,6 @@ pub const Options = struct {
     export_table: bool,
     initial_memory: ?u64,
     max_memory: ?u64,
-    no_entry: bool,
     shared_memory: bool,
     export_symbol_names: []const []const u8,
     global_base: ?u64,
src/main.zig
@@ -509,7 +509,9 @@ const usage_build_generic =
     \\  --dynamic-linker [path]        Set the dynamic interpreter path (usually ld.so)
     \\  --sysroot [path]               Set the system root directory (usually /)
     \\  --version [ver]                Dynamic library semver
-    \\  --entry [name]                 Set the entrypoint symbol name
+    \\  -fentry                        Enable entry point with default symbol name
+    \\  -fentry=[name]                 Override the entry point symbol name
+    \\  -fno-entry                     Do not output any entry point
     \\  --force_undefined [name]       Specify the symbol must be defined for the link to succeed
     \\  -fsoname[=name]                Override the default SONAME value
     \\  -fno-soname                    Disable emitting a SONAME
@@ -577,8 +579,6 @@ const usage_build_generic =
     \\  --shared-memory                (WebAssembly) use shared linear memory
     \\  --global-base=[addr]           (WebAssembly) where to start to place global data
     \\  --export=[value]               (WebAssembly) Force a symbol to be exported
-    \\  -fentry                        (WebAssembly) Force output an entry point
-    \\  -fno-entry                     (WebAssembly) Do not output any entry point
     \\
     \\Test Options:
     \\  --test-filter [text]           Skip tests that do not match filter
@@ -837,7 +837,7 @@ fn buildOutputType(
     var linker_import_symbols: bool = false;
     var linker_import_table: bool = false;
     var linker_export_table: bool = false;
-    var linker_no_entry: ?bool = null;
+    var linker_force_entry: ?bool = null;
     var linker_initial_memory: ?u64 = null;
     var linker_max_memory: ?u64 = null;
     var linker_shared_memory: bool = false;
@@ -1074,8 +1074,8 @@ fn buildOutputType(
                         subsystem = try parseSubSystem(args_iter.nextOrFatal());
                     } else if (mem.eql(u8, arg, "-O")) {
                         optimize_mode_string = args_iter.nextOrFatal();
-                    } else if (mem.eql(u8, arg, "--entry")) {
-                        entry = args_iter.nextOrFatal();
+                    } else if (mem.startsWith(u8, arg, "-fentry=")) {
+                        entry = arg["-fentry=".len..];
                     } else if (mem.eql(u8, arg, "--force_undefined")) {
                         try force_undefined_symbols.put(gpa, args_iter.nextOrFatal(), {});
                     } else if (mem.eql(u8, arg, "--stack")) {
@@ -1507,9 +1507,9 @@ fn buildOutputType(
                     } else if (mem.eql(u8, arg, "--import-memory")) {
                         linker_import_memory = true;
                     } else if (mem.eql(u8, arg, "-fentry")) {
-                        linker_no_entry = false;
+                        linker_force_entry = true;
                     } else if (mem.eql(u8, arg, "-fno-entry")) {
-                        linker_no_entry = true;
+                        linker_force_entry = false;
                     } else if (mem.eql(u8, arg, "--export-memory")) {
                         linker_export_memory = true;
                     } else if (mem.eql(u8, arg, "--import-symbols")) {
@@ -2142,7 +2142,7 @@ fn buildOutputType(
                 } else if (mem.eql(u8, arg, "--export-table")) {
                     linker_export_table = true;
                 } else if (mem.eql(u8, arg, "--no-entry")) {
-                    linker_no_entry = true;
+                    linker_force_entry = false;
                 } else if (mem.eql(u8, arg, "--initial-memory")) {
                     const next_arg = linker_args_it.nextOrFatal();
                     linker_initial_memory = std.fmt.parseUnsigned(u32, eatIntPrefix(next_arg, 16), 16) catch |err| {
@@ -2605,6 +2605,23 @@ fn buildOutputType(
             link_libcpp = true;
     }
 
+    if (linker_force_entry) |force| {
+        if (!force) {
+            entry = null;
+        } else if (entry == null and output_mode == .Exe) {
+            entry = switch (target_info.target.ofmt) {
+                .coff => "wWinMainCRTStartup",
+                .macho => "_main",
+                .elf, .plan9 => "_start",
+                .wasm => defaultWasmEntryName(wasi_exec_model),
+                else => |tag| fatal("No default entry point available for output format {s}", .{@tagName(tag)}),
+            };
+        }
+    } else if (entry == null and target_info.target.isWasm() and output_mode == .Exe) {
+        // For WebAssembly the compiler defaults to setting the entry name when no flags are set.
+        entry = defaultWasmEntryName(wasi_exec_model);
+    }
+
     if (target_info.target.ofmt == .coff) {
         // Now that we know the target supports resources,
         // we can add the res files as link objects.
@@ -2637,25 +2654,13 @@ fn buildOutputType(
                 linker_export_memory = false;
             }
         }
-        if (wasi_exec_model) |model| {
-            if (model == .reactor) {
-                if (linker_no_entry != null and !linker_no_entry.?) {
-                    fatal("WASI exucution model 'reactor' incompatible with flag '-fentry'. Reactor execution model has no entry point", .{});
-                }
-                if (entry) |entry_name| {
-                    if (!mem.eql(u8, "_initialize", entry_name)) {
-                        fatal("the entry symbol of the reactor model must be '_initialize', but found '{s}'", .{entry_name});
-                    }
-                } else {
-                    entry = "_initialize";
+        if (wasi_exec_model != null and wasi_exec_model.? == .reactor) {
+            if (entry) |entry_name| {
+                if (!mem.eql(u8, "_initialize", entry_name)) {
+                    fatal("the entry symbol of the reactor model must be '_initialize', but found '{s}'", .{entry_name});
                 }
             }
         }
-        if (linker_no_entry) |no_entry| {
-            if (no_entry and entry != null) {
-                fatal("combination of '--entry' and `-fno-entry` are incompatible", .{});
-            }
-        }
         if (linker_shared_memory) {
             if (output_mode == .Obj) {
                 fatal("shared memory is not allowed in object files", .{});
@@ -3503,7 +3508,6 @@ fn buildOutputType(
         .linker_import_symbols = linker_import_symbols,
         .linker_import_table = linker_import_table,
         .linker_export_table = linker_export_table,
-        .linker_no_entry = linker_no_entry orelse false,
         .linker_initial_memory = linker_initial_memory,
         .linker_max_memory = linker_max_memory,
         .linker_shared_memory = linker_shared_memory,
@@ -7253,3 +7257,11 @@ fn createDependenciesModule(
     try main_mod.deps.put(arena, "@dependencies", deps_mod);
     return deps_mod;
 }
+
+fn defaultWasmEntryName(exec_model: ?std.builtin.WasiExecModel) []const u8 {
+    const model = exec_model orelse .command;
+    if (model == .reactor) {
+        return "_initialize";
+    }
+    return "_start";
+}
test/link/macho/entry/build.zig
@@ -20,7 +20,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
     });
     exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} });
     exe.linkLibC();
-    exe.entry_symbol_name = "_non_main";
+    exe.entry = .{ .symbol_name = "_non_main" };
 
     const check_exe = exe.checkObject();
 
test/link/macho/entry_in_dylib/build.zig
@@ -30,7 +30,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
     exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} });
     exe.linkLibrary(lib);
     exe.linkLibC();
-    exe.entry_symbol_name = "_bootstrap";
+    exe.entry = .{ .symbol_name = "_bootstrap" };
     exe.forceUndefinedSymbol("_my_main");
 
     const check_exe = exe.checkObject();
test/link/wasm/archive/build.zig
@@ -21,7 +21,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
         .optimize = optimize,
         .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
     });
-    lib.no_entry = true;
+    lib.entry = .disabled;
     lib.use_llvm = false;
     lib.use_lld = false;
     lib.strip = false;
test/link/wasm/basic-features/build.zig
@@ -15,7 +15,7 @@ pub fn build(b: *std.Build) void {
             .os_tag = .freestanding,
         },
     });
-    lib.no_entry = true;
+    lib.entry = .disabled;
     lib.use_llvm = false;
     lib.use_lld = false;
 
test/link/wasm/bss/build.zig
@@ -20,7 +20,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.Opt
             .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
             .optimize = optimize_mode,
         });
-        lib.no_entry = true;
+        lib.entry = .disabled;
         lib.use_llvm = false;
         lib.use_lld = false;
         lib.strip = false;
@@ -67,7 +67,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.Opt
             .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
             .optimize = optimize_mode,
         });
-        lib.no_entry = true;
+        lib.entry = .disabled;
         lib.use_llvm = false;
         lib.use_lld = false;
         lib.strip = false;
test/link/wasm/export/build.zig
@@ -19,7 +19,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
         .optimize = optimize,
         .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
     });
-    no_export.no_entry = true;
+    no_export.entry = .disabled;
     no_export.use_llvm = false;
     no_export.use_lld = false;
 
@@ -29,7 +29,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
         .optimize = optimize,
         .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
     });
-    dynamic_export.no_entry = true;
+    dynamic_export.entry = .disabled;
     dynamic_export.rdynamic = true;
     dynamic_export.use_llvm = false;
     dynamic_export.use_lld = false;
@@ -40,7 +40,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
         .optimize = optimize,
         .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
     });
-    force_export.no_entry = true;
+    force_export.entry = .disabled;
     force_export.export_symbol_names = &.{"foo"};
     force_export.use_llvm = false;
     force_export.use_lld = false;
test/link/wasm/export-data/build.zig
@@ -15,7 +15,7 @@ pub fn build(b: *std.Build) void {
         .optimize = .ReleaseSafe, // to make the output deterministic in address positions
         .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
     });
-    lib.no_entry = true;
+    lib.entry = .disabled;
     lib.use_lld = false;
     lib.export_symbol_names = &.{ "foo", "bar" };
     lib.global_base = 0; // put data section at address 0 to make data symbols easier to parse
test/link/wasm/extern-mangle/build.zig
@@ -17,7 +17,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
         .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
         .optimize = optimize,
     });
-    lib.no_entry = true;
+    lib.entry = .disabled;
     lib.import_symbols = true; // import `a` and `b`
     lib.rdynamic = true; // export `foo`
 
test/link/wasm/function-table/build.zig
@@ -19,7 +19,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
         .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
         .optimize = optimize,
     });
-    import_table.no_entry = true;
+    import_table.entry = .disabled;
     import_table.use_llvm = false;
     import_table.use_lld = false;
     import_table.import_table = true;
@@ -30,7 +30,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
         .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
         .optimize = optimize,
     });
-    export_table.no_entry = true;
+    export_table.entry = .disabled;
     export_table.use_llvm = false;
     export_table.use_lld = false;
     export_table.export_table = true;
@@ -41,7 +41,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
         .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
         .optimize = optimize,
     });
-    regular_table.no_entry = true;
+    regular_table.entry = .disabled;
     regular_table.use_llvm = false;
     regular_table.use_lld = false;
 
test/link/wasm/infer-features/build.zig
@@ -27,7 +27,7 @@ pub fn build(b: *std.Build) void {
             .os_tag = .freestanding,
         },
     });
-    lib.no_entry = true;
+    lib.entry = .disabled;
     lib.use_llvm = false;
     lib.use_lld = false;
     lib.addObject(c_obj);
test/link/wasm/producers/build.zig
@@ -20,7 +20,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
         .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
         .optimize = optimize,
     });
-    lib.no_entry = true;
+    lib.entry = .disabled;
     lib.use_llvm = false;
     lib.use_lld = false;
     lib.strip = false;
test/link/wasm/segments/build.zig
@@ -19,7 +19,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
         .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
         .optimize = optimize,
     });
-    lib.no_entry = true;
+    lib.entry = .disabled;
     lib.use_llvm = false;
     lib.use_lld = false;
     lib.strip = false;
test/link/wasm/shared-memory/build.zig
@@ -22,7 +22,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.Opt
         },
         .optimize = optimize_mode,
     });
-    lib.no_entry = true;
+    lib.entry = .disabled;
     lib.use_lld = false;
     lib.strip = false;
     lib.import_memory = true;
test/link/wasm/stack_pointer/build.zig
@@ -19,7 +19,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
         .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
         .optimize = optimize,
     });
-    lib.no_entry = true;
+    lib.entry = .disabled;
     lib.use_llvm = false;
     lib.use_lld = false;
     lib.strip = false;
test/link/wasm/type/build.zig
@@ -19,7 +19,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
         .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
         .optimize = optimize,
     });
-    lib.no_entry = true;
+    lib.entry = .disabled;
     lib.use_llvm = false;
     lib.use_lld = false;
     lib.strip = false;
test/link/elf.zig
@@ -651,7 +651,7 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {
         const exe = addExecutable(b, "main", opts);
         exe.addObject(a_o);
         exe.addObject(b_o);
-        exe.entry_symbol_name = "foo";
+        exe.entry = .{ .symbol_name = "foo" };
 
         const check = exe.checkObject();
         check.checkStart();
@@ -667,7 +667,7 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {
         const exe = addExecutable(b, "other", opts);
         exe.addObject(a_o);
         exe.addObject(b_o);
-        exe.entry_symbol_name = "bar";
+        exe.entry = .{ .symbol_name = "bar" };
 
         const check = exe.checkObject();
         check.checkStart();