Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

cmdObjCopy

objcopy.cmdObjCopy
fn cmdObjCopy(arena: Allocator, io: Io, args: []const []const u8) !void

File

lib/compiler/objcopy.zig:26

Code

fn cmdObjCopy(arena: Allocator, io: Io, args: []const []const u8) !void {
    var i: usize = 0;
    var opt_out_fmt: ?std.Target.ObjectFormat = null;
    var opt_input: ?[]const u8 = null;
    var opt_output: ?[]const u8 = null;
    var opt_extract: ?[]const u8 = null;
    var opt_add_debuglink: ?[]const u8 = null;
    var only_section: ?[]const u8 = null;
    var pad_to: ?u64 = null;
    var strip_all: bool = false;
    var strip_debug: bool = false;
    var only_keep_debug: bool = false;
    var compress_debug_sections: bool = false;
    var listen = false;
    var add_section: ?AddSection = null;
    var set_section_alignment: ?SetSectionAlignment = null;
    var set_section_flags: ?SetSectionFlags = null;
    while (i < args.len) : (i += 1) {
        const arg = args[i];
        if (!mem.startsWith(u8, arg, "-")) {
            if (opt_input == null) {
                opt_input = arg;
            } else if (opt_output == null) {
                opt_output = arg;
            } else {
                fatal("unexpected positional argument: '{s}'", .{arg});
            }
        } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
            return Io.File.stdout().writeStreamingAll(io, usage);
        } else if (mem.eql(u8, arg, "-O") or mem.eql(u8, arg, "--output-target")) {
            i += 1;
            if (i >= args.len) fatal("expected another argument after '{s}'", .{arg});
            const next_arg = args[i];
            if (mem.eql(u8, next_arg, "binary")) {
                opt_out_fmt = .raw;
            } else {
                opt_out_fmt = std.meta.stringToEnum(std.Target.ObjectFormat, next_arg) orelse
                    fatal("invalid output format: '{s}'", .{next_arg});
            }
        } else if (mem.startsWith(u8, arg, "--output-target=")) {
            const next_arg = arg["--output-target=".len..];
            if (mem.eql(u8, next_arg, "binary")) {
                opt_out_fmt = .raw;
            } else {
                opt_out_fmt = std.meta.stringToEnum(std.Target.ObjectFormat, next_arg) orelse
                    fatal("invalid output format: '{s}'", .{next_arg});
            }
        } else if (mem.eql(u8, arg, "-j") or mem.eql(u8, arg, "--only-section")) {
            i += 1;
            if (i >= args.len) fatal("expected another argument after '{s}'", .{arg});
            only_section = args[i];
        } else if (mem.eql(u8, arg, "--listen=-")) {
            listen = true;
        } else if (mem.startsWith(u8, arg, "--only-section=")) {
            only_section = arg["--only-section=".len..];
        } else if (mem.eql(u8, arg, "--pad-to")) {
            i += 1;
            if (i >= args.len) fatal("expected another argument after '{s}'", .{arg});
            pad_to = std.fmt.parseInt(u64, args[i], 0) catch |err| {
                fatal("unable to parse: '{s}': {s}", .{ args[i], @errorName(err) });
            };
        } else if (mem.eql(u8, arg, "-g") or mem.eql(u8, arg, "--strip-debug")) {
            strip_debug = true;
        } else if (mem.eql(u8, arg, "-S") or mem.eql(u8, arg, "--strip-all")) {
            strip_all = true;
        } else if (mem.eql(u8, arg, "--only-keep-debug")) {
            only_keep_debug = true;
        } else if (mem.eql(u8, arg, "--compress-debug-sections")) {
            compress_debug_sections = true;
        } else if (mem.startsWith(u8, arg, "--add-gnu-debuglink=")) {
            opt_add_debuglink = arg["--add-gnu-debuglink=".len..];
        } else if (mem.eql(u8, arg, "--add-gnu-debuglink")) {
            i += 1;
            if (i >= args.len) fatal("expected another argument after '{s}'", .{arg});
            opt_add_debuglink = args[i];
        } else if (mem.startsWith(u8, arg, "--extract-to=")) {
            opt_extract = arg["--extract-to=".len..];
        } else if (mem.eql(u8, arg, "--extract-to")) {
            i += 1;
            if (i >= args.len) fatal("expected another argument after '{s}'", .{arg});
            opt_extract = args[i];
        } else if (mem.eql(u8, arg, "--set-section-alignment")) {
            i += 1;
            if (i >= args.len) fatal("expected section name and alignment arguments after '{s}'", .{arg});

            if (splitOption(args[i])) |split| {
                const alignment = std.fmt.parseInt(u32, split.second, 10) catch |err| {
                    fatal("unable to parse alignment number: '{s}': {s}", .{ split.second, @errorName(err) });
                };
                if (!std.math.isPowerOfTwo(alignment)) fatal("alignment must be a power of two", .{});
                set_section_alignment = .{ .section_name = split.first, .alignment = alignment };
            } else {
                fatal("unrecognized argument: '{s}', expecting <name>=<alignment>", .{args[i]});
            }
        } else if (mem.eql(u8, arg, "--set-section-flags")) {
            i += 1;
            if (i >= args.len) fatal("expected section name and filename arguments after '{s}'", .{arg});

            if (splitOption(args[i])) |split| {
                set_section_flags = .{ .section_name = split.first, .flags = parseSectionFlags(split.second) };
            } else {
                fatal("unrecognized argument: '{s}', expecting <name>=<flags>", .{args[i]});
            }
        } else if (mem.eql(u8, arg, "--add-section")) {
            i += 1;
            if (i >= args.len) fatal("expected section name and filename arguments after '{s}'", .{arg});

            if (splitOption(args[i])) |split| {
                add_section = .{ .section_name = split.first, .file_path = split.second };
            } else {
                fatal("unrecognized argument: '{s}', expecting <name>=<file>", .{args[i]});
            }
        } else {
            fatal("unrecognized argument: '{s}'", .{arg});
        }
    }
    const input = opt_input orelse fatal("expected input parameter", .{});
    const output = opt_output orelse fatal("expected output parameter", .{});

    const input_file = Io.Dir.cwd().openFile(io, input, .{}) catch |err| fatal("failed to open {s}: {t}", .{ input, err });
    defer input_file.close(io);

    const stat = input_file.stat(io) catch |err| fatal("failed to stat {s}: {t}", .{ input, err });

    var in: File.Reader = .initSize(input_file, io, &input_buffer, stat.size);

    const elf_hdr = std.elf.Header.read(&in.interface) catch |err| switch (err) {
        error.ReadFailed => fatal("unable to read {s}: {t}", .{ input, in.err.? }),
        else => |e| fatal("invalid elf file: {t}", .{e}),
    };

    const in_ofmt = .elf;

    const out_fmt: std.Target.ObjectFormat = opt_out_fmt orelse ofmt: {
        if (mem.endsWith(u8, output, ".hex") or std.mem.endsWith(u8, output, ".ihex")) {
            break :ofmt .hex;
        } else if (mem.endsWith(u8, output, ".bin")) {
            break :ofmt .raw;
        } else if (mem.endsWith(u8, output, ".elf")) {
            break :ofmt .elf;
        } else {
            break :ofmt in_ofmt;
        }
    };

    const permissions: Io.File.Permissions = if (out_fmt != .elf or only_keep_debug) .default_file else stat.permissions;

    var output_file = try Io.Dir.cwd().createFile(io, output, .{ .permissions = permissions });
    defer output_file.close(io);

    var out = output_file.writer(io, &output_buffer);

    switch (out_fmt) {
        .hex, .raw => {
            if (strip_debug or strip_all or only_keep_debug)
                fatal("zig objcopy: ELF to RAW or HEX copying does not support --strip", .{});
            if (opt_extract != null)
                fatal("zig objcopy: ELF to RAW or HEX copying does not support --extract-to", .{});
            if (add_section != null)
                fatal("zig objcopy: ELF to RAW or HEX copying does not support --add-section", .{});
            if (set_section_alignment != null)
                fatal("zig objcopy: ELF to RAW or HEX copying does not support --set_section_alignment", .{});
            if (set_section_flags != null)
                fatal("zig objcopy: ELF to RAW or HEX copying does not support --set_section_flags", .{});

            try emitElf(arena, &in, &out, elf_hdr, .{
                .ofmt = out_fmt,
                .only_section = only_section,
                .pad_to = pad_to,
            });
        },
        .elf => {
            if (elf_hdr.endian != builtin.target.cpu.arch.endian())
                fatal("zig objcopy: ELF to ELF copying only supports native endian", .{});
            if (elf_hdr.phoff == 0) // no program header
                fatal("zig objcopy: ELF to ELF copying only supports programs", .{});
            if (only_section) |_|
                fatal("zig objcopy: ELF to ELF copying does not support --only-section", .{});
            if (pad_to) |_|
                fatal("zig objcopy: ELF to ELF copying does not support --pad-to", .{});

            fatal("unimplemented", .{});
        },
        else => fatal("unsupported output object format: {s}", .{@tagName(out_fmt)}),
    }

    try out.end();

    if (listen) {
        var stdin_reader = Io.File.stdin().reader(io, &stdin_buffer);
        var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);
        var server = try Server.init(.{
            .in = &stdin_reader.interface,
            .out = &stdout_writer.interface,
            .zig_version = builtin.zig_version_string,
        });

        var seen_update = false;
        while (true) {
            const hdr = try server.receiveMessage();
            switch (hdr.tag) {
                .exit => {
                    return std.process.cleanExit(io);
                },
                .update => {
                    if (seen_update) fatal("zig objcopy only supports 1 update for now", .{});
                    seen_update = true;

                    // The build system already knows what the output is at this point, we
                    // only need to communicate that the process has finished.
                    // Use the empty error bundle to indicate that the update is done.
                    try server.serveErrorBundle(std.zig.ErrorBundle.empty);
                },
                else => fatal("unsupported message: {s}", .{@tagName(hdr.tag)}),
            }
        }
    }
    return std.process.cleanExit(io);
}