diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2024-01-02 14:11:27 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-01-02 14:11:27 -0800 |
| commit | 289ae45c1b58e952867c4fa1e246d0ef7bc2ff64 (patch) | |
| tree | 5dd034143a2354b7b44496e684f1c764e2f9664c /src/Builtin.zig | |
| parent | c89bb3e141ee215add0b52930d48bffd8dae8342 (diff) | |
| parent | c546ddb3edc557fae4b932e5239b9dcb66117832 (diff) | |
| download | zig-289ae45c1b58e952867c4fa1e246d0ef7bc2ff64.tar.gz zig-289ae45c1b58e952867c4fa1e246d0ef7bc2ff64.zip | |
Merge pull request #18160 from ziglang/std-build-module
Move many settings from being per-Compilation to being per-Module
Diffstat (limited to 'src/Builtin.zig')
| -rw-r--r-- | src/Builtin.zig | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/src/Builtin.zig b/src/Builtin.zig new file mode 100644 index 0000000000..3211dd3a69 --- /dev/null +++ b/src/Builtin.zig @@ -0,0 +1,314 @@ +target: std.Target, +zig_backend: std.builtin.CompilerBackend, +output_mode: std.builtin.OutputMode, +link_mode: std.builtin.LinkMode, +is_test: bool, +test_evented_io: bool, +single_threaded: bool, +link_libc: bool, +link_libcpp: bool, +optimize_mode: std.builtin.OptimizeMode, +error_tracing: bool, +valgrind: bool, +sanitize_thread: bool, +pic: bool, +pie: bool, +strip: bool, +code_model: std.builtin.CodeModel, +omit_frame_pointer: bool, +wasi_exec_model: std.builtin.WasiExecModel, + +pub fn generate(opts: @This(), allocator: Allocator) Allocator.Error![:0]u8 { + var buffer = std.ArrayList(u8).init(allocator); + try append(opts, &buffer); + return buffer.toOwnedSliceSentinel(0); +} + +pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { + const target = opts.target; + const generic_arch_name = target.cpu.arch.genericName(); + const zig_backend = opts.zig_backend; + + @setEvalBranchQuota(4000); + try buffer.writer().print( + \\const std = @import("std"); + \\/// Zig version. When writing code that supports multiple versions of Zig, prefer + \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks. + \\pub const zig_version = std.SemanticVersion.parse(zig_version_string) catch unreachable; + \\pub const zig_version_string = "{s}"; + \\pub const zig_backend = std.builtin.CompilerBackend.{}; + \\ + \\pub const output_mode = std.builtin.OutputMode.{}; + \\pub const link_mode = std.builtin.LinkMode.{}; + \\pub const is_test = {}; + \\pub const single_threaded = {}; + \\pub const abi = std.Target.Abi.{}; + \\pub const cpu: std.Target.Cpu = .{{ + \\ .arch = .{}, + \\ .model = &std.Target.{}.cpu.{}, + \\ .features = std.Target.{}.featureSet(&[_]std.Target.{}.Feature{{ + \\ + , .{ + build_options.version, + std.zig.fmtId(@tagName(zig_backend)), + std.zig.fmtId(@tagName(opts.output_mode)), + std.zig.fmtId(@tagName(opts.link_mode)), + opts.is_test, + opts.single_threaded, + std.zig.fmtId(@tagName(target.abi)), + std.zig.fmtId(@tagName(target.cpu.arch)), + std.zig.fmtId(generic_arch_name), + std.zig.fmtId(target.cpu.model.name), + std.zig.fmtId(generic_arch_name), + std.zig.fmtId(generic_arch_name), + }); + + for (target.cpu.arch.allFeaturesList(), 0..) |feature, index_usize| { + const index = @as(std.Target.Cpu.Feature.Set.Index, @intCast(index_usize)); + const is_enabled = target.cpu.features.isEnabled(index); + if (is_enabled) { + try buffer.writer().print(" .{},\n", .{std.zig.fmtId(feature.name)}); + } + } + try buffer.writer().print( + \\ }}), + \\}}; + \\pub const os = std.Target.Os{{ + \\ .tag = .{}, + \\ .version_range = .{{ + , + .{std.zig.fmtId(@tagName(target.os.tag))}, + ); + + switch (target.os.getVersionRange()) { + .none => try buffer.appendSlice(" .none = {} },\n"), + .semver => |semver| try buffer.writer().print( + \\ .semver = .{{ + \\ .min = .{{ + \\ .major = {}, + \\ .minor = {}, + \\ .patch = {}, + \\ }}, + \\ .max = .{{ + \\ .major = {}, + \\ .minor = {}, + \\ .patch = {}, + \\ }}, + \\ }}}}, + \\ + , .{ + semver.min.major, + semver.min.minor, + semver.min.patch, + + semver.max.major, + semver.max.minor, + semver.max.patch, + }), + .linux => |linux| try buffer.writer().print( + \\ .linux = .{{ + \\ .range = .{{ + \\ .min = .{{ + \\ .major = {}, + \\ .minor = {}, + \\ .patch = {}, + \\ }}, + \\ .max = .{{ + \\ .major = {}, + \\ .minor = {}, + \\ .patch = {}, + \\ }}, + \\ }}, + \\ .glibc = .{{ + \\ .major = {}, + \\ .minor = {}, + \\ .patch = {}, + \\ }}, + \\ }}}}, + \\ + , .{ + linux.range.min.major, + linux.range.min.minor, + linux.range.min.patch, + + linux.range.max.major, + linux.range.max.minor, + linux.range.max.patch, + + linux.glibc.major, + linux.glibc.minor, + linux.glibc.patch, + }), + .windows => |windows| try buffer.writer().print( + \\ .windows = .{{ + \\ .min = {s}, + \\ .max = {s}, + \\ }}}}, + \\ + , + .{ windows.min, windows.max }, + ), + } + try buffer.appendSlice( + \\}; + \\pub const target: std.Target = .{ + \\ .cpu = cpu, + \\ .os = os, + \\ .abi = abi, + \\ .ofmt = object_format, + \\ + ); + + if (target.dynamic_linker.get()) |dl| { + try buffer.writer().print( + \\ .dynamic_linker = std.Target.DynamicLinker.init("{s}"), + \\}}; + \\ + , .{dl}); + } else { + try buffer.appendSlice( + \\ .dynamic_linker = std.Target.DynamicLinker.none, + \\}; + \\ + ); + } + + // This is so that compiler_rt and libc.zig libraries know whether they + // will eventually be linked with libc. They make different decisions + // about what to export depending on whether another libc will be linked + // in. For example, compiler_rt will not export the __chkstk symbol if it + // knows libc will provide it, and likewise c.zig will not export memcpy. + const link_libc = opts.link_libc; + + try buffer.writer().print( + \\pub const object_format = std.Target.ObjectFormat.{}; + \\pub const mode = std.builtin.OptimizeMode.{}; + \\pub const link_libc = {}; + \\pub const link_libcpp = {}; + \\pub const have_error_return_tracing = {}; + \\pub const valgrind_support = {}; + \\pub const sanitize_thread = {}; + \\pub const position_independent_code = {}; + \\pub const position_independent_executable = {}; + \\pub const strip_debug_info = {}; + \\pub const code_model = std.builtin.CodeModel.{}; + \\pub const omit_frame_pointer = {}; + \\ + , .{ + std.zig.fmtId(@tagName(target.ofmt)), + std.zig.fmtId(@tagName(opts.optimize_mode)), + link_libc, + opts.link_libcpp, + opts.error_tracing, + opts.valgrind, + opts.sanitize_thread, + opts.pic, + opts.pie, + opts.strip, + std.zig.fmtId(@tagName(opts.code_model)), + opts.omit_frame_pointer, + }); + + if (target.os.tag == .wasi) { + const wasi_exec_model_fmt = std.zig.fmtId(@tagName(opts.wasi_exec_model)); + try buffer.writer().print( + \\pub const wasi_exec_model = std.builtin.WasiExecModel.{}; + \\ + , .{wasi_exec_model_fmt}); + } + + if (opts.is_test) { + try buffer.appendSlice( + \\pub var test_functions: []const std.builtin.TestFn = undefined; // overwritten later + \\ + ); + if (opts.test_evented_io) { + try buffer.appendSlice( + \\pub const test_io_mode = .evented; + \\ + ); + } else { + try buffer.appendSlice( + \\pub const test_io_mode = .blocking; + \\ + ); + } + } +} + +pub fn populateFile(comp: *Compilation, mod: *Module, file: *File) !void { + assert(file.source_loaded == true); + + if (mod.root.statFile(mod.root_src_path)) |stat| { + if (stat.size != file.source.len) { + std.log.warn( + "the cached file '{}{s}' had the wrong size. Expected {d}, found {d}. " ++ + "Overwriting with correct file contents now", + .{ mod.root, mod.root_src_path, file.source.len, stat.size }, + ); + + try writeFile(file, mod); + } else { + file.stat = .{ + .size = stat.size, + .inode = stat.inode, + .mtime = stat.mtime, + }; + } + } else |err| switch (err) { + error.BadPathName => unreachable, // it's always "builtin.zig" + error.NameTooLong => unreachable, // it's always "builtin.zig" + error.PipeBusy => unreachable, // it's not a pipe + error.WouldBlock => unreachable, // not asking for non-blocking I/O + + error.FileNotFound => try writeFile(file, mod), + + else => |e| return e, + } + + log.debug("parsing and generating '{s}'", .{mod.root_src_path}); + + file.tree = try std.zig.Ast.parse(comp.gpa, file.source, .zig); + assert(file.tree.errors.len == 0); // builtin.zig must parse + file.tree_loaded = true; + + file.zir = try AstGen.generate(comp.gpa, file.tree); + assert(!file.zir.hasCompileErrors()); // builtin.zig must not have astgen errors + file.zir_loaded = true; + file.status = .success_zir; +} + +fn writeFile(file: *File, mod: *Module) !void { + var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + var af = try mod.root.atomicFile(mod.root_src_path, .{ .make_path = true }, &buf); + defer af.deinit(); + try af.file.writeAll(file.source); + af.finish() catch |err| switch (err) { + error.AccessDenied => switch (builtin.os.tag) { + .windows => { + // Very likely happened due to another process or thread + // simultaneously creating the same, correct builtin.zig file. + // This is not a problem; ignore it. + }, + else => return err, + }, + else => return err, + }; + + file.stat = .{ + .size = file.source.len, + .inode = 0, // dummy value + .mtime = 0, // dummy value + }; +} + +const builtin = @import("builtin"); +const std = @import("std"); +const Allocator = std.mem.Allocator; +const build_options = @import("build_options"); +const Module = @import("Package/Module.zig"); +const assert = std.debug.assert; +const AstGen = @import("AstGen.zig"); +const File = @import("Module.zig").File; +const Compilation = @import("Compilation.zig"); +const log = std.log.scoped(.builtin); |
