dev: introduce dev environments that enable compiler feature sets

This commit is contained in:
Jacob Young 2024-07-19 01:04:59 -04:00 committed by Andrew Kelley
parent b7e48c6bcd
commit 4f742c4cfc
16 changed files with 520 additions and 237 deletions

View File

@ -578,6 +578,7 @@ set(ZIG_STAGE2_SOURCES
src/codegen/spirv/Section.zig src/codegen/spirv/Section.zig
src/codegen/spirv/spec.zig src/codegen/spirv/spec.zig
src/crash_report.zig src/crash_report.zig
src/dev.zig
src/glibc.zig src/glibc.zig
src/introspect.zig src/introspect.zig
src/libcxx.zig src/libcxx.zig

View File

@ -140,8 +140,7 @@ int main(int argc, char **argv) {
"pub const value_tracing = false;\n" "pub const value_tracing = false;\n"
"pub const skip_non_native = false;\n" "pub const skip_non_native = false;\n"
"pub const force_gpa = false;\n" "pub const force_gpa = false;\n"
"pub const only_c = false;\n" "pub const dev = .core;\n"
"pub const only_core_functionality = true;\n"
, zig_version); , zig_version);
if (written < 100) if (written < 100)
panic("unable to write to config.zig file"); panic("unable to write to config.zig file");

View File

@ -8,6 +8,7 @@ const io = std.io;
const fs = std.fs; const fs = std.fs;
const InstallDirectoryOptions = std.Build.InstallDirectoryOptions; const InstallDirectoryOptions = std.Build.InstallDirectoryOptions;
const assert = std.debug.assert; const assert = std.debug.assert;
const DevEnv = @import("src/dev.zig").Env;
const zig_version: std.SemanticVersion = .{ .major = 0, .minor = 14, .patch = 0 }; const zig_version: std.SemanticVersion = .{ .major = 0, .minor = 14, .patch = 0 };
const stack_size = 32 * 1024 * 1024; const stack_size = 32 * 1024 * 1024;
@ -232,8 +233,7 @@ pub fn build(b: *std.Build) !void {
exe_options.addOption(bool, "llvm_has_arc", llvm_has_arc); exe_options.addOption(bool, "llvm_has_arc", llvm_has_arc);
exe_options.addOption(bool, "llvm_has_xtensa", llvm_has_xtensa); exe_options.addOption(bool, "llvm_has_xtensa", llvm_has_xtensa);
exe_options.addOption(bool, "force_gpa", force_gpa); exe_options.addOption(bool, "force_gpa", force_gpa);
exe_options.addOption(bool, "only_c", only_c); exe_options.addOption(DevEnv, "dev", b.option(DevEnv, "dev", "Build a compiler with a reduced feature set for development of specific features") orelse if (only_c) .bootstrap else .full);
exe_options.addOption(bool, "only_core_functionality", only_c);
if (link_libc) { if (link_libc) {
exe.linkLibC(); exe.linkLibC();
@ -393,8 +393,6 @@ pub fn build(b: *std.Build) !void {
test_cases_options.addOption(bool, "llvm_has_arc", llvm_has_arc); test_cases_options.addOption(bool, "llvm_has_arc", llvm_has_arc);
test_cases_options.addOption(bool, "llvm_has_xtensa", llvm_has_xtensa); test_cases_options.addOption(bool, "llvm_has_xtensa", llvm_has_xtensa);
test_cases_options.addOption(bool, "force_gpa", force_gpa); test_cases_options.addOption(bool, "force_gpa", force_gpa);
test_cases_options.addOption(bool, "only_c", only_c);
test_cases_options.addOption(bool, "only_core_functionality", true);
test_cases_options.addOption(bool, "enable_qemu", b.enable_qemu); test_cases_options.addOption(bool, "enable_qemu", b.enable_qemu);
test_cases_options.addOption(bool, "enable_wine", b.enable_wine); test_cases_options.addOption(bool, "enable_wine", b.enable_wine);
test_cases_options.addOption(bool, "enable_wasmtime", b.enable_wasmtime); test_cases_options.addOption(bool, "enable_wasmtime", b.enable_wasmtime);
@ -406,6 +404,7 @@ pub fn build(b: *std.Build) !void {
test_cases_options.addOption([:0]const u8, "version", version); test_cases_options.addOption([:0]const u8, "version", version);
test_cases_options.addOption(std.SemanticVersion, "semver", semver); test_cases_options.addOption(std.SemanticVersion, "semver", semver);
test_cases_options.addOption([]const []const u8, "test_filters", test_filters); test_cases_options.addOption([]const []const u8, "test_filters", test_filters);
test_cases_options.addOption(DevEnv, "dev", if (only_c) .bootstrap else .core);
var chosen_opt_modes_buf: [4]builtin.OptimizeMode = undefined; var chosen_opt_modes_buf: [4]builtin.OptimizeMode = undefined;
var chosen_mode_index: usize = 0; var chosen_mode_index: usize = 0;
@ -575,7 +574,6 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
exe_options.addOption(u32, "mem_leak_frames", 0); exe_options.addOption(u32, "mem_leak_frames", 0);
exe_options.addOption(bool, "have_llvm", false); exe_options.addOption(bool, "have_llvm", false);
exe_options.addOption(bool, "force_gpa", false); exe_options.addOption(bool, "force_gpa", false);
exe_options.addOption(bool, "only_c", true);
exe_options.addOption([:0]const u8, "version", version); exe_options.addOption([:0]const u8, "version", version);
exe_options.addOption(std.SemanticVersion, "semver", semver); exe_options.addOption(std.SemanticVersion, "semver", semver);
exe_options.addOption(bool, "enable_debug_extensions", false); exe_options.addOption(bool, "enable_debug_extensions", false);
@ -585,7 +583,7 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
exe_options.addOption(bool, "enable_tracy_callstack", false); exe_options.addOption(bool, "enable_tracy_callstack", false);
exe_options.addOption(bool, "enable_tracy_allocation", false); exe_options.addOption(bool, "enable_tracy_allocation", false);
exe_options.addOption(bool, "value_tracing", false); exe_options.addOption(bool, "value_tracing", false);
exe_options.addOption(bool, "only_core_functionality", true); exe_options.addOption(DevEnv, "dev", .bootstrap);
const run_opt = b.addSystemCommand(&.{ const run_opt = b.addSystemCommand(&.{
"wasm-opt", "wasm-opt",

View File

@ -38,6 +38,7 @@ const Zir = std.zig.Zir;
const Air = @import("Air.zig"); const Air = @import("Air.zig");
const Builtin = @import("Builtin.zig"); const Builtin = @import("Builtin.zig");
const LlvmObject = @import("codegen/llvm.zig").Object; const LlvmObject = @import("codegen/llvm.zig").Object;
const dev = @import("dev.zig");
pub const Config = @import("Compilation/Config.zig"); pub const Config = @import("Compilation/Config.zig");
@ -94,8 +95,15 @@ native_system_include_paths: []const []const u8,
force_undefined_symbols: std.StringArrayHashMapUnmanaged(void), force_undefined_symbols: std.StringArrayHashMapUnmanaged(void),
c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{}, c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{},
win32_resource_table: if (build_options.only_core_functionality) void else std.AutoArrayHashMapUnmanaged(*Win32Resource, void) = win32_resource_table: if (dev.env.supports(.win32_resource)) std.AutoArrayHashMapUnmanaged(*Win32Resource, void) else struct {
if (build_options.only_core_functionality) {} else .{}, pub fn keys(_: @This()) [0]void {
return .{};
}
pub fn count(_: @This()) u0 {
return 0;
}
pub fn deinit(_: @This(), _: Allocator) void {}
} = .{},
link_error_flags: link.File.ErrorFlags = .{}, link_error_flags: link.File.ErrorFlags = .{},
link_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{}, link_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{},
@ -125,7 +133,13 @@ c_object_work_queue: std.fifo.LinearFifo(*CObject, .Dynamic),
/// These jobs are to invoke the RC compiler to create a compiled resource file (.res), which /// These jobs are to invoke the RC compiler to create a compiled resource file (.res), which
/// gets linked with the Compilation. /// gets linked with the Compilation.
win32_resource_work_queue: if (build_options.only_core_functionality) void else std.fifo.LinearFifo(*Win32Resource, .Dynamic), win32_resource_work_queue: if (dev.env.supports(.win32_resource)) std.fifo.LinearFifo(*Win32Resource, .Dynamic) else struct {
pub fn ensureUnusedCapacity(_: @This(), _: u0) error{}!void {}
pub fn readItem(_: @This()) ?noreturn {
return null;
}
pub fn deinit(_: @This()) void {}
},
/// These jobs are to tokenize, parse, and astgen files, which may be outdated /// These jobs are to tokenize, parse, and astgen files, which may be outdated
/// since the last compilation, as well as scan for `@import` and queue up /// since the last compilation, as well as scan for `@import` and queue up
@ -142,8 +156,12 @@ failed_c_objects: std.AutoArrayHashMapUnmanaged(*CObject, *CObject.Diag.Bundle)
/// The ErrorBundle memory is owned by the `Win32Resource`, using Compilation's general purpose allocator. /// The ErrorBundle memory is owned by the `Win32Resource`, using Compilation's general purpose allocator.
/// This data is accessed by multiple threads and is protected by `mutex`. /// This data is accessed by multiple threads and is protected by `mutex`.
failed_win32_resources: if (build_options.only_core_functionality) void else std.AutoArrayHashMapUnmanaged(*Win32Resource, ErrorBundle) = failed_win32_resources: if (dev.env.supports(.win32_resource)) std.AutoArrayHashMapUnmanaged(*Win32Resource, ErrorBundle) else struct {
if (build_options.only_core_functionality) {} else .{}, pub fn values(_: @This()) [0]void {
return .{};
}
pub fn deinit(_: @This(), _: Allocator) void {}
} = .{},
/// Miscellaneous things that can fail. /// Miscellaneous things that can fail.
misc_failures: std.AutoArrayHashMapUnmanaged(MiscTask, MiscError) = .{}, misc_failures: std.AutoArrayHashMapUnmanaged(MiscTask, MiscError) = .{},
@ -1484,7 +1502,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
.done = false, .done = false,
}, },
.c_object_work_queue = std.fifo.LinearFifo(*CObject, .Dynamic).init(gpa), .c_object_work_queue = std.fifo.LinearFifo(*CObject, .Dynamic).init(gpa),
.win32_resource_work_queue = if (build_options.only_core_functionality) {} else std.fifo.LinearFifo(*Win32Resource, .Dynamic).init(gpa), .win32_resource_work_queue = if (dev.env.supports(.win32_resource)) std.fifo.LinearFifo(*Win32Resource, .Dynamic).init(gpa) else .{},
.astgen_work_queue = std.fifo.LinearFifo(Zcu.File.Index, .Dynamic).init(gpa), .astgen_work_queue = std.fifo.LinearFifo(Zcu.File.Index, .Dynamic).init(gpa),
.embed_file_work_queue = std.fifo.LinearFifo(*Zcu.EmbedFile, .Dynamic).init(gpa), .embed_file_work_queue = std.fifo.LinearFifo(*Zcu.EmbedFile, .Dynamic).init(gpa),
.c_source_files = options.c_source_files, .c_source_files = options.c_source_files,
@ -1711,7 +1729,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
comp.emit_llvm_ir != null or comp.emit_llvm_ir != null or
comp.emit_llvm_bc != null)) comp.emit_llvm_bc != null))
{ {
if (build_options.only_c) unreachable; dev.check(.llvm_backend);
if (opt_zcu) |zcu| zcu.llvm_object = try LlvmObject.create(arena, comp); if (opt_zcu) |zcu| zcu.llvm_object = try LlvmObject.create(arena, comp);
} }
@ -1738,8 +1756,11 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
} }
// Add a `Win32Resource` for each `rc_source_files` and one for `manifest_file`. // Add a `Win32Resource` for each `rc_source_files` and one for `manifest_file`.
if (!build_options.only_core_functionality) { const win32_resource_count =
try comp.win32_resource_table.ensureTotalCapacity(gpa, options.rc_source_files.len + @intFromBool(options.manifest_file != null)); options.rc_source_files.len + @intFromBool(options.manifest_file != null);
if (win32_resource_count > 0) {
dev.check(.win32_resource);
try comp.win32_resource_table.ensureTotalCapacity(gpa, win32_resource_count);
for (options.rc_source_files) |rc_source_file| { for (options.rc_source_files) |rc_source_file| {
const win32_resource = try gpa.create(Win32Resource); const win32_resource = try gpa.create(Win32Resource);
errdefer gpa.destroy(win32_resource); errdefer gpa.destroy(win32_resource);
@ -1905,9 +1926,7 @@ pub fn destroy(comp: *Compilation) void {
for (comp.work_queues) |work_queue| work_queue.deinit(); for (comp.work_queues) |work_queue| work_queue.deinit();
if (!InternPool.single_threaded) comp.codegen_work.queue.deinit(); if (!InternPool.single_threaded) comp.codegen_work.queue.deinit();
comp.c_object_work_queue.deinit(); comp.c_object_work_queue.deinit();
if (!build_options.only_core_functionality) {
comp.win32_resource_work_queue.deinit(); comp.win32_resource_work_queue.deinit();
}
comp.astgen_work_queue.deinit(); comp.astgen_work_queue.deinit();
comp.embed_file_work_queue.deinit(); comp.embed_file_work_queue.deinit();
@ -1956,7 +1975,6 @@ pub fn destroy(comp: *Compilation) void {
} }
comp.failed_c_objects.deinit(gpa); comp.failed_c_objects.deinit(gpa);
if (!build_options.only_core_functionality) {
for (comp.win32_resource_table.keys()) |key| { for (comp.win32_resource_table.keys()) |key| {
key.destroy(gpa); key.destroy(gpa);
} }
@ -1966,7 +1984,6 @@ pub fn destroy(comp: *Compilation) void {
value.deinit(gpa); value.deinit(gpa);
} }
comp.failed_win32_resources.deinit(gpa); comp.failed_win32_resources.deinit(gpa);
}
for (comp.link_errors.items) |*item| item.deinit(gpa); for (comp.link_errors.items) |*item| item.deinit(gpa);
comp.link_errors.deinit(gpa); comp.link_errors.deinit(gpa);
@ -2153,7 +2170,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
// For compiling Win32 resources, we rely on the cache hash system to avoid duplicating work. // For compiling Win32 resources, we rely on the cache hash system to avoid duplicating work.
// Add a Job for each Win32 resource file. // Add a Job for each Win32 resource file.
if (!build_options.only_core_functionality) {
try comp.win32_resource_work_queue.ensureUnusedCapacity(comp.win32_resource_table.count()); try comp.win32_resource_work_queue.ensureUnusedCapacity(comp.win32_resource_table.count());
for (comp.win32_resource_table.keys()) |key| { for (comp.win32_resource_table.keys()) |key| {
comp.win32_resource_work_queue.writeItemAssumeCapacity(key); comp.win32_resource_work_queue.writeItemAssumeCapacity(key);
@ -2164,7 +2180,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
.manifest => continue, .manifest => continue,
}; };
} }
}
if (comp.module) |zcu| { if (comp.module) |zcu| {
const pt: Zcu.PerThread = .{ .zcu = zcu, .tid = .main }; const pt: Zcu.PerThread = .{ .zcu = zcu, .tid = .main };
@ -2397,7 +2412,6 @@ fn flush(comp: *Compilation, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
try link.File.C.flushEmitH(zcu); try link.File.C.flushEmitH(zcu);
if (zcu.llvm_object) |llvm_object| { if (zcu.llvm_object) |llvm_object| {
if (build_options.only_c) unreachable;
const default_emit = switch (comp.cache_use) { const default_emit = switch (comp.cache_use) {
.whole => |whole| .{ .whole => |whole| .{
.directory = whole.tmp_artifact_directory.?, .directory = whole.tmp_artifact_directory.?,
@ -2541,7 +2555,6 @@ fn addNonIncrementalStuffToCacheManifest(
man.hash.addListOfBytes(key.src.extra_flags); man.hash.addListOfBytes(key.src.extra_flags);
} }
if (!build_options.only_core_functionality) {
for (comp.win32_resource_table.keys()) |key| { for (comp.win32_resource_table.keys()) |key| {
switch (key.src) { switch (key.src) {
.rc => |rc_src| { .rc => |rc_src| {
@ -2553,7 +2566,6 @@ fn addNonIncrementalStuffToCacheManifest(
}, },
} }
} }
}
man.hash.add(comp.config.use_llvm); man.hash.add(comp.config.use_llvm);
man.hash.add(comp.config.use_lib_llvm); man.hash.add(comp.config.use_lib_llvm);
@ -2695,8 +2707,6 @@ pub fn emitLlvmObject(
llvm_object: *LlvmObject, llvm_object: *LlvmObject,
prog_node: std.Progress.Node, prog_node: std.Progress.Node,
) !void { ) !void {
if (build_options.only_c) @compileError("unreachable");
const sub_prog_node = prog_node.start("LLVM Emit Object", 0); const sub_prog_node = prog_node.start("LLVM Emit Object", 0);
defer sub_prog_node.end(); defer sub_prog_node.end();
@ -2860,6 +2870,7 @@ fn reportMultiModuleErrors(pt: Zcu.PerThread) !void {
/// or whatever is needed so that it can be executed. /// or whatever is needed so that it can be executed.
/// After this, one must call` makeFileWritable` before calling `update`. /// After this, one must call` makeFileWritable` before calling `update`.
pub fn makeBinFileExecutable(comp: *Compilation) !void { pub fn makeBinFileExecutable(comp: *Compilation) !void {
if (!dev.env.supports(.make_executable)) return;
const lf = comp.bin_file orelse return; const lf = comp.bin_file orelse return;
return lf.makeExecutable(); return lf.makeExecutable();
} }
@ -2897,6 +2908,8 @@ const Header = extern struct {
/// saved, such as the target and most CLI flags. A cache hit will only occur /// saved, such as the target and most CLI flags. A cache hit will only occur
/// when subsequent compiler invocations use the same set of flags. /// when subsequent compiler invocations use the same set of flags.
pub fn saveState(comp: *Compilation) !void { pub fn saveState(comp: *Compilation) !void {
dev.check(.incremental);
const lf = comp.bin_file orelse return; const lf = comp.bin_file orelse return;
const gpa = comp.gpa; const gpa = comp.gpa;
@ -3001,11 +3014,9 @@ pub fn totalErrorCount(comp: *Compilation) u32 {
total += bundle.diags.len; total += bundle.diags.len;
} }
if (!build_options.only_core_functionality) {
for (comp.failed_win32_resources.values()) |errs| { for (comp.failed_win32_resources.values()) |errs| {
total += errs.errorMessageCount(); total += errs.errorMessageCount();
} }
}
if (comp.module) |zcu| { if (comp.module) |zcu| {
total += zcu.failed_exports.count(); total += zcu.failed_exports.count();
@ -3082,11 +3093,9 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
try diag_bundle.addToErrorBundle(&bundle); try diag_bundle.addToErrorBundle(&bundle);
} }
if (!build_options.only_core_functionality) {
for (comp.failed_win32_resources.values()) |error_bundle| { for (comp.failed_win32_resources.values()) |error_bundle| {
try bundle.addBundleAsRoots(error_bundle); try bundle.addBundleAsRoots(error_bundle);
} }
}
for (comp.lld_errors.items) |lld_error| { for (comp.lld_errors.items) |lld_error| {
const notes_len = @as(u32, @intCast(lld_error.context_lines.len)); const notes_len = @as(u32, @intCast(lld_error.context_lines.len));
@ -3509,12 +3518,11 @@ fn performAllTheWorkInner(
comp.work_queue_wait_group.reset(); comp.work_queue_wait_group.reset();
defer comp.work_queue_wait_group.wait(); defer comp.work_queue_wait_group.wait();
if (!build_options.only_c and !build_options.only_core_functionality) {
if (comp.docs_emit != null) { if (comp.docs_emit != null) {
dev.check(.docs_emit);
comp.thread_pool.spawnWg(&comp.work_queue_wait_group, workerDocsCopy, .{comp}); comp.thread_pool.spawnWg(&comp.work_queue_wait_group, workerDocsCopy, .{comp});
comp.work_queue_wait_group.spawnManager(workerDocsWasm, .{ comp, main_progress_node }); comp.work_queue_wait_group.spawnManager(workerDocsWasm, .{ comp, main_progress_node });
} }
}
{ {
const astgen_frame = tracy.namedFrame("astgen"); const astgen_frame = tracy.namedFrame("astgen");
@ -3585,14 +3593,12 @@ fn performAllTheWorkInner(
}); });
} }
if (!build_options.only_core_functionality) {
while (comp.win32_resource_work_queue.readItem()) |win32_resource| { while (comp.win32_resource_work_queue.readItem()) |win32_resource| {
comp.thread_pool.spawnWg(&comp.work_queue_wait_group, workerUpdateWin32Resource, .{ comp.thread_pool.spawnWg(&comp.work_queue_wait_group, workerUpdateWin32Resource, .{
comp, win32_resource, main_progress_node, comp, win32_resource, main_progress_node,
}); });
} }
} }
}
if (comp.module) |zcu| { if (comp.module) |zcu| {
const pt: Zcu.PerThread = .{ .zcu = zcu, .tid = .main }; const pt: Zcu.PerThread = .{ .zcu = zcu, .tid = .main };
@ -3867,9 +3873,6 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
}; };
}, },
.windows_import_lib => |index| { .windows_import_lib => |index| {
if (build_options.only_c)
@panic("building import libs not included in core functionality");
const named_frame = tracy.namedFrame("windows_import_lib"); const named_frame = tracy.namedFrame("windows_import_lib");
defer named_frame.end(); defer named_frame.end();
@ -4466,7 +4469,8 @@ pub const CImportResult = struct {
/// This API is currently coupled pretty tightly to stage1's needs; it will need to be reworked /// This API is currently coupled pretty tightly to stage1's needs; it will need to be reworked
/// a bit when we want to start using it from self-hosted. /// a bit when we want to start using it from self-hosted.
pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module) !CImportResult { pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module) !CImportResult {
if (build_options.only_core_functionality) @panic("@cImport is not available in a zig2.c build"); dev.check(.translate_c_command);
const tracy_trace = trace(@src()); const tracy_trace = trace(@src());
defer tracy_trace.end(); defer tracy_trace.end();

View File

@ -38,6 +38,7 @@ const Alignment = InternPool.Alignment;
const AnalUnit = InternPool.AnalUnit; const AnalUnit = InternPool.AnalUnit;
const BuiltinFn = std.zig.BuiltinFn; const BuiltinFn = std.zig.BuiltinFn;
const LlvmObject = @import("codegen/llvm.zig").Object; const LlvmObject = @import("codegen/llvm.zig").Object;
const dev = @import("dev.zig");
comptime { comptime {
@setEvalBranchQuota(4000); @setEvalBranchQuota(4000);
@ -57,7 +58,7 @@ comp: *Compilation,
/// Usually, the LlvmObject is managed by linker code, however, in the case /// Usually, the LlvmObject is managed by linker code, however, in the case
/// that -fno-emit-bin is specified, the linker code never executes, so we /// that -fno-emit-bin is specified, the linker code never executes, so we
/// store the LlvmObject here. /// store the LlvmObject here.
llvm_object: ?*LlvmObject, llvm_object: if (dev.env.supports(.llvm_backend)) ?*LlvmObject else ?noreturn,
/// Pointer to externally managed resource. /// Pointer to externally managed resource.
root_mod: *Package.Module, root_mod: *Package.Module,
@ -2403,10 +2404,7 @@ pub fn deinit(zcu: *Zcu) void {
const pt: Zcu.PerThread = .{ .tid = .main, .zcu = zcu }; const pt: Zcu.PerThread = .{ .tid = .main, .zcu = zcu };
const gpa = zcu.gpa; const gpa = zcu.gpa;
if (zcu.llvm_object) |llvm_object| { if (zcu.llvm_object) |llvm_object| llvm_object.deinit();
if (build_options.only_c) unreachable;
llvm_object.deinit();
}
for (zcu.import_table.keys()) |key| { for (zcu.import_table.keys()) |key| {
gpa.free(key); gpa.free(key);
@ -3041,7 +3039,7 @@ pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {
// `updateExports` on flush). // `updateExports` on flush).
// This case is needed because in some rare edge cases, `Sema` wants to add and delete exports // This case is needed because in some rare edge cases, `Sema` wants to add and delete exports
// within a single update. // within a single update.
if (!build_options.only_c) { if (dev.env.supports(.incremental)) {
for (exports, exports_base..) |exp, export_idx| { for (exports, exports_base..) |exp, export_idx| {
if (zcu.comp.bin_file) |lf| { if (zcu.comp.bin_file) |lf| {
lf.deleteExport(exp.exported, exp.opts.name); lf.deleteExport(exp.exported, exp.opts.name);

View File

@ -64,6 +64,7 @@ pub fn astGenFile(
path_digest: Cache.BinDigest, path_digest: Cache.BinDigest,
opt_root_decl: Zcu.Decl.OptionalIndex, opt_root_decl: Zcu.Decl.OptionalIndex,
) !void { ) !void {
dev.check(.ast_gen);
assert(!file.mod.isBuiltin()); assert(!file.mod.isBuiltin());
const tracy = trace(@src()); const tracy = trace(@src());
@ -504,6 +505,8 @@ pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.Sem
/// For example an inferred error set is not resolved until after `analyzeFnBody`. /// For example an inferred error set is not resolved until after `analyzeFnBody`.
/// is called. /// is called.
pub fn ensureDeclAnalyzed(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) Zcu.SemaError!void { pub fn ensureDeclAnalyzed(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) Zcu.SemaError!void {
dev.check(.sema);
const tracy = trace(@src()); const tracy = trace(@src());
defer tracy.end(); defer tracy.end();
@ -552,9 +555,9 @@ pub fn ensureDeclAnalyzed(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) Zcu.Sem
} }
if (was_outdated) { if (was_outdated) {
dev.check(.incremental);
// The exports this Decl performs will be re-discovered, so we remove them here // The exports this Decl performs will be re-discovered, so we remove them here
// prior to re-analysis. // prior to re-analysis.
if (build_options.only_c) unreachable;
mod.deleteUnitExports(decl_as_depender); mod.deleteUnitExports(decl_as_depender);
mod.deleteUnitReferences(decl_as_depender); mod.deleteUnitReferences(decl_as_depender);
} }
@ -623,6 +626,8 @@ pub fn ensureDeclAnalyzed(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) Zcu.Sem
} }
pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: InternPool.Index) Zcu.SemaError!void { pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: InternPool.Index) Zcu.SemaError!void {
dev.check(.sema);
const tracy = trace(@src()); const tracy = trace(@src());
defer tracy.end(); defer tracy.end();
@ -684,7 +689,7 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter
zcu.potentially_outdated.swapRemove(func_as_depender); zcu.potentially_outdated.swapRemove(func_as_depender);
if (was_outdated) { if (was_outdated) {
if (build_options.only_c) unreachable; dev.check(.incremental);
_ = zcu.outdated_ready.swapRemove(func_as_depender); _ = zcu.outdated_ready.swapRemove(func_as_depender);
zcu.deleteUnitExports(func_as_depender); zcu.deleteUnitExports(func_as_depender);
zcu.deleteUnitReferences(func_as_depender); zcu.deleteUnitReferences(func_as_depender);
@ -836,7 +841,6 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: Ai
}, },
}; };
} else if (zcu.llvm_object) |llvm_object| { } else if (zcu.llvm_object) |llvm_object| {
if (build_options.only_c) unreachable;
llvm_object.updateFunc(pt, func_index, air, liveness) catch |err| switch (err) { llvm_object.updateFunc(pt, func_index, air, liveness) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory, error.OutOfMemory => return error.OutOfMemory,
}; };
@ -845,6 +849,7 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: Ai
/// https://github.com/ziglang/zig/issues/14307 /// https://github.com/ziglang/zig/issues/14307
pub fn semaPkg(pt: Zcu.PerThread, pkg: *Module) !void { pub fn semaPkg(pt: Zcu.PerThread, pkg: *Module) !void {
dev.check(.sema);
const import_file_result = try pt.importPkg(pkg); const import_file_result = try pt.importPkg(pkg);
const root_decl_index = pt.zcu.fileRootDecl(import_file_result.file_index); const root_decl_index = pt.zcu.fileRootDecl(import_file_result.file_index);
if (root_decl_index == .none) { if (root_decl_index == .none) {
@ -2481,7 +2486,6 @@ fn processExportsInner(
if (zcu.comp.bin_file) |lf| { if (zcu.comp.bin_file) |lf| {
try zcu.handleUpdateExports(export_indices, lf.updateExports(pt, exported, export_indices)); try zcu.handleUpdateExports(export_indices, lf.updateExports(pt, exported, export_indices));
} else if (zcu.llvm_object) |llvm_object| { } else if (zcu.llvm_object) |llvm_object| {
if (build_options.only_c) unreachable;
try zcu.handleUpdateExports(export_indices, llvm_object.updateExports(pt, exported, export_indices)); try zcu.handleUpdateExports(export_indices, llvm_object.updateExports(pt, exported, export_indices));
} }
} }
@ -2654,7 +2658,6 @@ pub fn linkerUpdateDecl(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) !void {
}, },
}; };
} else if (zcu.llvm_object) |llvm_object| { } else if (zcu.llvm_object) |llvm_object| {
if (build_options.only_c) unreachable;
llvm_object.updateDecl(pt, decl_index) catch |err| switch (err) { llvm_object.updateDecl(pt, decl_index) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory, error.OutOfMemory => return error.OutOfMemory,
}; };
@ -3271,6 +3274,7 @@ const BigIntMutable = std.math.big.int.Mutable;
const build_options = @import("build_options"); const build_options = @import("build_options");
const builtin = @import("builtin"); const builtin = @import("builtin");
const Cache = std.Build.Cache; const Cache = std.Build.Cache;
const dev = @import("../dev.zig");
const InternPool = @import("../InternPool.zig"); const InternPool = @import("../InternPool.zig");
const isUpDir = @import("../introspect.zig").isUpDir; const isUpDir = @import("../introspect.zig").isUpDir;
const Liveness = @import("../Liveness.zig"); const Liveness = @import("../Liveness.zig");

View File

@ -22,6 +22,7 @@ const Type = @import("Type.zig");
const Value = @import("Value.zig"); const Value = @import("Value.zig");
const Zir = std.zig.Zir; const Zir = std.zig.Zir;
const Alignment = InternPool.Alignment; const Alignment = InternPool.Alignment;
const dev = @import("dev.zig");
pub const Result = union(enum) { pub const Result = union(enum) {
/// The `code` parameter passed to `generateSymbol` has the value ok. /// The `code` parameter passed to `generateSymbol` has the value ok.
@ -43,6 +44,23 @@ pub const DebugInfoOutput = union(enum) {
none, none,
}; };
fn devFeatureForBackend(comptime backend: std.builtin.CompilerBackend) dev.Feature {
comptime assert(mem.startsWith(u8, @tagName(backend), "stage2_"));
return @field(dev.Feature, @tagName(backend)["stage2_".len..] ++ "_backend");
}
fn importBackend(comptime backend: std.builtin.CompilerBackend) type {
return switch (backend) {
.stage2_aarch64 => @import("arch/aarch64/CodeGen.zig"),
.stage2_arm => @import("arch/arm/CodeGen.zig"),
.stage2_riscv64 => @import("arch/riscv64/CodeGen.zig"),
.stage2_sparc64 => @import("arch/sparc64/CodeGen.zig"),
.stage2_wasm => @import("arch/wasm/CodeGen.zig"),
.stage2_x86_64 => @import("arch/x86_64/CodeGen.zig"),
else => unreachable,
};
}
pub fn generateFunction( pub fn generateFunction(
lf: *link.File, lf: *link.File,
pt: Zcu.PerThread, pt: Zcu.PerThread,
@ -58,21 +76,18 @@ pub fn generateFunction(
const decl = zcu.declPtr(func.owner_decl); const decl = zcu.declPtr(func.owner_decl);
const namespace = zcu.namespacePtr(decl.src_namespace); const namespace = zcu.namespacePtr(decl.src_namespace);
const target = namespace.fileScope(zcu).mod.resolved_target.result; const target = namespace.fileScope(zcu).mod.resolved_target.result;
switch (target.cpu.arch) { switch (target_util.zigBackend(target, false)) {
.arm,
.armeb,
=> return @import("arch/arm/CodeGen.zig").generate(lf, pt, src_loc, func_index, air, liveness, code, debug_output),
.aarch64,
.aarch64_be,
.aarch64_32,
=> return @import("arch/aarch64/CodeGen.zig").generate(lf, pt, src_loc, func_index, air, liveness, code, debug_output),
.riscv64 => return @import("arch/riscv64/CodeGen.zig").generate(lf, pt, src_loc, func_index, air, liveness, code, debug_output),
.sparc64 => return @import("arch/sparc64/CodeGen.zig").generate(lf, pt, src_loc, func_index, air, liveness, code, debug_output),
.x86_64 => return @import("arch/x86_64/CodeGen.zig").generate(lf, pt, src_loc, func_index, air, liveness, code, debug_output),
.wasm32,
.wasm64,
=> return @import("arch/wasm/CodeGen.zig").generate(lf, pt, src_loc, func_index, air, liveness, code, debug_output),
else => unreachable, else => unreachable,
inline .stage2_aarch64,
.stage2_arm,
.stage2_riscv64,
.stage2_sparc64,
.stage2_wasm,
.stage2_x86_64,
=> |backend| {
dev.check(devFeatureForBackend(backend));
return importBackend(backend).generate(lf, pt, src_loc, func_index, air, liveness, code, debug_output);
},
} }
} }
@ -89,9 +104,12 @@ pub fn generateLazyFunction(
const decl = zcu.declPtr(decl_index); const decl = zcu.declPtr(decl_index);
const namespace = zcu.namespacePtr(decl.src_namespace); const namespace = zcu.namespacePtr(decl.src_namespace);
const target = namespace.fileScope(zcu).mod.resolved_target.result; const target = namespace.fileScope(zcu).mod.resolved_target.result;
switch (target.cpu.arch) { switch (target_util.zigBackend(target, false)) {
.x86_64 => return @import("arch/x86_64/CodeGen.zig").generateLazy(lf, pt, src_loc, lazy_sym, code, debug_output),
else => unreachable, else => unreachable,
inline .stage2_x86_64 => |backend| {
dev.check(devFeatureForBackend(backend));
return importBackend(backend).generateLazy(lf, pt, src_loc, lazy_sym, code, debug_output);
},
} }
} }

View File

@ -868,7 +868,6 @@ pub const Object = struct {
pub const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, Builder.Type); pub const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, Builder.Type);
pub fn create(arena: Allocator, comp: *Compilation) !*Object { pub fn create(arena: Allocator, comp: *Compilation) !*Object {
if (build_options.only_c) unreachable;
const gpa = comp.gpa; const gpa = comp.gpa;
const target = comp.root_mod.resolved_target.result; const target = comp.root_mod.resolved_target.result;
const llvm_target_triple = try targetTriple(arena, target); const llvm_target_triple = try targetTriple(arena, target);

238
src/dev.zig Normal file
View File

@ -0,0 +1,238 @@
pub const Env = enum {
/// zig1 features
bootstrap,
/// zig2 features
core,
/// stage3 features
full,
/// - `zig cc`
/// - `zig c++`
/// - `zig translate-c`
c_source,
/// - `zig ast-check`
/// - `zig changelist`
/// - `zig dump-zir`
ast_gen,
/// - ast_gen
/// - `zig build-* -fno-emit-bin`
sema,
/// - sema
/// - jit command on x86_64-linux host
/// - `zig build-* -fno-llvm -fno-lld -target x86_64-linux`
@"x86_64-linux",
pub inline fn supports(comptime dev_env: Env, comptime feature: Feature) bool {
return switch (dev_env) {
.full => true,
.bootstrap => switch (feature) {
.build_exe_command,
.build_obj_command,
.ast_gen,
.sema,
.c_backend,
.c_linker,
=> true,
else => false,
},
.core => switch (feature) {
.build_exe_command,
.build_lib_command,
.build_obj_command,
.test_command,
.run_command,
.ar_command,
.build_command,
.clang_command,
.stdio_listen,
.build_import_lib,
.make_executable,
.make_writable,
.incremental,
.ast_gen,
.sema,
.llvm_backend,
.c_backend,
.wasm_backend,
.arm_backend,
.x86_64_backend,
.aarch64_backend,
.x86_backend,
.riscv64_backend,
.sparc64_backend,
.spirv64_backend,
.lld_linker,
.coff_linker,
.elf_linker,
.macho_linker,
.c_linker,
.wasm_linker,
.spirv_linker,
.plan9_linker,
.nvptx_linker,
=> true,
.cc_command,
.translate_c_command,
.jit_command,
.fetch_command,
.init_command,
.targets_command,
.version_command,
.env_command,
.zen_command,
.help_command,
.ast_check_command,
.detect_cpu_command,
.changelist_command,
.dump_zir_command,
.llvm_ints_command,
.docs_emit,
// Avoid dragging networking into zig2.c because it adds dependencies on some
// linker symbols that are annoying to satisfy while bootstrapping.
.network_listen,
.win32_resource,
=> false,
},
.c_source => switch (feature) {
.clang_command,
.cc_command,
.translate_c_command,
=> true,
else => false,
},
.ast_gen => switch (feature) {
.ast_check_command,
.changelist_command,
.dump_zir_command,
.make_executable,
.make_writable,
.incremental,
.ast_gen,
=> true,
else => false,
},
.sema => switch (feature) {
.build_exe_command,
.build_lib_command,
.build_obj_command,
.test_command,
.run_command,
.sema,
=> true,
else => Env.ast_gen.supports(feature),
},
.@"x86_64-linux" => switch (feature) {
.x86_64_backend,
.elf_linker,
=> true,
else => Env.sema.supports(feature),
},
};
}
pub inline fn supportsAny(comptime dev_env: Env, comptime features: []const Feature) bool {
inline for (features) |feature| if (dev_env.supports(feature)) return true;
return false;
}
pub inline fn supportsAll(comptime dev_env: Env, comptime features: []const Feature) bool {
inline for (features) |feature| if (!dev_env.supports(feature)) return false;
return true;
}
};
pub const Feature = enum {
build_exe_command,
build_lib_command,
build_obj_command,
test_command,
run_command,
ar_command,
build_command,
clang_command,
cc_command,
translate_c_command,
jit_command,
fetch_command,
init_command,
targets_command,
version_command,
env_command,
zen_command,
help_command,
ast_check_command,
detect_cpu_command,
changelist_command,
dump_zir_command,
llvm_ints_command,
docs_emit,
stdio_listen,
network_listen,
build_import_lib,
win32_resource,
make_executable,
make_writable,
incremental,
ast_gen,
sema,
llvm_backend,
c_backend,
wasm_backend,
arm_backend,
x86_64_backend,
aarch64_backend,
x86_backend,
riscv64_backend,
sparc64_backend,
spirv64_backend,
lld_linker,
coff_linker,
elf_linker,
macho_linker,
c_linker,
wasm_linker,
spirv_linker,
plan9_linker,
nvptx_linker,
};
/// Makes the code following the call to this function unreachable if `feature` is disabled.
pub fn check(comptime feature: Feature) if (env.supports(feature)) void else noreturn {
if (env.supports(feature)) return;
@panic("development environment " ++ @tagName(env) ++ " does not support feature " ++ @tagName(feature));
}
/// Makes the code following the call to this function unreachable if all of `features` are disabled.
pub fn checkAny(comptime features: []const Feature) if (env.supportsAny(features)) void else noreturn {
if (env.supportsAny(features)) return;
comptime var feature_tags: []const u8 = "";
inline for (features[0 .. features.len - 1]) |feature| feature_tags = feature_tags ++ @tagName(feature) ++ ", ";
feature_tags = feature_tags ++ "or " ++ @tagName(features[features.len - 1]);
@panic("development environment " ++ @tagName(env) ++ " does not support feature " ++ feature_tags);
}
/// Makes the code following the call to this function unreachable if any of `features` are disabled.
pub fn checkAll(comptime features: []const Feature) if (env.supportsAll(features)) void else noreturn {
if (env.supportsAll(features)) return;
inline for (features) |feature| if (!env.supports(feature))
@panic("development environment " ++ @tagName(env) ++ " does not support feature " ++ @tagName(feature));
}
const build_options = @import("build_options");
pub const env: Env = if (@hasDecl(build_options, "dev"))
@field(Env, @tagName(build_options.dev))
else if (@hasDecl(build_options, "only_c") and build_options.only_c)
.bootstrap
else if (@hasDecl(build_options, "only_core_functionality") and build_options.only_core_functionality)
.core
else
.full;

View File

@ -21,6 +21,7 @@ const Value = @import("Value.zig");
const LlvmObject = @import("codegen/llvm.zig").Object; const LlvmObject = @import("codegen/llvm.zig").Object;
const lldMain = @import("main.zig").lldMain; const lldMain = @import("main.zig").lldMain;
const Package = @import("Package.zig"); const Package = @import("Package.zig");
const dev = @import("dev.zig");
/// When adding a new field, remember to update `hashAddSystemLibs`. /// When adding a new field, remember to update `hashAddSystemLibs`.
/// These are *always* dynamically linked. Static libraries will be /// These are *always* dynamically linked. Static libraries will be
@ -192,7 +193,7 @@ pub const File = struct {
) !*File { ) !*File {
switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) { switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) {
inline else => |tag| { inline else => |tag| {
if (tag != .c and build_options.only_c) unreachable; dev.check(tag.devFeature());
const ptr = try tag.Type().open(arena, comp, emit, options); const ptr = try tag.Type().open(arena, comp, emit, options);
return &ptr.base; return &ptr.base;
}, },
@ -207,7 +208,7 @@ pub const File = struct {
) !*File { ) !*File {
switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) { switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) {
inline else => |tag| { inline else => |tag| {
if (tag != .c and build_options.only_c) unreachable; dev.check(tag.devFeature());
const ptr = try tag.Type().createEmpty(arena, comp, emit, options); const ptr = try tag.Type().createEmpty(arena, comp, emit, options);
return &ptr.base; return &ptr.base;
}, },
@ -219,12 +220,13 @@ pub const File = struct {
} }
pub fn makeWritable(base: *File) !void { pub fn makeWritable(base: *File) !void {
dev.check(.make_writable);
const comp = base.comp; const comp = base.comp;
const gpa = comp.gpa; const gpa = comp.gpa;
switch (base.tag) { switch (base.tag) {
.coff, .elf, .macho, .plan9, .wasm => { .coff, .elf, .macho, .plan9, .wasm => {
if (build_options.only_c) unreachable;
if (base.file != null) return; if (base.file != null) return;
dev.checkAny(&.{ .coff_linker, .elf_linker, .macho_linker, .plan9_linker, .wasm_linker });
const emit = base.emit; const emit = base.emit;
if (base.child_pid) |pid| { if (base.child_pid) |pid| {
if (builtin.os.tag == .windows) { if (builtin.os.tag == .windows) {
@ -263,11 +265,12 @@ pub const File = struct {
.mode = determineMode(use_lld, output_mode, link_mode), .mode = determineMode(use_lld, output_mode, link_mode),
}); });
}, },
.c, .spirv, .nvptx => {}, .c, .spirv, .nvptx => dev.checkAny(&.{ .c_linker, .spirv_linker, .nvptx_linker }),
} }
} }
pub fn makeExecutable(base: *File) !void { pub fn makeExecutable(base: *File) !void {
dev.check(.make_executable);
const comp = base.comp; const comp = base.comp;
const output_mode = comp.config.output_mode; const output_mode = comp.config.output_mode;
const link_mode = comp.config.link_mode; const link_mode = comp.config.link_mode;
@ -283,7 +286,7 @@ pub const File = struct {
} }
switch (base.tag) { switch (base.tag) {
.elf => if (base.file) |f| { .elf => if (base.file) |f| {
if (build_options.only_c) unreachable; dev.check(.elf_linker);
if (base.zcu_object_sub_path != null and use_lld) { if (base.zcu_object_sub_path != null and use_lld) {
// The file we have open is not the final file that we want to // The file we have open is not the final file that we want to
// make executable, so we don't have to close it. // make executable, so we don't have to close it.
@ -302,7 +305,7 @@ pub const File = struct {
} }
}, },
.coff, .macho, .plan9, .wasm => if (base.file) |f| { .coff, .macho, .plan9, .wasm => if (base.file) |f| {
if (build_options.only_c) unreachable; dev.checkAny(&.{ .coff_linker, .macho_linker, .plan9_linker, .wasm_linker });
if (base.zcu_object_sub_path != null) { if (base.zcu_object_sub_path != null) {
// The file we have open is not the final file that we want to // The file we have open is not the final file that we want to
// make executable, so we don't have to close it. // make executable, so we don't have to close it.
@ -321,7 +324,7 @@ pub const File = struct {
} }
} }
}, },
.c, .spirv, .nvptx => {}, .c, .spirv, .nvptx => dev.checkAny(&.{ .c_linker, .spirv_linker, .nvptx_linker }),
} }
} }
@ -366,13 +369,13 @@ pub const File = struct {
/// constant. Returns the symbol index of the lowered constant in the read-only section /// constant. Returns the symbol index of the lowered constant in the read-only section
/// of the final binary. /// of the final binary.
pub fn lowerUnnamedConst(base: *File, pt: Zcu.PerThread, val: Value, decl_index: InternPool.DeclIndex) UpdateDeclError!u32 { pub fn lowerUnnamedConst(base: *File, pt: Zcu.PerThread, val: Value, decl_index: InternPool.DeclIndex) UpdateDeclError!u32 {
if (build_options.only_c) @compileError("unreachable");
switch (base.tag) { switch (base.tag) {
.spirv => unreachable, .spirv => unreachable,
.c => unreachable, .c => unreachable,
.nvptx => unreachable, .nvptx => unreachable,
inline else => |t| { inline else => |tag| {
return @as(*t.Type(), @fieldParentPtr("base", base)).lowerUnnamedConst(pt, val, decl_index); dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).lowerUnnamedConst(pt, val, decl_index);
}, },
} }
} }
@ -383,15 +386,15 @@ pub const File = struct {
/// Optionally, it is possible to specify where to expect the symbol defined if it /// Optionally, it is possible to specify where to expect the symbol defined if it
/// is an import. /// is an import.
pub fn getGlobalSymbol(base: *File, name: []const u8, lib_name: ?[]const u8) UpdateDeclError!u32 { pub fn getGlobalSymbol(base: *File, name: []const u8, lib_name: ?[]const u8) UpdateDeclError!u32 {
if (build_options.only_c) @compileError("unreachable");
log.debug("getGlobalSymbol '{s}' (expected in '{?s}')", .{ name, lib_name }); log.debug("getGlobalSymbol '{s}' (expected in '{?s}')", .{ name, lib_name });
switch (base.tag) { switch (base.tag) {
.plan9 => unreachable, .plan9 => unreachable,
.spirv => unreachable, .spirv => unreachable,
.c => unreachable, .c => unreachable,
.nvptx => unreachable, .nvptx => unreachable,
inline else => |t| { inline else => |tag| {
return @as(*t.Type(), @fieldParentPtr("base", base)).getGlobalSymbol(name, lib_name); dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).getGlobalSymbol(name, lib_name);
}, },
} }
} }
@ -402,7 +405,7 @@ pub const File = struct {
assert(decl.has_tv); assert(decl.has_tv);
switch (base.tag) { switch (base.tag) {
inline else => |tag| { inline else => |tag| {
if (tag != .c and build_options.only_c) unreachable; dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).updateDecl(pt, decl_index); return @as(*tag.Type(), @fieldParentPtr("base", base)).updateDecl(pt, decl_index);
}, },
} }
@ -418,7 +421,7 @@ pub const File = struct {
) UpdateDeclError!void { ) UpdateDeclError!void {
switch (base.tag) { switch (base.tag) {
inline else => |tag| { inline else => |tag| {
if (tag != .c and build_options.only_c) unreachable; dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).updateFunc(pt, func_index, air, liveness); return @as(*tag.Type(), @fieldParentPtr("base", base)).updateFunc(pt, func_index, air, liveness);
}, },
} }
@ -430,7 +433,7 @@ pub const File = struct {
switch (base.tag) { switch (base.tag) {
.spirv, .nvptx => {}, .spirv, .nvptx => {},
inline else => |tag| { inline else => |tag| {
if (tag != .c and build_options.only_c) unreachable; dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).updateDeclLineNumber(pt, decl_index); return @as(*tag.Type(), @fieldParentPtr("base", base)).updateDeclLineNumber(pt, decl_index);
}, },
} }
@ -454,7 +457,7 @@ pub const File = struct {
if (base.file) |f| f.close(); if (base.file) |f| f.close();
switch (base.tag) { switch (base.tag) {
inline else => |tag| { inline else => |tag| {
if (tag != .c and build_options.only_c) unreachable; dev.check(tag.devFeature());
@as(*tag.Type(), @fieldParentPtr("base", base)).deinit(); @as(*tag.Type(), @fieldParentPtr("base", base)).deinit();
}, },
} }
@ -536,12 +539,9 @@ pub const File = struct {
/// and `use_lld`, not only `effectiveOutputMode`. /// and `use_lld`, not only `effectiveOutputMode`.
/// `arena` has the lifetime of the call to `Compilation.update`. /// `arena` has the lifetime of the call to `Compilation.update`.
pub fn flush(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) FlushError!void { pub fn flush(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) FlushError!void {
if (build_options.only_c) {
assert(base.tag == .c);
return @as(*C, @fieldParentPtr("base", base)).flush(arena, tid, prog_node);
}
const comp = base.comp; const comp = base.comp;
if (comp.clang_preprocessor_mode == .yes or comp.clang_preprocessor_mode == .pch) { if (comp.clang_preprocessor_mode == .yes or comp.clang_preprocessor_mode == .pch) {
dev.check(.clang_command);
const gpa = comp.gpa; const gpa = comp.gpa;
const emit = base.emit; const emit = base.emit;
// TODO: avoid extra link step when it's just 1 object file (the `zig cc -c` case) // TODO: avoid extra link step when it's just 1 object file (the `zig cc -c` case)
@ -565,6 +565,7 @@ pub const File = struct {
} }
switch (base.tag) { switch (base.tag) {
inline else => |tag| { inline else => |tag| {
dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).flush(arena, tid, prog_node); return @as(*tag.Type(), @fieldParentPtr("base", base)).flush(arena, tid, prog_node);
}, },
} }
@ -575,7 +576,7 @@ pub const File = struct {
pub fn flushModule(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) FlushError!void { pub fn flushModule(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) FlushError!void {
switch (base.tag) { switch (base.tag) {
inline else => |tag| { inline else => |tag| {
if (tag != .c and build_options.only_c) unreachable; dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).flushModule(arena, tid, prog_node); return @as(*tag.Type(), @fieldParentPtr("base", base)).flushModule(arena, tid, prog_node);
}, },
} }
@ -585,7 +586,7 @@ pub const File = struct {
pub fn freeDecl(base: *File, decl_index: InternPool.DeclIndex) void { pub fn freeDecl(base: *File, decl_index: InternPool.DeclIndex) void {
switch (base.tag) { switch (base.tag) {
inline else => |tag| { inline else => |tag| {
if (tag != .c and build_options.only_c) unreachable; dev.check(tag.devFeature());
@as(*tag.Type(), @fieldParentPtr("base", base)).freeDecl(decl_index); @as(*tag.Type(), @fieldParentPtr("base", base)).freeDecl(decl_index);
}, },
} }
@ -608,7 +609,7 @@ pub const File = struct {
) UpdateExportsError!void { ) UpdateExportsError!void {
switch (base.tag) { switch (base.tag) {
inline else => |tag| { inline else => |tag| {
if (tag != .c and build_options.only_c) unreachable; dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).updateExports(pt, exported, export_indices); return @as(*tag.Type(), @fieldParentPtr("base", base)).updateExports(pt, exported, export_indices);
}, },
} }
@ -627,12 +628,12 @@ pub const File = struct {
/// May be called before or after updateFunc/updateDecl therefore it is up to the linker to allocate /// May be called before or after updateFunc/updateDecl therefore it is up to the linker to allocate
/// the block/atom. /// the block/atom.
pub fn getDeclVAddr(base: *File, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex, reloc_info: RelocInfo) !u64 { pub fn getDeclVAddr(base: *File, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex, reloc_info: RelocInfo) !u64 {
if (build_options.only_c) @compileError("unreachable");
switch (base.tag) { switch (base.tag) {
.c => unreachable, .c => unreachable,
.spirv => unreachable, .spirv => unreachable,
.nvptx => unreachable, .nvptx => unreachable,
inline else => |tag| { inline else => |tag| {
dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).getDeclVAddr(pt, decl_index, reloc_info); return @as(*tag.Type(), @fieldParentPtr("base", base)).getDeclVAddr(pt, decl_index, reloc_info);
}, },
} }
@ -647,24 +648,24 @@ pub const File = struct {
decl_align: InternPool.Alignment, decl_align: InternPool.Alignment,
src_loc: Zcu.LazySrcLoc, src_loc: Zcu.LazySrcLoc,
) !LowerResult { ) !LowerResult {
if (build_options.only_c) @compileError("unreachable");
switch (base.tag) { switch (base.tag) {
.c => unreachable, .c => unreachable,
.spirv => unreachable, .spirv => unreachable,
.nvptx => unreachable, .nvptx => unreachable,
inline else => |tag| { inline else => |tag| {
dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).lowerAnonDecl(pt, decl_val, decl_align, src_loc); return @as(*tag.Type(), @fieldParentPtr("base", base)).lowerAnonDecl(pt, decl_val, decl_align, src_loc);
}, },
} }
} }
pub fn getAnonDeclVAddr(base: *File, decl_val: InternPool.Index, reloc_info: RelocInfo) !u64 { pub fn getAnonDeclVAddr(base: *File, decl_val: InternPool.Index, reloc_info: RelocInfo) !u64 {
if (build_options.only_c) @compileError("unreachable");
switch (base.tag) { switch (base.tag) {
.c => unreachable, .c => unreachable,
.spirv => unreachable, .spirv => unreachable,
.nvptx => unreachable, .nvptx => unreachable,
inline else => |tag| { inline else => |tag| {
dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).getAnonDeclVAddr(decl_val, reloc_info); return @as(*tag.Type(), @fieldParentPtr("base", base)).getAnonDeclVAddr(decl_val, reloc_info);
}, },
} }
@ -675,7 +676,6 @@ pub const File = struct {
exported: Zcu.Exported, exported: Zcu.Exported,
name: InternPool.NullTerminatedString, name: InternPool.NullTerminatedString,
) void { ) void {
if (build_options.only_c) @compileError("unreachable");
switch (base.tag) { switch (base.tag) {
.plan9, .plan9,
.spirv, .spirv,
@ -683,12 +683,15 @@ pub const File = struct {
=> {}, => {},
inline else => |tag| { inline else => |tag| {
dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).deleteExport(exported, name); return @as(*tag.Type(), @fieldParentPtr("base", base)).deleteExport(exported, name);
}, },
} }
} }
pub fn linkAsArchive(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) FlushError!void { pub fn linkAsArchive(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) FlushError!void {
dev.check(.lld_linker);
const tracy = trace(@src()); const tracy = trace(@src());
defer tracy.end(); defer tracy.end();
@ -743,11 +746,9 @@ pub const File = struct {
for (comp.c_object_table.keys()) |key| { for (comp.c_object_table.keys()) |key| {
_ = try man.addFile(key.status.success.object_path, null); _ = try man.addFile(key.status.success.object_path, null);
} }
if (!build_options.only_core_functionality) {
for (comp.win32_resource_table.keys()) |key| { for (comp.win32_resource_table.keys()) |key| {
_ = try man.addFile(key.status.success.res_path, null); _ = try man.addFile(key.status.success.res_path, null);
} }
}
try man.addOptionalFile(zcu_obj_path); try man.addOptionalFile(zcu_obj_path);
try man.addOptionalFile(compiler_rt_path); try man.addOptionalFile(compiler_rt_path);
@ -777,7 +778,7 @@ pub const File = struct {
}; };
} }
const win32_resource_table_len = if (build_options.only_core_functionality) 0 else comp.win32_resource_table.count(); const win32_resource_table_len = comp.win32_resource_table.count();
const num_object_files = objects.len + comp.c_object_table.count() + win32_resource_table_len + 2; const num_object_files = objects.len + comp.c_object_table.count() + win32_resource_table_len + 2;
var object_files = try std.ArrayList([*:0]const u8).initCapacity(gpa, num_object_files); var object_files = try std.ArrayList([*:0]const u8).initCapacity(gpa, num_object_files);
defer object_files.deinit(); defer object_files.deinit();
@ -788,11 +789,9 @@ pub const File = struct {
for (comp.c_object_table.keys()) |key| { for (comp.c_object_table.keys()) |key| {
object_files.appendAssumeCapacity(try arena.dupeZ(u8, key.status.success.object_path)); object_files.appendAssumeCapacity(try arena.dupeZ(u8, key.status.success.object_path));
} }
if (!build_options.only_core_functionality) {
for (comp.win32_resource_table.keys()) |key| { for (comp.win32_resource_table.keys()) |key| {
object_files.appendAssumeCapacity(try arena.dupeZ(u8, key.status.success.res_path)); object_files.appendAssumeCapacity(try arena.dupeZ(u8, key.status.success.res_path));
} }
}
if (zcu_obj_path) |p| { if (zcu_obj_path) |p| {
object_files.appendAssumeCapacity(try arena.dupeZ(u8, p)); object_files.appendAssumeCapacity(try arena.dupeZ(u8, p));
} }
@ -869,6 +868,10 @@ pub const File = struct {
.dxcontainer => @panic("TODO implement dxcontainer object format"), .dxcontainer => @panic("TODO implement dxcontainer object format"),
}; };
} }
pub fn devFeature(tag: Tag) dev.Feature {
return @field(dev.Feature, @tagName(tag) ++ "_linker");
}
}; };
pub const ErrorFlags = struct { pub const ErrorFlags = struct {

View File

@ -2,6 +2,7 @@ const std = @import("std");
const build_options = @import("build_options"); const build_options = @import("build_options");
const allocPrint = std.fmt.allocPrint; const allocPrint = std.fmt.allocPrint;
const assert = std.debug.assert; const assert = std.debug.assert;
const dev = @import("../../dev.zig");
const fs = std.fs; const fs = std.fs;
const log = std.log.scoped(.link); const log = std.log.scoped(.link);
const mem = std.mem; const mem = std.mem;
@ -18,6 +19,8 @@ const Compilation = @import("../../Compilation.zig");
const Zcu = @import("../../Zcu.zig"); const Zcu = @import("../../Zcu.zig");
pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void { pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void {
dev.check(.lld_linker);
const tracy = trace(@src()); const tracy = trace(@src());
defer tracy.end(); defer tracy.end();
@ -77,11 +80,9 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
for (comp.c_object_table.keys()) |key| { for (comp.c_object_table.keys()) |key| {
_ = try man.addFile(key.status.success.object_path, null); _ = try man.addFile(key.status.success.object_path, null);
} }
if (!build_options.only_core_functionality) {
for (comp.win32_resource_table.keys()) |key| { for (comp.win32_resource_table.keys()) |key| {
_ = try man.addFile(key.status.success.res_path, null); _ = try man.addFile(key.status.success.res_path, null);
} }
}
try man.addOptionalFile(module_obj_path); try man.addOptionalFile(module_obj_path);
man.hash.addOptionalBytes(entry_name); man.hash.addOptionalBytes(entry_name);
man.hash.add(self.base.stack_size); man.hash.add(self.base.stack_size);
@ -274,11 +275,9 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
try argv.append(key.status.success.object_path); try argv.append(key.status.success.object_path);
} }
if (!build_options.only_core_functionality) {
for (comp.win32_resource_table.keys()) |key| { for (comp.win32_resource_table.keys()) |key| {
try argv.append(key.status.success.res_path); try argv.append(key.status.success.res_path);
} }
}
if (module_obj_path) |p| { if (module_obj_path) |p| {
try argv.append(p); try argv.append(p);

View File

@ -2148,6 +2148,8 @@ fn scanRelocs(self: *Elf) !void {
} }
fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void { fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void {
dev.check(.lld_linker);
const tracy = trace(@src()); const tracy = trace(@src());
defer tracy.end(); defer tracy.end();
@ -6430,6 +6432,7 @@ const math = std.math;
const mem = std.mem; const mem = std.mem;
const codegen = @import("../codegen.zig"); const codegen = @import("../codegen.zig");
const dev = @import("../dev.zig");
const eh_frame = @import("Elf/eh_frame.zig"); const eh_frame = @import("Elf/eh_frame.zig");
const gc = @import("Elf/gc.zig"); const gc = @import("Elf/gc.zig");
const glibc = @import("../glibc.zig"); const glibc = @import("../glibc.zig");

View File

@ -6,6 +6,7 @@ const assert = std.debug.assert;
const build_options = @import("build_options"); const build_options = @import("build_options");
const builtin = @import("builtin"); const builtin = @import("builtin");
const codegen = @import("../codegen.zig"); const codegen = @import("../codegen.zig");
const dev = @import("../dev.zig");
const fs = std.fs; const fs = std.fs;
const leb = std.leb; const leb = std.leb;
const link = @import("../link.zig"); const link = @import("../link.zig");
@ -3325,6 +3326,8 @@ fn emitImport(wasm: *Wasm, writer: anytype, import: types.Import) !void {
} }
fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void { fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void {
dev.check(.lld_linker);
const tracy = trace(@src()); const tracy = trace(@src());
defer tracy.end(); defer tracy.end();

View File

@ -30,6 +30,7 @@ const Zcu = @import("Zcu.zig");
const AstGen = std.zig.AstGen; const AstGen = std.zig.AstGen;
const mingw = @import("mingw.zig"); const mingw = @import("mingw.zig");
const Server = std.zig.Server; const Server = std.zig.Server;
const dev = @import("dev.zig");
pub const std_options = .{ pub const std_options = .{
.wasiCwd = wasi_cwd, .wasiCwd = wasi_cwd,
@ -195,17 +196,6 @@ pub fn main() anyerror!void {
wasi_preopens = try fs.wasi.preopensAlloc(arena); wasi_preopens = try fs.wasi.preopensAlloc(arena);
} }
// Short circuit some of the other logic for bootstrapping.
if (build_options.only_c) {
if (mem.eql(u8, args[1], "build-exe")) {
return buildOutputType(gpa, arena, args, .{ .build = .Exe });
} else if (mem.eql(u8, args[1], "build-obj")) {
return buildOutputType(gpa, arena, args, .{ .build = .Obj });
} else {
@panic("only build-exe or build-obj is supported in a -Donly-c build");
}
}
return mainArgs(gpa, arena, args); return mainArgs(gpa, arena, args);
} }
@ -227,6 +217,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
} }
if (process.can_execv and std.posix.getenvZ("ZIG_IS_DETECTING_LIBC_PATHS") != null) { if (process.can_execv and std.posix.getenvZ("ZIG_IS_DETECTING_LIBC_PATHS") != null) {
dev.check(.cc_command);
// In this case we have accidentally invoked ourselves as "the system C compiler" // In this case we have accidentally invoked ourselves as "the system C compiler"
// to figure out where libc is installed. This is essentially infinite recursion // to figure out where libc is installed. This is essentially infinite recursion
// via child process execution due to the CC environment variable pointing to Zig. // via child process execution due to the CC environment variable pointing to Zig.
@ -260,39 +251,49 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
const cmd = args[1]; const cmd = args[1];
const cmd_args = args[2..]; const cmd_args = args[2..];
if (mem.eql(u8, cmd, "build-exe")) { if (mem.eql(u8, cmd, "build-exe")) {
dev.check(.build_exe_command);
return buildOutputType(gpa, arena, args, .{ .build = .Exe }); return buildOutputType(gpa, arena, args, .{ .build = .Exe });
} else if (mem.eql(u8, cmd, "build-lib")) { } else if (mem.eql(u8, cmd, "build-lib")) {
dev.check(.build_lib_command);
return buildOutputType(gpa, arena, args, .{ .build = .Lib }); return buildOutputType(gpa, arena, args, .{ .build = .Lib });
} else if (mem.eql(u8, cmd, "build-obj")) { } else if (mem.eql(u8, cmd, "build-obj")) {
dev.check(.build_obj_command);
return buildOutputType(gpa, arena, args, .{ .build = .Obj }); return buildOutputType(gpa, arena, args, .{ .build = .Obj });
} else if (mem.eql(u8, cmd, "test")) { } else if (mem.eql(u8, cmd, "test")) {
dev.check(.test_command);
return buildOutputType(gpa, arena, args, .zig_test); return buildOutputType(gpa, arena, args, .zig_test);
} else if (mem.eql(u8, cmd, "run")) { } else if (mem.eql(u8, cmd, "run")) {
dev.check(.run_command);
return buildOutputType(gpa, arena, args, .run); return buildOutputType(gpa, arena, args, .run);
} else if (mem.eql(u8, cmd, "dlltool") or } else if (mem.eql(u8, cmd, "dlltool") or
mem.eql(u8, cmd, "ranlib") or mem.eql(u8, cmd, "ranlib") or
mem.eql(u8, cmd, "lib") or mem.eql(u8, cmd, "lib") or
mem.eql(u8, cmd, "ar")) mem.eql(u8, cmd, "ar"))
{ {
dev.check(.ar_command);
return process.exit(try llvmArMain(arena, args)); return process.exit(try llvmArMain(arena, args));
} else if (mem.eql(u8, cmd, "build")) { } else if (mem.eql(u8, cmd, "build")) {
dev.check(.build_command);
return cmdBuild(gpa, arena, cmd_args); return cmdBuild(gpa, arena, cmd_args);
} else if (mem.eql(u8, cmd, "clang") or } else if (mem.eql(u8, cmd, "clang") or
mem.eql(u8, cmd, "-cc1") or mem.eql(u8, cmd, "-cc1as")) mem.eql(u8, cmd, "-cc1") or mem.eql(u8, cmd, "-cc1as"))
{ {
dev.check(.clang_command);
return process.exit(try clangMain(arena, args)); return process.exit(try clangMain(arena, args));
} else if (mem.eql(u8, cmd, "ld.lld") or } else if (mem.eql(u8, cmd, "ld.lld") or
mem.eql(u8, cmd, "lld-link") or mem.eql(u8, cmd, "lld-link") or
mem.eql(u8, cmd, "wasm-ld")) mem.eql(u8, cmd, "wasm-ld"))
{ {
dev.check(.lld_linker);
return process.exit(try lldMain(arena, args, true)); return process.exit(try lldMain(arena, args, true));
} else if (build_options.only_core_functionality) {
@panic("only a few subcommands are supported in a zig2.c build");
} else if (mem.eql(u8, cmd, "cc")) { } else if (mem.eql(u8, cmd, "cc")) {
dev.check(.cc_command);
return buildOutputType(gpa, arena, args, .cc); return buildOutputType(gpa, arena, args, .cc);
} else if (mem.eql(u8, cmd, "c++")) { } else if (mem.eql(u8, cmd, "c++")) {
dev.check(.cc_command);
return buildOutputType(gpa, arena, args, .cpp); return buildOutputType(gpa, arena, args, .cpp);
} else if (mem.eql(u8, cmd, "translate-c")) { } else if (mem.eql(u8, cmd, "translate-c")) {
dev.check(.translate_c_command);
return buildOutputType(gpa, arena, args, .translate_c); return buildOutputType(gpa, arena, args, .translate_c);
} else if (mem.eql(u8, cmd, "rc")) { } else if (mem.eql(u8, cmd, "rc")) {
const use_server = cmd_args.len > 0 and std.mem.eql(u8, cmd_args[0], "--zig-integration"); const use_server = cmd_args.len > 0 and std.mem.eql(u8, cmd_args[0], "--zig-integration");
@ -332,16 +333,19 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
} else if (mem.eql(u8, cmd, "init")) { } else if (mem.eql(u8, cmd, "init")) {
return cmdInit(gpa, arena, cmd_args); return cmdInit(gpa, arena, cmd_args);
} else if (mem.eql(u8, cmd, "targets")) { } else if (mem.eql(u8, cmd, "targets")) {
dev.check(.targets_command);
const host = std.zig.resolveTargetQueryOrFatal(.{}); const host = std.zig.resolveTargetQueryOrFatal(.{});
const stdout = io.getStdOut().writer(); const stdout = io.getStdOut().writer();
return @import("print_targets.zig").cmdTargets(arena, cmd_args, stdout, host); return @import("print_targets.zig").cmdTargets(arena, cmd_args, stdout, host);
} else if (mem.eql(u8, cmd, "version")) { } else if (mem.eql(u8, cmd, "version")) {
dev.check(.version_command);
try std.io.getStdOut().writeAll(build_options.version ++ "\n"); try std.io.getStdOut().writeAll(build_options.version ++ "\n");
// Check libc++ linkage to make sure Zig was built correctly, but only // Check libc++ linkage to make sure Zig was built correctly, but only
// for "env" and "version" to avoid affecting the startup time for // for "env" and "version" to avoid affecting the startup time for
// build-critical commands (check takes about ~10 μs) // build-critical commands (check takes about ~10 μs)
return verifyLibcxxCorrectlyLinked(); return verifyLibcxxCorrectlyLinked();
} else if (mem.eql(u8, cmd, "env")) { } else if (mem.eql(u8, cmd, "env")) {
dev.check(.env_command);
verifyLibcxxCorrectlyLinked(); verifyLibcxxCorrectlyLinked();
return @import("print_env.zig").cmdEnv(arena, cmd_args, io.getStdOut().writer()); return @import("print_env.zig").cmdEnv(arena, cmd_args, io.getStdOut().writer());
} else if (mem.eql(u8, cmd, "reduce")) { } else if (mem.eql(u8, cmd, "reduce")) {
@ -350,8 +354,10 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
.root_src_path = "reduce.zig", .root_src_path = "reduce.zig",
}); });
} else if (mem.eql(u8, cmd, "zen")) { } else if (mem.eql(u8, cmd, "zen")) {
dev.check(.zen_command);
return io.getStdOut().writeAll(info_zen); return io.getStdOut().writeAll(info_zen);
} else if (mem.eql(u8, cmd, "help") or mem.eql(u8, cmd, "-h") or mem.eql(u8, cmd, "--help")) { } else if (mem.eql(u8, cmd, "help") or mem.eql(u8, cmd, "-h") or mem.eql(u8, cmd, "--help")) {
dev.check(.help_command);
return io.getStdOut().writeAll(usage); return io.getStdOut().writeAll(usage);
} else if (mem.eql(u8, cmd, "ast-check")) { } else if (mem.eql(u8, cmd, "ast-check")) {
return cmdAstCheck(gpa, arena, cmd_args); return cmdAstCheck(gpa, arena, cmd_args);
@ -726,14 +732,10 @@ const ArgMode = union(enum) {
run, run,
}; };
/// Avoid dragging networking into zig2.c because it adds dependencies on some
/// linker symbols that are annoying to satisfy while bootstrapping.
const Ip4Address = if (build_options.only_core_functionality) void else std.net.Ip4Address;
const Listen = union(enum) { const Listen = union(enum) {
none, none,
ip4: Ip4Address, stdio: if (dev.env.supports(.stdio_listen)) void else noreturn,
stdio, ip4: if (dev.env.supports(.network_listen)) std.net.Ip4Address else noreturn,
}; };
const ArgsIterator = struct { const ArgsIterator = struct {
@ -1338,9 +1340,10 @@ fn buildOutputType(
} else if (mem.eql(u8, arg, "--listen")) { } else if (mem.eql(u8, arg, "--listen")) {
const next_arg = args_iter.nextOrFatal(); const next_arg = args_iter.nextOrFatal();
if (mem.eql(u8, next_arg, "-")) { if (mem.eql(u8, next_arg, "-")) {
dev.check(.stdio_listen);
listen = .stdio; listen = .stdio;
} else { } else {
if (build_options.only_core_functionality) unreachable; dev.check(.network_listen);
// example: --listen 127.0.0.1:9000 // example: --listen 127.0.0.1:9000
var it = std.mem.splitScalar(u8, next_arg, ':'); var it = std.mem.splitScalar(u8, next_arg, ':');
const host = it.next().?; const host = it.next().?;
@ -1351,6 +1354,7 @@ fn buildOutputType(
fatal("invalid host: '{s}': {s}", .{ host, @errorName(err) }) }; fatal("invalid host: '{s}': {s}", .{ host, @errorName(err) }) };
} }
} else if (mem.eql(u8, arg, "--listen=-")) { } else if (mem.eql(u8, arg, "--listen=-")) {
dev.check(.stdio_listen);
listen = .stdio; listen = .stdio;
} else if (mem.eql(u8, arg, "--debug-link-snapshot")) { } else if (mem.eql(u8, arg, "--debug-link-snapshot")) {
if (!build_options.enable_link_snapshots) { if (!build_options.enable_link_snapshots) {
@ -1359,6 +1363,7 @@ fn buildOutputType(
enable_link_snapshots = true; enable_link_snapshots = true;
} }
} else if (mem.eql(u8, arg, "-fincremental")) { } else if (mem.eql(u8, arg, "-fincremental")) {
dev.check(.incremental);
opt_incremental = true; opt_incremental = true;
} else if (mem.eql(u8, arg, "-fno-incremental")) { } else if (mem.eql(u8, arg, "-fno-incremental")) {
opt_incremental = false; opt_incremental = false;
@ -1762,7 +1767,7 @@ fn buildOutputType(
} }
}, },
.cc, .cpp => { .cc, .cpp => {
if (build_options.only_c) unreachable; dev.check(.cc_command);
emit_h = .no; emit_h = .no;
soname = .no; soname = .no;
@ -3395,7 +3400,6 @@ fn buildOutputType(
switch (listen) { switch (listen) {
.none => {}, .none => {},
.stdio => { .stdio => {
if (build_options.only_c) unreachable;
try serve( try serve(
comp, comp,
std.io.getStdIn(), std.io.getStdIn(),
@ -3409,8 +3413,6 @@ fn buildOutputType(
return cleanExit(); return cleanExit();
}, },
.ip4 => |ip4_addr| { .ip4 => |ip4_addr| {
if (build_options.only_core_functionality) unreachable;
const addr: std.net.Address = .{ .in = ip4_addr }; const addr: std.net.Address = .{ .in = ip4_addr };
var server = try addr.listen(.{ var server = try addr.listen(.{
@ -3454,10 +3456,16 @@ fn buildOutputType(
else => |e| return e, else => |e| return e,
}; };
} }
if (build_options.only_c) return cleanExit();
try comp.makeBinFileExecutable(); try comp.makeBinFileExecutable();
saveState(comp, incremental); saveState(comp, incremental);
if (switch (arg_mode) {
.run => true,
.zig_test => !test_no_exec,
else => false,
}) {
dev.checkAny(&.{ .run_command, .test_command });
if (test_exec_args.items.len == 0 and target.ofmt == .c) default_exec_args: { if (test_exec_args.items.len == 0 and target.ofmt == .c) default_exec_args: {
// Default to using `zig run` to execute the produced .c code from `zig test`. // Default to using `zig run` to execute the produced .c code from `zig test`.
const c_code_loc = emit_bin_loc orelse break :default_exec_args; const c_code_loc = emit_bin_loc orelse break :default_exec_args;
@ -3492,12 +3500,6 @@ fn buildOutputType(
try test_exec_args.append(arena, c_code_path); try test_exec_args.append(arena, c_code_path);
} }
const run_or_test = switch (arg_mode) {
.run => true,
.zig_test => !test_no_exec,
else => false,
};
if (run_or_test) {
try runOrTest( try runOrTest(
comp, comp,
gpa, gpa,
@ -4459,7 +4461,8 @@ fn cmdTranslateC(
file_system_inputs: ?*std.ArrayListUnmanaged(u8), file_system_inputs: ?*std.ArrayListUnmanaged(u8),
prog_node: std.Progress.Node, prog_node: std.Progress.Node,
) !void { ) !void {
if (build_options.only_core_functionality) @panic("@translate-c is not available in a zig2.c build"); dev.check(.translate_c_command);
const color: Color = .auto; const color: Color = .auto;
assert(comp.c_source_files.len == 1); assert(comp.c_source_files.len == 1);
const c_source_file = comp.c_source_files[0]; const c_source_file = comp.c_source_files[0];
@ -4627,6 +4630,8 @@ const usage_init =
; ;
fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
dev.check(.init_command);
{ {
var i: usize = 0; var i: usize = 0;
while (i < args.len) : (i += 1) { while (i < args.len) : (i += 1) {
@ -4678,6 +4683,8 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
} }
fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
dev.check(.build_command);
var build_file: ?[]const u8 = null; var build_file: ?[]const u8 = null;
var override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena); var override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena);
var override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena); var override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
@ -4969,16 +4976,12 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
}); });
defer thread_pool.deinit(); defer thread_pool.deinit();
// Dummy http client that is not actually used when only_core_functionality is enabled. // Dummy http client that is not actually used when fetch_command is unsupported.
// Prevents bootstrap from depending on a bunch of unnecessary stuff. // Prevents bootstrap from depending on a bunch of unnecessary stuff.
const HttpClient = if (build_options.only_core_functionality) struct { var http_client: if (dev.env.supports(.fetch_command)) std.http.Client else struct {
allocator: Allocator, allocator: Allocator,
fn deinit(self: *@This()) void { fn deinit(_: @This()) void {}
_ = self; } = .{ .allocator = gpa };
}
} else std.http.Client;
var http_client: HttpClient = .{ .allocator = gpa };
defer http_client.deinit(); defer http_client.deinit();
var unlazy_set: Package.Fetch.JobQueue.UnlazySet = .{}; var unlazy_set: Package.Fetch.JobQueue.UnlazySet = .{};
@ -5045,16 +5048,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
var cleanup_build_dir: ?fs.Dir = null; var cleanup_build_dir: ?fs.Dir = null;
defer if (cleanup_build_dir) |*dir| dir.close(); defer if (cleanup_build_dir) |*dir| dir.close();
if (build_options.only_core_functionality) { if (dev.env.supports(.fetch_command)) {
try createEmptyDependenciesModule(
arena,
root_mod,
global_cache_directory,
local_cache_directory,
builtin_mod,
config,
);
} else {
const fetch_prog_node = root_prog_node.start("Fetch Packages", 0); const fetch_prog_node = root_prog_node.start("Fetch Packages", 0);
defer fetch_prog_node.end(); defer fetch_prog_node.end();
@ -5203,7 +5197,14 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
} }
} }
} }
} } else try createEmptyDependenciesModule(
arena,
root_mod,
global_cache_directory,
local_cache_directory,
builtin_mod,
config,
);
try root_mod.deps.put(arena, "@build", build_mod); try root_mod.deps.put(arena, "@build", build_mod);
@ -5269,7 +5270,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
if (code == 2) process.exit(2); if (code == 2) process.exit(2);
if (code == 3) { if (code == 3) {
if (build_options.only_core_functionality) process.exit(3); if (!dev.env.supports(.fetch_command)) process.exit(3);
// Indicates the configure phase failed due to missing lazy // Indicates the configure phase failed due to missing lazy
// dependencies and stdout contains the hashes of the ones // dependencies and stdout contains the hashes of the ones
// that are missing. // that are missing.
@ -5346,6 +5347,8 @@ fn jitCmd(
args: []const []const u8, args: []const []const u8,
options: JitCmdOptions, options: JitCmdOptions,
) !void { ) !void {
dev.check(.jit_command);
const color: Color = .auto; const color: Color = .auto;
const root_prog_node = if (options.progress_node) |node| node else std.Progress.start(.{ const root_prog_node = if (options.progress_node) |node| node else std.Progress.start(.{
.disable_printing = (color == .off), .disable_printing = (color == .off),
@ -5995,6 +5998,8 @@ fn cmdAstCheck(
arena: Allocator, arena: Allocator,
args: []const []const u8, args: []const []const u8,
) !void { ) !void {
dev.check(.ast_check_command);
const Zir = std.zig.Zir; const Zir = std.zig.Zir;
var color: Color = .auto; var color: Color = .auto;
@ -6154,6 +6159,8 @@ fn cmdDetectCpu(
arena: Allocator, arena: Allocator,
args: []const []const u8, args: []const []const u8,
) !void { ) !void {
dev.check(.detect_cpu_command);
_ = gpa; _ = gpa;
_ = arena; _ = arena;
@ -6293,6 +6300,8 @@ fn cmdDumpLlvmInts(
arena: Allocator, arena: Allocator,
args: []const []const u8, args: []const []const u8,
) !void { ) !void {
dev.check(.llvm_ints_command);
_ = gpa; _ = gpa;
if (!build_options.have_llvm) if (!build_options.have_llvm)
@ -6336,6 +6345,8 @@ fn cmdDumpZir(
arena: Allocator, arena: Allocator,
args: []const []const u8, args: []const []const u8,
) !void { ) !void {
dev.check(.dump_zir_command);
_ = arena; _ = arena;
const Zir = std.zig.Zir; const Zir = std.zig.Zir;
@ -6395,6 +6406,8 @@ fn cmdChangelist(
arena: Allocator, arena: Allocator,
args: []const []const u8, args: []const []const u8,
) !void { ) !void {
dev.check(.changelist_command);
const color: Color = .auto; const color: Color = .auto;
const Zir = std.zig.Zir; const Zir = std.zig.Zir;
@ -6895,6 +6908,8 @@ fn cmdFetch(
arena: Allocator, arena: Allocator,
args: []const []const u8, args: []const []const u8,
) !void { ) !void {
dev.check(.fetch_command);
const color: Color = .auto; const color: Color = .auto;
const work_around_btrfs_bug = native_os == .linux and const work_around_btrfs_bug = native_os == .linux and
EnvVar.ZIG_BTRFS_WORKAROUND.isSet(); EnvVar.ZIG_BTRFS_WORKAROUND.isSet();

View File

@ -9,6 +9,7 @@ const builtin = @import("builtin");
const Compilation = @import("Compilation.zig"); const Compilation = @import("Compilation.zig");
const build_options = @import("build_options"); const build_options = @import("build_options");
const Cache = std.Build.Cache; const Cache = std.Build.Cache;
const dev = @import("dev.zig");
pub const CRTFile = enum { pub const CRTFile = enum {
crt2_o, crt2_o,
@ -157,7 +158,8 @@ fn add_cc_args(
} }
pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
if (build_options.only_c) @compileError("building import libs not included in core functionality"); dev.check(.build_import_lib);
var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
defer arena_allocator.deinit(); defer arena_allocator.deinit();
const arena = arena_allocator.allocator(); const arena = arena_allocator.allocator();

View File

@ -12,5 +12,4 @@ pub const enable_tracy = false;
pub const value_tracing = false; pub const value_tracing = false;
pub const skip_non_native = false; pub const skip_non_native = false;
pub const force_gpa = false; pub const force_gpa = false;
pub const only_c = false; pub const dev = .core;
pub const only_core_functionality = true;