stage2 now supports using stage1 as a backend for compiling zig code

* move stage2.cpp code into zig0.cpp for simplicity
 * add -ftime-report and some more CLI options to stage2
 * stage2 compites the llvm cpu features string
 * classifyFileExt understands more file extensions
 * correction to generateBuiltinZigSource using the wrong allocator
   (thanks dbandstra!)
 * stage2 is now able to build hello.zig into hello.o using stage1 as a
   library however it fails linking due to missing compiler-rt
 * remove dead code
 * simplify zig0 builtin.zig source
 * fix not resolving builtin.zig source path causing duplicate imports
 * fix stage1.h not being valid C code
 * fix stage2.h not being valid C code
master
Andrew Kelley 2020-09-18 22:48:28 -07:00
parent 333b12a8f9
commit 2ef68631cb
17 changed files with 750 additions and 678 deletions

View File

@ -1,3 +1,6 @@
* build & link against compiler-rt
* build & link against freestanding libc
* Cache integration for stage1 zig code compilation
* `zig test`
* `zig build`
* `-ftime-report`
@ -14,10 +17,7 @@
- using it as a preprocessor (-E)
- try building some software
* support rpaths in ELF linker code
* build & link against compiler-rt
- stage1 C++ code integration
* repair @cImport
* build & link against freestanding libc
* add CLI support for a way to pass extra flags to c source files
* capture lld stdout/stderr better
* musl
@ -35,10 +35,12 @@
* implement emit-h in stage2
* implement -fno-emit-bin
* audit the base cache hash
* --main-pkg-path
* audit the CLI options for stage2
* `zig init-lib`
* `zig init-exe`
* `zig run`
* restore error messages for stage2_add_link_lib
* implement serialization/deserialization of incremental compilation metadata
* incremental compilation - implement detection of which source files changed

View File

@ -258,7 +258,6 @@ find_package(Threads)
# This is our shim which will be replaced by stage1.zig.
set(ZIG0_SOURCES
"${CMAKE_SOURCE_DIR}/src/zig0.cpp"
"${CMAKE_SOURCE_DIR}/src/stage2.cpp"
)
set(ZIG_SOURCES

View File

@ -19,6 +19,7 @@ const libunwind = @import("libunwind.zig");
const fatal = @import("main.zig").fatal;
const Module = @import("Module.zig");
const Cache = @import("Cache.zig");
const stage1 = @import("stage1.zig");
/// General-purpose allocator. Used for both temporary and long-term storage.
gpa: *Allocator,
@ -26,6 +27,7 @@ gpa: *Allocator,
arena_state: std.heap.ArenaAllocator.State,
bin_file: *link.File,
c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{},
stage1_module: ?*stage1.Module,
link_error_flags: link.File.ErrorFlags = .{},
@ -122,6 +124,8 @@ const Job = union(enum) {
/// Generate builtin.zig source code and write it into the correct place.
generate_builtin_zig: void,
/// Use stage1 C++ code to compile zig code into an object file.
stage1_module: void,
};
pub const CObject = struct {
@ -274,6 +278,7 @@ pub const InitOptions = struct {
strip: bool = false,
single_threaded: bool = false,
is_native_os: bool,
time_report: bool = false,
link_eh_frame_hdr: bool = false,
linker_script: ?[]const u8 = null,
version_script: ?[]const u8 = null,
@ -288,12 +293,20 @@ pub const InitOptions = struct {
clang_passthrough_mode: bool = false,
verbose_cc: bool = false,
verbose_link: bool = false,
verbose_tokenize: bool = false,
verbose_ast: bool = false,
verbose_ir: bool = false,
verbose_llvm_ir: bool = false,
verbose_cimport: bool = false,
verbose_llvm_cpu_features: bool = false,
is_test: bool = false,
stack_size_override: ?u64 = null,
self_exe_path: ?[]const u8 = null,
version: ?std.builtin.Version = null,
libc_installation: ?*const LibCInstallation = null,
machine_code_model: std.builtin.CodeModel = .default,
/// This is for stage1 and should be deleted upon completion of self-hosting.
color: @import("main.zig").Color = .Auto,
};
pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
@ -332,11 +345,27 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
{
break :blk true;
}
if (build_options.is_stage1) {
// If stage1 generates an object file, self-hosted linker is not
// yet sophisticated enough to handle that.
break :blk options.root_pkg != null;
}
break :blk false;
};
// Make a decision on whether to use LLVM or our own backend.
const use_llvm = if (options.use_llvm) |explicit| explicit else blk: {
// If we have no zig code to compile, no need for LLVM.
if (options.root_pkg == null)
break :blk false;
// If we are the stage1 compiler, we depend on the stage1 c++ llvm backend
// to compile zig code.
if (build_options.is_stage1)
break :blk true;
// We would want to prefer LLVM for release builds when it is available, however
// we don't have an LLVM backend yet :)
// We would also want to prefer LLVM for architectures that we don't have self-hosted support for too.
@ -580,6 +609,118 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.ReleaseFast, .ReleaseSmall => false,
};
const llvm_cpu_features: ?[*:0]const u8 = if (build_options.have_llvm and use_llvm) blk: {
var buf = std.ArrayList(u8).init(arena);
for (options.target.cpu.arch.allFeaturesList()) |feature, index_usize| {
const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
const is_enabled = options.target.cpu.features.isEnabled(index);
if (feature.llvm_name) |llvm_name| {
const plus_or_minus = "-+"[@boolToInt(is_enabled)];
try buf.ensureCapacity(buf.items.len + 2 + llvm_name.len);
buf.appendAssumeCapacity(plus_or_minus);
buf.appendSliceAssumeCapacity(llvm_name);
buf.appendSliceAssumeCapacity(",");
}
}
assert(mem.endsWith(u8, buf.items, ","));
buf.items[buf.items.len - 1] = 0;
buf.shrink(buf.items.len);
break :blk buf.items[0 .. buf.items.len - 1 :0].ptr;
} else null;
const stage1_module: ?*stage1.Module = if (build_options.is_stage1 and use_llvm) blk: {
// Here we use the legacy stage1 C++ compiler to compile Zig code.
const stage2_target = try arena.create(stage1.Stage2Target);
stage2_target.* = .{
.arch = @enumToInt(options.target.cpu.arch) + 1, // skip over ZigLLVM_UnknownArch
.os = @enumToInt(options.target.os.tag),
.abi = @enumToInt(options.target.abi),
.is_native_os = options.is_native_os,
.is_native_cpu = false, // Only true when bootstrapping the compiler.
.llvm_cpu_name = if (options.target.cpu.model.llvm_name) |s| s.ptr else null,
.llvm_cpu_features = llvm_cpu_features.?,
};
const progress = try arena.create(std.Progress);
const main_progress_node = try progress.start("", 100);
if (options.color == .Off) progress.terminal = null;
const mod = module.?;
const main_zig_file = mod.root_pkg.root_src_path;
const zig_lib_dir = options.zig_lib_directory.path.?;
const builtin_sub = &[_][]const u8{"builtin.zig"};
const builtin_zig_path = try mod.zig_cache_artifact_directory.join(arena, builtin_sub);
const stage1_module = stage1.create(
@enumToInt(options.optimize_mode),
undefined,
0, // TODO --main-pkg-path
main_zig_file.ptr,
main_zig_file.len,
zig_lib_dir.ptr,
zig_lib_dir.len,
stage2_target,
options.is_test,
) orelse return error.OutOfMemory;
const output_dir = bin_directory.path orelse ".";
const stage1_pkg = try arena.create(stage1.Pkg);
stage1_pkg.* = .{
.name_ptr = undefined,
.name_len = 0,
.path_ptr = undefined,
.path_len = 0,
.children_ptr = undefined,
.children_len = 0,
.parent = null,
};
stage1_module.* = .{
.root_name_ptr = root_name.ptr,
.root_name_len = root_name.len,
.output_dir_ptr = output_dir.ptr,
.output_dir_len = output_dir.len,
.builtin_zig_path_ptr = builtin_zig_path.ptr,
.builtin_zig_path_len = builtin_zig_path.len,
.test_filter_ptr = "",
.test_filter_len = 0,
.test_name_prefix_ptr = "",
.test_name_prefix_len = 0,
.userdata = @ptrToInt(comp),
.root_pkg = stage1_pkg,
.code_model = @enumToInt(options.machine_code_model),
.subsystem = stage1.TargetSubsystem.Auto,
.err_color = @enumToInt(options.color),
.pic = pic,
.link_libc = options.link_libc,
.link_libcpp = options.link_libcpp,
.strip = options.strip,
.is_single_threaded = single_threaded,
.dll_export_fns = dll_export_fns,
.link_mode_dynamic = link_mode == .Dynamic,
.valgrind_enabled = valgrind,
.function_sections = options.function_sections orelse false,
.enable_stack_probing = stack_check,
.enable_time_report = options.time_report,
.enable_stack_report = false,
.dump_analysis = false,
.enable_doc_generation = false,
.emit_bin = true,
.emit_asm = false,
.emit_llvm_ir = false,
.test_is_evented = false,
.verbose_tokenize = options.verbose_tokenize,
.verbose_ast = options.verbose_ast,
.verbose_ir = options.verbose_ir,
.verbose_llvm_ir = options.verbose_llvm_ir,
.verbose_cimport = options.verbose_cimport,
.verbose_llvm_cpu_features = options.verbose_llvm_cpu_features,
.main_progress_node = main_progress_node,
};
break :blk stage1_module;
} else null;
const bin_file = try link.File.openPath(gpa, .{
.directory = bin_directory,
.sub_path = emit_bin.basename,
@ -626,6 +767,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.machine_code_model = options.machine_code_model,
.dll_export_fns = dll_export_fns,
.error_return_tracing = error_return_tracing,
.llvm_cpu_features = llvm_cpu_features,
});
errdefer bin_file.destroy();
@ -635,6 +777,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.zig_lib_directory = options.zig_lib_directory,
.zig_cache_directory = options.zig_cache_directory,
.bin_file = bin_file,
.stage1_module = stage1_module,
.work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),
.keep_source_files_loaded = options.keep_source_files_loaded,
.use_clang = use_clang,
@ -681,6 +824,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
try comp.work_queue.writeItem(.{ .libunwind = {} });
}
if (comp.stage1_module) |module| {
try comp.work_queue.writeItem(.{ .stage1_module = {} });
}
return comp;
}
@ -689,6 +836,11 @@ pub fn destroy(self: *Compilation) void {
self.bin_file.destroy();
if (optional_module) |module| module.deinit();
if (self.stage1_module) |module| {
module.main_progress_node.?.end();
module.destroy();
}
const gpa = self.gpa;
self.work_queue.deinit();
@ -997,6 +1149,10 @@ pub fn performAllTheWork(self: *Compilation) error{OutOfMemory}!void {
fatal("unable to update builtin.zig file: {}", .{@errorName(err)});
};
},
.stage1_module => {
// This Job is only queued up if there is a zig module.
self.stage1_module.?.build_object();
},
};
}
@ -1365,7 +1521,7 @@ pub fn addCCArgs(
try argv.append("-fPIC");
}
},
.so, .assembly, .ll, .bc, .unknown => {},
.shared_library, .assembly, .ll, .bc, .unknown, .static_library, .object, .zig, .zir => {},
}
if (out_dep_path) |p| {
try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p });
@ -1445,17 +1601,39 @@ pub const FileExt = enum {
ll,
bc,
assembly,
so,
shared_library,
object,
static_library,
zig,
zir,
unknown,
pub fn clangSupportsDepFile(ext: FileExt) bool {
return switch (ext) {
.c, .cpp, .h => true,
.ll, .bc, .assembly, .so, .unknown => false,
.ll,
.bc,
.assembly,
.shared_library,
.object,
.static_library,
.zig,
.zir,
.unknown,
=> false,
};
}
};
pub fn hasObjectExt(filename: []const u8) bool {
return mem.endsWith(u8, filename, ".o") or mem.endsWith(u8, filename, ".obj");
}
pub fn hasStaticLibraryExt(filename: []const u8) bool {
return mem.endsWith(u8, filename, ".a") or mem.endsWith(u8, filename, ".lib");
}
pub fn hasCExt(filename: []const u8) bool {
return mem.endsWith(u8, filename, ".c");
}
@ -1471,6 +1649,32 @@ pub fn hasAsmExt(filename: []const u8) bool {
return mem.endsWith(u8, filename, ".s") or mem.endsWith(u8, filename, ".S");
}
pub fn hasSharedLibraryExt(filename: []const u8) bool {
if (mem.endsWith(u8, filename, ".so") or
mem.endsWith(u8, filename, ".dll") or
mem.endsWith(u8, filename, ".dylib"))
{
return true;
}
// Look for .so.X, .so.X.Y, .so.X.Y.Z
var it = mem.split(filename, ".");
_ = it.next().?;
var so_txt = it.next() orelse return false;
while (!mem.eql(u8, so_txt, "so")) {
so_txt = it.next() orelse return false;
}
const n1 = it.next() orelse return false;
const n2 = it.next();
const n3 = it.next();
_ = std.fmt.parseInt(u32, n1, 10) catch return false;
if (n2) |x| _ = std.fmt.parseInt(u32, x, 10) catch return false;
if (n3) |x| _ = std.fmt.parseInt(u32, x, 10) catch return false;
if (it.next() != null) return false;
return true;
}
pub fn classifyFileExt(filename: []const u8) FileExt {
if (hasCExt(filename)) {
return .c;
@ -1484,26 +1688,19 @@ pub fn classifyFileExt(filename: []const u8) FileExt {
return .assembly;
} else if (mem.endsWith(u8, filename, ".h")) {
return .h;
} else if (mem.endsWith(u8, filename, ".so")) {
return .so;
} else if (mem.endsWith(u8, filename, ".zig")) {
return .zig;
} else if (mem.endsWith(u8, filename, ".zir")) {
return .zig;
} else if (hasSharedLibraryExt(filename)) {
return .shared_library;
} else if (hasStaticLibraryExt(filename)) {
return .static_library;
} else if (hasObjectExt(filename)) {
return .object;
} else {
return .unknown;
}
// Look for .so.X, .so.X.Y, .so.X.Y.Z
var it = mem.split(filename, ".");
_ = it.next().?;
var so_txt = it.next() orelse return .unknown;
while (!mem.eql(u8, so_txt, "so")) {
so_txt = it.next() orelse return .unknown;
}
const n1 = it.next() orelse return .unknown;
const n2 = it.next();
const n3 = it.next();
_ = std.fmt.parseInt(u32, n1, 10) catch return .unknown;
if (n2) |x| _ = std.fmt.parseInt(u32, x, 10) catch return .unknown;
if (n3) |x| _ = std.fmt.parseInt(u32, x, 10) catch return .unknown;
if (it.next() != null) return .unknown;
return .so;
}
test "classifyFileExt" {
@ -1681,7 +1878,7 @@ pub fn dump_argv(argv: []const []const u8) void {
}
pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8 {
var buffer = std.ArrayList(u8).init(comp.gpa);
var buffer = std.ArrayList(u8).init(allocator);
defer buffer.deinit();
const target = comp.getTarget();
@ -1691,9 +1888,9 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
try buffer.writer().print(
\\usingnamespace @import("std").builtin;
\\/// Deprecated
\\pub const arch = std.Target.current.cpu.arch;
\\pub const arch = Target.current.cpu.arch;
\\/// Deprecated
\\pub const endian = std.Target.current.cpu.arch.endian();
\\pub const endian = Target.current.cpu.arch.endian();
\\pub const output_mode = OutputMode.{};
\\pub const link_mode = LinkMode.{};
\\pub const is_test = {};

View File

@ -69,6 +69,7 @@ pub const Options = struct {
linker_script: ?[]const u8 = null,
version_script: ?[]const u8 = null,
override_soname: ?[]const u8 = null,
llvm_cpu_features: ?[*:0]const u8 = null,
/// Extra args passed directly to LLD. Ignored when not linking with LLD.
extra_lld_args: []const []const u8 = &[0][]const u8,
@ -134,6 +135,18 @@ pub const File = struct {
/// rewriting it. A malicious file is detected as incremental link failure
/// and does not cause Illegal Behavior. This operation is not atomic.
pub fn openPath(allocator: *Allocator, options: Options) !*File {
const use_stage1 = build_options.is_stage1 and options.use_llvm;
if (use_stage1) {
return switch (options.object_format) {
.coff, .pe => &(try Coff.createEmpty(allocator, options)).base,
.elf => &(try Elf.createEmpty(allocator, options)).base,
.macho => &(try MachO.createEmpty(allocator, options)).base,
.wasm => &(try Wasm.createEmpty(allocator, options)).base,
.c => unreachable, // Reported error earlier.
.hex => return error.HexObjectFormatUnimplemented,
.raw => return error.RawObjectFormatUnimplemented,
};
}
const use_lld = build_options.have_llvm and options.use_lld; // comptime known false when !have_llvm
const sub_path = if (use_lld) blk: {
if (options.module == null) {

View File

@ -1222,13 +1222,16 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
// If there is no Zig code to compile, then we should skip flushing the output file because it
// will not be part of the linker line anyway.
const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: {
try self.flushModule(comp);
const use_stage1 = build_options.is_stage1 and self.base.options.use_llvm;
if (use_stage1) {
const obj_basename = try std.fmt.allocPrint(arena, "{}.o", .{self.base.options.root_name});
const full_obj_path = try directory.join(arena, &[_][]const u8{obj_basename});
break :blk full_obj_path;
}
try self.flushModule(comp);
const obj_basename = self.base.intermediary_basename.?;
const full_obj_path = if (directory.path) |dir_path|
try std.fs.path.join(arena, &[_][]const u8{dir_path, obj_basename})
else
obj_basename;
const full_obj_path = try directory.join(arena, &[_][]const u8{obj_basename});
break :blk full_obj_path;
} else null;
@ -1504,7 +1507,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
// (the check for that needs to be earlier), but they could be full paths to .so files, in which
// case we want to avoid prepending "-l".
const ext = Compilation.classifyFileExt(link_lib);
const arg = if (ext == .so) link_lib else try std.fmt.allocPrint(arena, "-l{}", .{link_lib});
const arg = if (ext == .shared_library) link_lib else try std.fmt.allocPrint(arena, "-l{}", .{link_lib});
argv.appendAssumeCapacity(arg);
}

View File

@ -222,21 +222,27 @@ const usage_build_generic =
\\ --libc [file] Provide a file which specifies libc paths
\\
\\Link Options:
\\ -l[lib], --library [lib] Link against system library
\\ -l[lib], --library [lib] Link against system library
\\ -L[d], --library-directory [d] Add a directory to the library search path
\\ -T[script] Use a custom linker script
\\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)
\\ --version [ver] Dynamic library semver
\\ -rdynamic Add all symbols to the dynamic symbol table
\\ -rpath [path] Add directory to the runtime library search path
\\ --eh-frame-hdr Enable C++ exception handling by passing --eh-frame-hdr to linker
\\ -dynamic Force output to be dynamically linked
\\ -static Force output to be statically linked
\\ -T[script] Use a custom linker script
\\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)
\\ --version [ver] Dynamic library semver
\\ -rdynamic Add all symbols to the dynamic symbol table
\\ -rpath [path] Add directory to the runtime library search path
\\ --eh-frame-hdr Enable C++ exception handling by passing --eh-frame-hdr to linker
\\ -dynamic Force output to be dynamically linked
\\ -static Force output to be statically linked
\\
\\Debug Options (Zig Compiler Development):
\\ -ftime-report Print timing diagnostics
\\ --verbose-link Display linker invocations
\\ --verbose-cc Display C compiler invocations
\\ -ftime-report Print timing diagnostics
\\ --verbose-link Display linker invocations
\\ --verbose-cc Display C compiler invocations
\\ --verbose-tokenize Enable compiler debug output for tokenization
\\ --verbose-ast Enable compiler debug output for AST parsing
\\ --verbose-ir Enable compiler debug output for Zig IR
\\ --verbose-llvm-ir Enable compiler debug output for LLVM IR
\\ --verbose-cimport Enable compiler debug output for C imports
\\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features
\\
;
@ -278,6 +284,12 @@ pub fn buildOutputType(
var watch = false;
var verbose_link = false;
var verbose_cc = false;
var verbose_tokenize = false;
var verbose_ast = false;
var verbose_ir = false;
var verbose_llvm_ir = false;
var verbose_cimport = false;
var verbose_llvm_cpu_features = false;
var time_report = false;
var show_builtin = false;
var emit_bin: Emit = .yes_default_path;
@ -548,6 +560,18 @@ pub fn buildOutputType(
verbose_link = true;
} else if (mem.eql(u8, arg, "--verbose-cc")) {
verbose_cc = true;
} else if (mem.eql(u8, arg, "--verbose-tokenize")) {
verbose_tokenize = true;
} else if (mem.eql(u8, arg, "--verbose-ast")) {
verbose_ast = true;
} else if (mem.eql(u8, arg, "--verbose-ir")) {
verbose_ir = true;
} else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
verbose_llvm_ir = true;
} else if (mem.eql(u8, arg, "--verbose-cimport")) {
verbose_cimport = true;
} else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) {
verbose_llvm_cpu_features = true;
} else if (mem.startsWith(u8, arg, "-T")) {
linker_script = arg[2..];
} else if (mem.startsWith(u8, arg, "-L")) {
@ -563,28 +587,27 @@ pub fn buildOutputType(
} else {
fatal("unrecognized parameter: '{}'", .{arg});
}
} else if (mem.endsWith(u8, arg, ".o") or
mem.endsWith(u8, arg, ".obj") or
mem.endsWith(u8, arg, ".a") or
mem.endsWith(u8, arg, ".lib"))
{
try link_objects.append(arg);
} else if (Compilation.hasAsmExt(arg) or Compilation.hasCExt(arg) or Compilation.hasCppExt(arg)) {
// TODO a way to pass extra flags on the CLI
try c_source_files.append(.{ .src_path = arg });
} else if (mem.endsWith(u8, arg, ".so") or
mem.endsWith(u8, arg, ".dylib") or
mem.endsWith(u8, arg, ".dll"))
{
fatal("linking against dynamic libraries not yet supported", .{});
} else if (mem.endsWith(u8, arg, ".zig") or mem.endsWith(u8, arg, ".zir")) {
if (root_src_file) |other| {
fatal("found another zig file '{}' after root source file '{}'", .{ arg, other });
} else {
root_src_file = arg;
}
} else {
fatal("unrecognized file extension of parameter '{}'", .{arg});
} else switch (Compilation.classifyFileExt(arg)) {
.object, .static_library => {
try link_objects.append(arg);
},
.assembly, .c, .cpp, .h, .ll, .bc => {
// TODO a way to pass extra flags on the CLI
try c_source_files.append(.{ .src_path = arg });
},
.shared_library => {
fatal("linking against dynamic libraries not yet supported", .{});
},
.zig, .zir => {
if (root_src_file) |other| {
fatal("found another zig file '{}' after root source file '{}'", .{ arg, other });
} else {
root_src_file = arg;
}
},
.unknown => {
fatal("unrecognized file extension of parameter '{}'", .{arg});
},
}
}
} else {
@ -617,7 +640,16 @@ pub fn buildOutputType(
const file_ext = Compilation.classifyFileExt(mem.spanZ(it.only_arg));
switch (file_ext) {
.assembly, .c, .cpp, .ll, .bc, .h => try c_source_files.append(.{ .src_path = it.only_arg }),
.unknown, .so => try link_objects.append(it.only_arg),
.unknown, .shared_library, .object, .static_library => {
try link_objects.append(it.only_arg);
},
.zig, .zir => {
if (root_src_file) |other| {
fatal("found another zig file '{}' after root source file '{}'", .{ it.only_arg, other });
} else {
root_src_file = it.only_arg;
}
},
}
},
.l => {
@ -1173,7 +1205,15 @@ pub fn buildOutputType(
.libc_installation = if (libc_installation) |*lci| lci else null,
.verbose_cc = verbose_cc,
.verbose_link = verbose_link,
.verbose_tokenize = verbose_tokenize,
.verbose_ast = verbose_ast,
.verbose_ir = verbose_ir,
.verbose_llvm_ir = verbose_llvm_ir,
.verbose_cimport = verbose_cimport,
.verbose_llvm_cpu_features = verbose_llvm_cpu_features,
.machine_code_model = machine_code_model,
.color = color,
.time_report = time_report,
}) catch |err| {
fatal("unable to create compilation: {}", .{@errorName(err)});
};
@ -1193,6 +1233,10 @@ pub fn buildOutputType(
fatal("TODO: implement `zig cc` when using it as a preprocessor", .{});
}
if (build_options.is_stage1 and comp.stage1_module != null and watch) {
std.log.warn("--watch is not recommended with the stage1 backend; it leaks memory and is not capable of incremental compilation", .{});
}
const stdin = std.io.getStdIn().inStream();
const stderr = std.io.getStdErr().outStream();
var repl_buf: [1024]u8 = undefined;

View File

@ -10,6 +10,7 @@ const stage2 = @import("main.zig");
const fatal = stage2.fatal;
const CrossTarget = std.zig.CrossTarget;
const Target = std.Target;
const Compilation = @import("Compilation.zig");
comptime {
assert(std.builtin.link_libc);
@ -23,6 +24,8 @@ pub const log_level = stage2.log_level;
pub export fn main(argc: c_int, argv: [*]const [*:0]const u8) c_int {
std.debug.maybeEnableSegfaultHandler();
zig_stage1_os_init();
const gpa = std.heap.c_allocator;
var arena_instance = std.heap.ArenaAllocator.init(gpa);
defer arena_instance.deinit();
@ -36,6 +39,106 @@ pub export fn main(argc: c_int, argv: [*]const [*:0]const u8) c_int {
return 0;
}
/// Matches stage2.Color;
pub const ErrColor = c_int;
/// Matches std.builtin.CodeModel
pub const CodeModel = c_int;
/// Matches std.Target.Os.Tag
pub const OS = c_int;
/// Matches std.builtin.BuildMode
pub const BuildMode = c_int;
pub const TargetSubsystem = extern enum(c_int) {
Console,
Windows,
Posix,
Native,
EfiApplication,
EfiBootServiceDriver,
EfiRom,
EfiRuntimeDriver,
Auto,
};
pub const Pkg = extern struct {
name_ptr: [*]const u8,
name_len: usize,
path_ptr: [*]const u8,
path_len: usize,
children_ptr: [*]*Pkg,
children_len: usize,
parent: ?*Pkg,
};
pub const Module = extern struct {
root_name_ptr: [*]const u8,
root_name_len: usize,
output_dir_ptr: [*]const u8,
output_dir_len: usize,
builtin_zig_path_ptr: [*]const u8,
builtin_zig_path_len: usize,
test_filter_ptr: [*]const u8,
test_filter_len: usize,
test_name_prefix_ptr: [*]const u8,
test_name_prefix_len: usize,
userdata: usize,
root_pkg: *Pkg,
main_progress_node: ?*std.Progress.Node,
code_model: CodeModel,
subsystem: TargetSubsystem,
err_color: ErrColor,
pic: bool,
link_libc: bool,
link_libcpp: bool,
strip: bool,
is_single_threaded: bool,
dll_export_fns: bool,
link_mode_dynamic: bool,
valgrind_enabled: bool,
function_sections: bool,
enable_stack_probing: bool,
enable_time_report: bool,
enable_stack_report: bool,
dump_analysis: bool,
enable_doc_generation: bool,
emit_bin: bool,
emit_asm: bool,
emit_llvm_ir: bool,
test_is_evented: bool,
verbose_tokenize: bool,
verbose_ast: bool,
verbose_ir: bool,
verbose_llvm_ir: bool,
verbose_cimport: bool,
verbose_llvm_cpu_features: bool,
pub fn build_object(mod: *Module) void {
zig_stage1_build_object(mod);
}
pub fn destroy(mod: *Module) void {
zig_stage1_destroy(mod);
}
};
extern fn zig_stage1_os_init() void;
pub const create = zig_stage1_create;
extern fn zig_stage1_create(
optimize_mode: BuildMode,
main_pkg_path_ptr: [*]const u8,
main_pkg_path_len: usize,
root_src_path_ptr: [*]const u8,
root_src_path_len: usize,
zig_lib_dir_ptr: [*c]const u8,
zig_lib_dir_len: usize,
target: [*c]const Stage2Target,
is_test_build: bool,
) ?*Module;
extern fn zig_stage1_build_object(*Module) void;
extern fn zig_stage1_destroy(*Module) void;
// ABI warning
export fn stage2_panic(ptr: [*]const u8, len: usize) void {
@panic(ptr[0..len]);
@ -199,297 +302,50 @@ export fn stage2_progress_update_node(node: *std.Progress.Node, done_count: usiz
}
// ABI warning
const Stage2Target = extern struct {
pub const Stage2Target = extern struct {
arch: c_int,
vendor: c_int,
os: OS,
abi: c_int,
os: c_int,
is_native_os: bool,
is_native_cpu: bool,
llvm_cpu_name: ?[*:0]const u8,
llvm_cpu_features: ?[*:0]const u8,
cpu_builtin_str: ?[*:0]const u8,
os_builtin_str: ?[*:0]const u8,
dynamic_linker: ?[*:0]const u8,
llvm_cpu_features_asm_ptr: [*]const [*:0]const u8,
llvm_cpu_features_asm_len: usize,
fn fromTarget(self: *Stage2Target, cross_target: CrossTarget) !void {
const allocator = std.heap.c_allocator;
var dynamic_linker: ?[*:0]u8 = null;
const target = try crossTargetToTarget(cross_target, &dynamic_linker);
const generic_arch_name = target.cpu.arch.genericName();
var cpu_builtin_str_buffer = try std.ArrayListSentineled(u8, 0).allocPrint(allocator,
\\Cpu{{
\\ .arch = .{},
\\ .model = &Target.{}.cpu.{},
\\ .features = Target.{}.featureSet(&[_]Target.{}.Feature{{
\\
, .{
@tagName(target.cpu.arch),
generic_arch_name,
target.cpu.model.name,
generic_arch_name,
generic_arch_name,
});
defer cpu_builtin_str_buffer.deinit();
var llvm_features_buffer = try std.ArrayListSentineled(u8, 0).initSize(allocator, 0);
defer llvm_features_buffer.deinit();
// Unfortunately we have to do the work twice, because Clang does not support
// the same command line parameters for CPU features when assembling code as it does
// when compiling C code.
var asm_features_list = std.ArrayList([*:0]const u8).init(allocator);
defer asm_features_list.deinit();
for (target.cpu.arch.allFeaturesList()) |feature, index_usize| {
const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
const is_enabled = target.cpu.features.isEnabled(index);
if (feature.llvm_name) |llvm_name| {
const plus_or_minus = "-+"[@boolToInt(is_enabled)];
try llvm_features_buffer.append(plus_or_minus);
try llvm_features_buffer.appendSlice(llvm_name);
try llvm_features_buffer.appendSlice(",");
}
if (is_enabled) {
// TODO some kind of "zig identifier escape" function rather than
// unconditionally using @"" syntax
try cpu_builtin_str_buffer.appendSlice(" .@\"");
try cpu_builtin_str_buffer.appendSlice(feature.name);
try cpu_builtin_str_buffer.appendSlice("\",\n");
}
}
switch (target.cpu.arch) {
.riscv32, .riscv64 => {
if (Target.riscv.featureSetHas(target.cpu.features, .relax)) {
try asm_features_list.append("-mrelax");
} else {
try asm_features_list.append("-mno-relax");
}
},
else => {
// TODO
// Argh, why doesn't the assembler accept the list of CPU features?!
// I don't see a way to do this other than hard coding everything.
},
}
try cpu_builtin_str_buffer.appendSlice(
\\ }),
\\};
\\
);
assert(mem.endsWith(u8, llvm_features_buffer.span(), ","));
llvm_features_buffer.shrink(llvm_features_buffer.len() - 1);
var os_builtin_str_buffer = try std.ArrayListSentineled(u8, 0).allocPrint(allocator,
\\Os{{
\\ .tag = .{},
\\ .version_range = .{{
, .{@tagName(target.os.tag)});
defer os_builtin_str_buffer.deinit();
// We'll re-use the OS version range builtin string for the cache hash.
const os_builtin_str_ver_start_index = os_builtin_str_buffer.len();
@setEvalBranchQuota(2000);
switch (target.os.tag) {
.freestanding,
.ananas,
.cloudabi,
.dragonfly,
.fuchsia,
.ios,
.kfreebsd,
.lv2,
.solaris,
.haiku,
.minix,
.rtems,
.nacl,
.cnk,
.aix,
.cuda,
.nvcl,
.amdhsa,
.ps4,
.elfiamcu,
.tvos,
.watchos,
.mesa3d,
.contiki,
.amdpal,
.hermit,
.hurd,
.wasi,
.emscripten,
.uefi,
.other,
=> try os_builtin_str_buffer.appendSlice(" .none = {} }\n"),
.freebsd,
.macosx,
.netbsd,
.openbsd,
=> try os_builtin_str_buffer.outStream().print(
\\ .semver = .{{
\\ .min = .{{
\\ .major = {},
\\ .minor = {},
\\ .patch = {},
\\ }},
\\ .max = .{{
\\ .major = {},
\\ .minor = {},
\\ .patch = {},
\\ }},
\\ }}}},
\\
, .{
target.os.version_range.semver.min.major,
target.os.version_range.semver.min.minor,
target.os.version_range.semver.min.patch,
target.os.version_range.semver.max.major,
target.os.version_range.semver.max.minor,
target.os.version_range.semver.max.patch,
}),
.linux => try os_builtin_str_buffer.outStream().print(
\\ .linux = .{{
\\ .range = .{{
\\ .min = .{{
\\ .major = {},
\\ .minor = {},
\\ .patch = {},
\\ }},
\\ .max = .{{
\\ .major = {},
\\ .minor = {},
\\ .patch = {},
\\ }},
\\ }},
\\ .glibc = .{{
\\ .major = {},
\\ .minor = {},
\\ .patch = {},
\\ }},
\\ }}}},
\\
, .{
target.os.version_range.linux.range.min.major,
target.os.version_range.linux.range.min.minor,
target.os.version_range.linux.range.min.patch,
target.os.version_range.linux.range.max.major,
target.os.version_range.linux.range.max.minor,
target.os.version_range.linux.range.max.patch,
target.os.version_range.linux.glibc.major,
target.os.version_range.linux.glibc.minor,
target.os.version_range.linux.glibc.patch,
}),
.windows => try os_builtin_str_buffer.outStream().print(
\\ .windows = .{{
\\ .min = {s},
\\ .max = {s},
\\ }}}},
\\
, .{
target.os.version_range.windows.min,
target.os.version_range.windows.max,
}),
}
try os_builtin_str_buffer.appendSlice("};\n");
const glibc_or_darwin_version = blk: {
if (target.isGnuLibC()) {
const stage1_glibc = try std.heap.c_allocator.create(Stage2SemVer);
const stage2_glibc = target.os.version_range.linux.glibc;
stage1_glibc.* = .{
.major = stage2_glibc.major,
.minor = stage2_glibc.minor,
.patch = stage2_glibc.patch,
};
break :blk stage1_glibc;
} else if (target.isDarwin()) {
const stage1_semver = try std.heap.c_allocator.create(Stage2SemVer);
const stage2_semver = target.os.version_range.semver.min;
stage1_semver.* = .{
.major = stage2_semver.major,
.minor = stage2_semver.minor,
.patch = stage2_semver.patch,
};
break :blk stage1_semver;
} else {
break :blk null;
}
};
const std_dl = target.standardDynamicLinkerPath();
const std_dl_z = if (std_dl.get()) |dl|
(try mem.dupeZ(std.heap.c_allocator, u8, dl)).ptr
else
null;
const asm_features = asm_features_list.toOwnedSlice();
self.* = .{
.arch = @enumToInt(target.cpu.arch) + 1, // skip over ZigLLVM_UnknownArch
.vendor = 0,
.os = @enumToInt(target.os.tag),
.abi = @enumToInt(target.abi),
.llvm_cpu_name = if (target.cpu.model.llvm_name) |s| s.ptr else null,
.llvm_cpu_features = llvm_features_buffer.toOwnedSlice().ptr,
.llvm_cpu_features_asm_ptr = asm_features.ptr,
.llvm_cpu_features_asm_len = asm_features.len,
.cpu_builtin_str = cpu_builtin_str_buffer.toOwnedSlice().ptr,
.os_builtin_str = os_builtin_str_buffer.toOwnedSlice().ptr,
.is_native_os = cross_target.isNativeOs(),
.is_native_cpu = cross_target.isNativeCpu(),
.glibc_or_darwin_version = glibc_or_darwin_version,
.dynamic_linker = dynamic_linker,
.standard_dynamic_linker_path = std_dl_z,
};
}
};
fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8) !Target {
var info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator, cross_target);
if (info.cpu_detection_unimplemented) {
// TODO We want to just use detected_info.target but implementing
// CPU model & feature detection is todo so here we rely on LLVM.
const llvm = @import("llvm.zig");
const llvm_cpu_name = llvm.GetHostCPUName();
const llvm_cpu_features = llvm.GetNativeFeatures();
const arch = Target.current.cpu.arch;
info.target.cpu = try detectNativeCpuWithLLVM(arch, llvm_cpu_name, llvm_cpu_features);
cross_target.updateCpuFeatures(&info.target.cpu.features);
info.target.cpu.arch = cross_target.getCpuArch();
}
if (info.dynamic_linker.get()) |dl| {
dynamic_linker_ptr.* = try mem.dupeZ(std.heap.c_allocator, u8, dl);
} else {
dynamic_linker_ptr.* = null;
}
return info.target;
}
// ABI warning
const Stage2SemVer = extern struct {
major: u32,
minor: u32,
patch: u32,
};
// ABI warning
export fn stage2_cimport(stage1: *Module) [*:0]const u8 {
@panic("TODO implement stage2_cimport");
}
export fn stage2_add_link_lib(
stage1: *Module,
lib_name_ptr: [*c]const u8,
lib_name_len: usize,
symbol_name_ptr: [*c]const u8,
symbol_name_len: usize,
) ?[*:0]const u8 {
return null; // no error
}
export fn stage2_fetch_file(
stage1: *Module,
path_ptr: [*]const u8,
path_len: usize,
result_len: *usize,
) ?[*]const u8 {
const comp = @intToPtr(*Compilation, stage1.userdata);
// TODO integrate this with cache hash
const file_path = path_ptr[0..path_len];
const contents = std.fs.cwd().readFileAlloc(comp.gpa, file_path, std.math.maxInt(u32)) catch return null;
result_len.* = contents.len;
return contents.ptr;
}

View File

@ -7987,7 +7987,7 @@ Error file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents_buf) {
size_t len;
const char *contents = stage2_fetch_file(&g->stage1, buf_ptr(resolved_path), buf_len(resolved_path), &len);
if (contents == nullptr)
return ErrorNoMem;
return ErrorFileNotFound;
buf_init_from_mem(contents_buf, contents, len);
return ErrorNone;
}

View File

@ -8809,33 +8809,18 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
static_assert(TargetSubsystemEfiBootServiceDriver == 5, "");
static_assert(TargetSubsystemEfiRom == 6, "");
static_assert(TargetSubsystemEfiRuntimeDriver == 7, "");
{
const char *endian_str = g->is_big_endian ? "Endian.Big" : "Endian.Little";
buf_appendf(contents, "pub const endian = %s;\n", endian_str);
}
buf_append_str(contents, "/// Deprecated: use `std.Target.current.cpu.arch`\n");
buf_append_str(contents, "pub const arch = Target.current.cpu.arch;\n");
buf_append_str(contents, "/// Deprecated: use `std.Target.current.cpu.arch.endian()`\n");
buf_append_str(contents, "pub const endian = Target.current.cpu.arch.endian();\n");
buf_appendf(contents, "pub const output_mode = OutputMode.Obj;\n");
buf_appendf(contents, "pub const link_mode = LinkMode.Static;\n");
buf_appendf(contents, "pub const is_test = false;\n");
buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded));
buf_append_str(contents, "/// Deprecated: use `std.Target.cpu.arch`\n");
buf_appendf(contents, "pub const arch = Arch.%s;\n", cur_arch);
buf_appendf(contents, "pub const abi = Abi.%s;\n", cur_abi);
{
buf_append_str(contents, "pub const cpu: Cpu = ");
if (g->zig_target->cpu_builtin_str != nullptr) {
buf_append_str(contents, g->zig_target->cpu_builtin_str);
} else {
buf_appendf(contents, "Target.Cpu.baseline(.%s);\n", cur_arch);
}
}
{
buf_append_str(contents, "pub const os = ");
if (g->zig_target->os_builtin_str != nullptr) {
buf_append_str(contents, g->zig_target->os_builtin_str);
} else {
buf_appendf(contents, "Target.Os.Tag.defaultVersionRange(.%s);\n", cur_os);
}
}
buf_appendf(contents, "pub const cpu: Cpu = Target.Cpu.baseline(.%s);\n", cur_arch);
buf_appendf(contents, "pub const os = Target.Os.Tag.defaultVersionRange(.%s);\n", cur_os);
buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt);
buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode));
buf_appendf(contents, "pub const link_libc = %s;\n", bool_to_str(g->link_libc));
@ -8866,6 +8851,8 @@ static Error define_builtin_compile_vars(CodeGen *g) {
if (g->std_package == nullptr)
return ErrorNone;
assert(g->main_pkg);
const char *builtin_zig_basename = "builtin.zig";
Buf *contents;
@ -8879,17 +8866,22 @@ static Error define_builtin_compile_vars(CodeGen *g) {
fprintf(stderr, "Unable to write file '%s': %s\n", buf_ptr(g->builtin_zig_path), err_str(err));
exit(1);
}
g->compile_var_package = new_package(buf_ptr(g->output_dir), builtin_zig_basename, "builtin");
} else {
Buf *resolve_paths[] = { g->builtin_zig_path, };
*g->builtin_zig_path = os_path_resolve(resolve_paths, 1);
contents = buf_alloc();
if ((err = os_fetch_file_path(g->builtin_zig_path, contents))) {
fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(g->builtin_zig_path), err_str(err));
exit(1);
}
Buf builtin_dirname = BUF_INIT;
os_path_dirname(g->builtin_zig_path, &builtin_dirname);
g->compile_var_package = new_package(buf_ptr(&builtin_dirname), builtin_zig_basename, "builtin");
}
assert(g->main_pkg);
assert(g->std_package);
g->compile_var_package = new_package(buf_ptr(g->output_dir), builtin_zig_basename, "builtin");
if (g->is_test_build) {
if (g->test_runner_package == nullptr) {
g->test_runner_package = create_test_runner_pkg(g);
@ -8914,6 +8906,13 @@ static void init(CodeGen *g) {
if (g->module)
return;
codegen_add_time_event(g, "Initialize");
{
const char *progress_name = "Initialize";
codegen_switch_sub_prog_node(g, stage2_progress_start(g->main_progress_node,
progress_name, strlen(progress_name), 0));
}
g->have_err_ret_tracing = detect_err_ret_tracing(g);
assert(g->root_out_name);
@ -9374,19 +9373,11 @@ void codegen_destroy(CodeGen *g) {
CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,
BuildMode build_mode, Buf *override_lib_dir,
bool is_test_build, Stage2ProgressNode *progress_node)
bool is_test_build)
{
CodeGen *g = heap::c_allocator.create<CodeGen>();
g->emit_bin = true;
g->pass1_arena = heap::ArenaAllocator::construct(&heap::c_allocator, &heap::c_allocator, "pass1");
g->main_progress_node = progress_node;
codegen_add_time_event(g, "Initialize");
{
const char *progress_name = "Initialize";
codegen_switch_sub_prog_node(g, stage2_progress_start(g->main_progress_node,
progress_name, strlen(progress_name), 0));
}
g->subsystem = TargetSubsystemAuto;
g->zig_target = target;
@ -9440,7 +9431,7 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget
Buf resolved_main_pkg_path = os_path_resolve(&main_pkg_path, 1);
if (!buf_starts_with_buf(&resolved_root_src_path, &resolved_main_pkg_path)) {
fprintf(stderr, "Root source path '%s' outside main package path '%s'",
fprintf(stderr, "Root source path '%s' outside main package path '%s'\n",
buf_ptr(root_src_path), buf_ptr(main_pkg_path));
exit(1);
}

View File

@ -16,8 +16,7 @@
#include <stdio.h>
CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,
BuildMode build_mode, Buf *zig_lib_dir,
bool is_test_build, Stage2ProgressNode *progress_node);
BuildMode build_mode, Buf *zig_lib_dir, bool is_test_build);
void codegen_build_object(CodeGen *g);
void codegen_destroy(CodeGen *);

View File

@ -20,13 +20,14 @@ struct ZigStage1 *zig_stage1_create(BuildMode optimize_mode,
const char *main_pkg_path_ptr, size_t main_pkg_path_len,
const char *root_src_path_ptr, size_t root_src_path_len,
const char *zig_lib_dir_ptr, size_t zig_lib_dir_len,
const ZigTarget *target, bool is_test_build, Stage2ProgressNode *progress_node)
const ZigTarget *target, bool is_test_build)
{
Buf *main_pkg_path = buf_create_from_mem(main_pkg_path_ptr, main_pkg_path_len);
Buf *main_pkg_path = (main_pkg_path_len == 0) ?
nullptr : buf_create_from_mem(main_pkg_path_ptr, main_pkg_path_len);
Buf *root_src_path = buf_create_from_mem(root_src_path_ptr, root_src_path_len);
Buf *zig_lib_dir = buf_create_from_mem(zig_lib_dir_ptr, zig_lib_dir_len);
CodeGen *g = codegen_create(main_pkg_path, root_src_path, target, optimize_mode,
zig_lib_dir, is_test_build, progress_node);
zig_lib_dir, is_test_build);
return &g->stage1;
}
@ -68,8 +69,6 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {
CodeGen *g = reinterpret_cast<CodeGen *>(stage1);
g->root_out_name = buf_create_from_mem(stage1->root_name_ptr, stage1->root_name_len);
g->zig_lib_dir = buf_create_from_mem(stage1->zig_lib_dir_ptr, stage1->zig_lib_dir_len);
g->zig_std_dir = buf_create_from_mem(stage1->zig_std_dir_ptr, stage1->zig_std_dir_len);
g->output_dir = buf_create_from_mem(stage1->output_dir_ptr, stage1->output_dir_len);
if (stage1->builtin_zig_path_len != 0) {
g->builtin_zig_path = buf_create_from_mem(stage1->builtin_zig_path_ptr, stage1->builtin_zig_path_len);
@ -119,6 +118,8 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {
}
}
g->main_progress_node = stage1->main_progress_node;
add_package(g, stage1->root_pkg, g->main_pkg);
codegen_build_object(g);

View File

@ -100,22 +100,14 @@ enum Os {
// ABI warning
struct ZigTarget {
enum ZigLLVM_ArchType arch;
enum ZigLLVM_VendorType vendor;
enum Os os;
enum ZigLLVM_EnvironmentType abi;
Os os;
bool is_native_os;
bool is_native_cpu;
const char *llvm_cpu_name;
const char *llvm_cpu_features;
const char *cpu_builtin_str;
const char *os_builtin_str;
const char *dynamic_linker;
const char **llvm_cpu_features_asm_ptr;
size_t llvm_cpu_features_asm_len;
};
// ABI warning
@ -161,18 +153,13 @@ struct ZigStage1 {
const char *test_name_prefix_ptr;
size_t test_name_prefix_len;
const char *zig_lib_dir_ptr;
size_t zig_lib_dir_len;
const char *zig_std_dir_ptr;
size_t zig_std_dir_len;
void *userdata;
struct ZigStage1Pkg *root_pkg;
struct Stage2ProgressNode *main_progress_node;
CodeModel code_model;
TargetSubsystem subsystem;
ErrColor err_color;
enum CodeModel code_model;
enum TargetSubsystem subsystem;
enum ErrColor err_color;
bool pic;
bool link_libc;
@ -206,7 +193,7 @@ ZIG_EXTERN_C struct ZigStage1 *zig_stage1_create(enum BuildMode optimize_mode,
const char *main_pkg_path_ptr, size_t main_pkg_path_len,
const char *root_src_path_ptr, size_t root_src_path_len,
const char *zig_lib_dir_ptr, size_t zig_lib_dir_len,
const ZigTarget *target, bool is_test_build, Stage2ProgressNode *progress_node);
const struct ZigTarget *target, bool is_test_build);
ZIG_EXTERN_C void zig_stage1_build_object(struct ZigStage1 *);

View File

@ -1,241 +0,0 @@
// This file is a shim for zig1. The real implementations of these are in
// src-self-hosted/stage1.zig
#include "stage2.h"
#include "util.hpp"
#include "zig_llvm.h"
#include "target.hpp"
#include "buffer.hpp"
#include "os.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void stage2_panic(const char *ptr, size_t len) {
fwrite(ptr, 1, len, stderr);
fprintf(stderr, "\n");
fflush(stderr);
abort();
}
struct Stage2Progress {
int trash;
};
struct Stage2ProgressNode {
int trash;
};
Stage2Progress *stage2_progress_create(void) {
return nullptr;
}
void stage2_progress_destroy(Stage2Progress *progress) {}
Stage2ProgressNode *stage2_progress_start_root(Stage2Progress *progress,
const char *name_ptr, size_t name_len, size_t estimated_total_items)
{
return nullptr;
}
Stage2ProgressNode *stage2_progress_start(Stage2ProgressNode *node,
const char *name_ptr, size_t name_len, size_t estimated_total_items)
{
return nullptr;
}
void stage2_progress_end(Stage2ProgressNode *node) {}
void stage2_progress_complete_one(Stage2ProgressNode *node) {}
void stage2_progress_disable_tty(Stage2Progress *progress) {}
void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){}
static Os get_zig_os_type(ZigLLVM_OSType os_type) {
switch (os_type) {
case ZigLLVM_UnknownOS:
return OsFreestanding;
case ZigLLVM_Ananas:
return OsAnanas;
case ZigLLVM_CloudABI:
return OsCloudABI;
case ZigLLVM_DragonFly:
return OsDragonFly;
case ZigLLVM_FreeBSD:
return OsFreeBSD;
case ZigLLVM_Fuchsia:
return OsFuchsia;
case ZigLLVM_IOS:
return OsIOS;
case ZigLLVM_KFreeBSD:
return OsKFreeBSD;
case ZigLLVM_Linux:
return OsLinux;
case ZigLLVM_Lv2:
return OsLv2;
case ZigLLVM_Darwin:
case ZigLLVM_MacOSX:
return OsMacOSX;
case ZigLLVM_NetBSD:
return OsNetBSD;
case ZigLLVM_OpenBSD:
return OsOpenBSD;
case ZigLLVM_Solaris:
return OsSolaris;
case ZigLLVM_Win32:
return OsWindows;
case ZigLLVM_Haiku:
return OsHaiku;
case ZigLLVM_Minix:
return OsMinix;
case ZigLLVM_RTEMS:
return OsRTEMS;
case ZigLLVM_NaCl:
return OsNaCl;
case ZigLLVM_CNK:
return OsCNK;
case ZigLLVM_AIX:
return OsAIX;
case ZigLLVM_CUDA:
return OsCUDA;
case ZigLLVM_NVCL:
return OsNVCL;
case ZigLLVM_AMDHSA:
return OsAMDHSA;
case ZigLLVM_PS4:
return OsPS4;
case ZigLLVM_ELFIAMCU:
return OsELFIAMCU;
case ZigLLVM_TvOS:
return OsTvOS;
case ZigLLVM_WatchOS:
return OsWatchOS;
case ZigLLVM_Mesa3D:
return OsMesa3D;
case ZigLLVM_Contiki:
return OsContiki;
case ZigLLVM_AMDPAL:
return OsAMDPAL;
case ZigLLVM_HermitCore:
return OsHermitCore;
case ZigLLVM_Hurd:
return OsHurd;
case ZigLLVM_WASI:
return OsWASI;
case ZigLLVM_Emscripten:
return OsEmscripten;
}
zig_unreachable();
}
static void get_native_target(ZigTarget *target) {
// first zero initialize
*target = {};
ZigLLVM_OSType os_type;
ZigLLVM_ObjectFormatType oformat; // ignored; based on arch/os
ZigLLVMGetNativeTarget(
&target->arch,
&target->vendor,
&os_type,
&target->abi,
&oformat);
target->os = get_zig_os_type(os_type);
target->is_native_os = true;
target->is_native_cpu = true;
if (target->abi == ZigLLVM_UnknownEnvironment) {
target->abi = target_default_abi(target->arch, target->os);
}
}
Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu,
const char *dynamic_linker)
{
Error err;
if (zig_triple != nullptr && strcmp(zig_triple, "native") == 0) {
zig_triple = nullptr;
}
if (zig_triple == nullptr) {
get_native_target(target);
if (mcpu == nullptr) {
target->llvm_cpu_name = ZigLLVMGetHostCPUName();
target->llvm_cpu_features = ZigLLVMGetNativeFeatures();
} else if (strcmp(mcpu, "baseline") == 0) {
target->is_native_os = false;
target->is_native_cpu = false;
target->llvm_cpu_name = "";
target->llvm_cpu_features = "";
} else {
const char *msg = "stage0 can't handle CPU/features in the target";
stage2_panic(msg, strlen(msg));
}
} else {
// first initialize all to zero
*target = {};
SplitIterator it = memSplit(str(zig_triple), str("-"));
Optional<Slice<uint8_t>> opt_archsub = SplitIterator_next(&it);
Optional<Slice<uint8_t>> opt_os = SplitIterator_next(&it);
Optional<Slice<uint8_t>> opt_abi = SplitIterator_next(&it);
if (!opt_archsub.is_some)
return ErrorMissingArchitecture;
if ((err = target_parse_arch(&target->arch, (char*)opt_archsub.value.ptr, opt_archsub.value.len))) {
return err;
}
if (!opt_os.is_some)
return ErrorMissingOperatingSystem;
if ((err = target_parse_os(&target->os, (char*)opt_os.value.ptr, opt_os.value.len))) {
return err;
}
if (opt_abi.is_some) {
if ((err = target_parse_abi(&target->abi, (char*)opt_abi.value.ptr, opt_abi.value.len))) {
return err;
}
} else {
target->abi = target_default_abi(target->arch, target->os);
}
if (mcpu != nullptr && strcmp(mcpu, "baseline") != 0) {
const char *msg = "stage0 can't handle CPU/features in the target";
stage2_panic(msg, strlen(msg));
}
}
if (dynamic_linker != nullptr) {
target->dynamic_linker = dynamic_linker;
}
return ErrorNone;
}
const char *stage2_fetch_file(struct ZigStage1 *stage1, const char *path_ptr, size_t path_len,
size_t *result_len)
{
Error err;
Buf contents_buf = BUF_INIT;
Buf path_buf = BUF_INIT;
buf_init_from_mem(&path_buf, path_ptr, path_len);
if ((err = os_fetch_file_path(&path_buf, &contents_buf))) {
return nullptr;
}
*result_len = buf_len(&contents_buf);
return buf_ptr(&contents_buf);
}
const char *stage2_cimport(struct ZigStage1 *stage1) {
const char *msg = "stage0 called stage2_cimport";
stage2_panic(msg, strlen(msg));
}
const char *stage2_add_link_lib(struct ZigStage1 *stage1,
const char *lib_name_ptr, size_t lib_name_len,
const char *symbol_name_ptr, size_t symbol_name_len)
{
return nullptr;
}

View File

@ -130,23 +130,23 @@ struct Stage2ErrorMsg {
ZIG_EXTERN_C ZIG_ATTRIBUTE_NORETURN void stage2_panic(const char *ptr, size_t len);
// ABI warning
ZIG_EXTERN_C Stage2Progress *stage2_progress_create(void);
ZIG_EXTERN_C struct Stage2Progress *stage2_progress_create(void);
// ABI warning
ZIG_EXTERN_C void stage2_progress_disable_tty(Stage2Progress *progress);
ZIG_EXTERN_C void stage2_progress_disable_tty(struct Stage2Progress *progress);
// ABI warning
ZIG_EXTERN_C void stage2_progress_destroy(Stage2Progress *progress);
ZIG_EXTERN_C void stage2_progress_destroy(struct Stage2Progress *progress);
// ABI warning
ZIG_EXTERN_C Stage2ProgressNode *stage2_progress_start_root(Stage2Progress *progress,
ZIG_EXTERN_C struct Stage2ProgressNode *stage2_progress_start_root(struct Stage2Progress *progress,
const char *name_ptr, size_t name_len, size_t estimated_total_items);
// ABI warning
ZIG_EXTERN_C Stage2ProgressNode *stage2_progress_start(Stage2ProgressNode *node,
ZIG_EXTERN_C struct Stage2ProgressNode *stage2_progress_start(struct Stage2ProgressNode *node,
const char *name_ptr, size_t name_len, size_t estimated_total_items);
// ABI warning
ZIG_EXTERN_C void stage2_progress_end(Stage2ProgressNode *node);
ZIG_EXTERN_C void stage2_progress_end(struct Stage2ProgressNode *node);
// ABI warning
ZIG_EXTERN_C void stage2_progress_complete_one(Stage2ProgressNode *node);
ZIG_EXTERN_C void stage2_progress_complete_one(struct Stage2ProgressNode *node);
// ABI warning
ZIG_EXTERN_C void stage2_progress_update_node(Stage2ProgressNode *node,
ZIG_EXTERN_C void stage2_progress_update_node(struct Stage2ProgressNode *node,
size_t completed_count, size_t estimated_total_items);
// ABI warning

View File

@ -380,10 +380,6 @@ Error target_parse_abi(ZigLLVM_EnvironmentType *out_abi, const char *abi_ptr, si
return ErrorUnknownABI;
}
Error target_parse_triple(ZigTarget *target, const char *triple, const char *mcpu, const char *dynamic_linker) {
return stage2_target_parse(target, triple, mcpu, dynamic_linker);
}
const char *target_arch_name(ZigLLVM_ArchType arch) {
return ZigLLVMGetArchTypeName(arch);
}
@ -408,7 +404,7 @@ void target_triple_llvm(Buf *triple, const ZigTarget *target) {
buf_resize(triple, 0);
buf_appendf(triple, "%s-%s-%s-%s",
ZigLLVMGetArchTypeName(target->arch),
ZigLLVMGetVendorTypeName(target->vendor),
ZigLLVMGetVendorTypeName(ZigLLVM_UnknownVendor),
ZigLLVMGetOSTypeName(get_llvm_os_type(target->os)),
ZigLLVMGetEnvironmentTypeName(target->abi));
}
@ -1149,7 +1145,6 @@ void target_libc_enum(size_t index, ZigTarget *out_target) {
out_target->arch = libcs_available[index].arch;
out_target->os = libcs_available[index].os;
out_target->abi = libcs_available[index].abi;
out_target->vendor = ZigLLVM_UnknownVendor;
out_target->is_native_os = false;
out_target->is_native_cpu = false;
}

View File

@ -25,7 +25,6 @@ enum CIntType {
CIntTypeCount,
};
Error target_parse_triple(ZigTarget *target, const char *triple, const char *mcpu, const char *dynamic_linker);
Error target_parse_arch(ZigLLVM_ArchType *arch, const char *arch_ptr, size_t arch_len);
Error target_parse_os(Os *os, const char *os_ptr, size_t os_len);
Error target_parse_abi(ZigLLVM_EnvironmentType *abi, const char *abi_ptr, size_t abi_len);

View File

@ -14,6 +14,9 @@
#include "stage2.h"
#include "target.hpp"
#include "error.hpp"
#include "util.hpp"
#include "buffer.hpp"
#include "os.hpp"
#include <stdio.h>
#include <string.h>
@ -33,7 +36,6 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
" --output-dir [dir] override output directory (defaults to cwd)\n"
" --pkg-begin [name] [path] make pkg available to import and push current pkg\n"
" --pkg-end pop current pkg\n"
" --main-pkg-path set the directory of the root package\n"
" --release-fast build with optimizations on and safety off\n"
" --release-safe build with optimizations on and safety on\n"
" --release-small build with size optimizations on and safety off\n"
@ -53,6 +55,170 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
return return_code;
}
static Os get_zig_os_type(ZigLLVM_OSType os_type) {
switch (os_type) {
case ZigLLVM_UnknownOS:
return OsFreestanding;
case ZigLLVM_Ananas:
return OsAnanas;
case ZigLLVM_CloudABI:
return OsCloudABI;
case ZigLLVM_DragonFly:
return OsDragonFly;
case ZigLLVM_FreeBSD:
return OsFreeBSD;
case ZigLLVM_Fuchsia:
return OsFuchsia;
case ZigLLVM_IOS:
return OsIOS;
case ZigLLVM_KFreeBSD:
return OsKFreeBSD;
case ZigLLVM_Linux:
return OsLinux;
case ZigLLVM_Lv2:
return OsLv2;
case ZigLLVM_Darwin:
case ZigLLVM_MacOSX:
return OsMacOSX;
case ZigLLVM_NetBSD:
return OsNetBSD;
case ZigLLVM_OpenBSD:
return OsOpenBSD;
case ZigLLVM_Solaris:
return OsSolaris;
case ZigLLVM_Win32:
return OsWindows;
case ZigLLVM_Haiku:
return OsHaiku;
case ZigLLVM_Minix:
return OsMinix;
case ZigLLVM_RTEMS:
return OsRTEMS;
case ZigLLVM_NaCl:
return OsNaCl;
case ZigLLVM_CNK:
return OsCNK;
case ZigLLVM_AIX:
return OsAIX;
case ZigLLVM_CUDA:
return OsCUDA;
case ZigLLVM_NVCL:
return OsNVCL;
case ZigLLVM_AMDHSA:
return OsAMDHSA;
case ZigLLVM_PS4:
return OsPS4;
case ZigLLVM_ELFIAMCU:
return OsELFIAMCU;
case ZigLLVM_TvOS:
return OsTvOS;
case ZigLLVM_WatchOS:
return OsWatchOS;
case ZigLLVM_Mesa3D:
return OsMesa3D;
case ZigLLVM_Contiki:
return OsContiki;
case ZigLLVM_AMDPAL:
return OsAMDPAL;
case ZigLLVM_HermitCore:
return OsHermitCore;
case ZigLLVM_Hurd:
return OsHurd;
case ZigLLVM_WASI:
return OsWASI;
case ZigLLVM_Emscripten:
return OsEmscripten;
}
zig_unreachable();
}
static void get_native_target(ZigTarget *target) {
// first zero initialize
*target = {};
ZigLLVM_OSType os_type;
ZigLLVM_ObjectFormatType oformat; // ignored; based on arch/os
ZigLLVM_VendorType trash;
ZigLLVMGetNativeTarget(
&target->arch,
&trash,
&os_type,
&target->abi,
&oformat);
target->os = get_zig_os_type(os_type);
target->is_native_os = true;
target->is_native_cpu = true;
if (target->abi == ZigLLVM_UnknownEnvironment) {
target->abi = target_default_abi(target->arch, target->os);
}
}
static Error target_parse_triple(struct ZigTarget *target, const char *zig_triple, const char *mcpu,
const char *dynamic_linker)
{
Error err;
if (zig_triple != nullptr && strcmp(zig_triple, "native") == 0) {
zig_triple = nullptr;
}
if (zig_triple == nullptr) {
get_native_target(target);
if (mcpu == nullptr) {
target->llvm_cpu_name = ZigLLVMGetHostCPUName();
target->llvm_cpu_features = ZigLLVMGetNativeFeatures();
} else if (strcmp(mcpu, "baseline") == 0) {
target->is_native_os = false;
target->is_native_cpu = false;
target->llvm_cpu_name = "";
target->llvm_cpu_features = "";
} else {
const char *msg = "stage0 can't handle CPU/features in the target";
stage2_panic(msg, strlen(msg));
}
} else {
// first initialize all to zero
*target = {};
SplitIterator it = memSplit(str(zig_triple), str("-"));
Optional<Slice<uint8_t>> opt_archsub = SplitIterator_next(&it);
Optional<Slice<uint8_t>> opt_os = SplitIterator_next(&it);
Optional<Slice<uint8_t>> opt_abi = SplitIterator_next(&it);
if (!opt_archsub.is_some)
return ErrorMissingArchitecture;
if ((err = target_parse_arch(&target->arch, (char*)opt_archsub.value.ptr, opt_archsub.value.len))) {
return err;
}
if (!opt_os.is_some)
return ErrorMissingOperatingSystem;
if ((err = target_parse_os(&target->os, (char*)opt_os.value.ptr, opt_os.value.len))) {
return err;
}
if (opt_abi.is_some) {
if ((err = target_parse_abi(&target->abi, (char*)opt_abi.value.ptr, opt_abi.value.len))) {
return err;
}
} else {
target->abi = target_default_abi(target->arch, target->os);
}
if (mcpu != nullptr && strcmp(mcpu, "baseline") != 0) {
const char *msg = "stage0 can't handle CPU/features in the target";
stage2_panic(msg, strlen(msg));
}
}
return ErrorNone;
}
static bool str_starts_with(const char *s1, const char *s2) {
size_t s2_len = strlen(s2);
if (strlen(s1) < s2_len) {
@ -90,10 +256,9 @@ int main(int argc, char **argv) {
bool link_libcpp = false;
const char *target_string = nullptr;
ZigStage1Pkg *cur_pkg = heap::c_allocator.create<ZigStage1Pkg>();
BuildMode build_mode = BuildModeDebug;
BuildMode optimize_mode = BuildModeDebug;
TargetSubsystem subsystem = TargetSubsystemAuto;
const char *override_lib_dir = nullptr;
const char *main_pkg_path = nullptr;
const char *mcpu = nullptr;
for (int i = 1; i < argc; i += 1) {
@ -103,11 +268,11 @@ int main(int argc, char **argv) {
if (strcmp(arg, "--") == 0) {
fprintf(stderr, "Unexpected end-of-parameter mark: %s\n", arg);
} else if (strcmp(arg, "--release-fast") == 0) {
build_mode = BuildModeFastRelease;
optimize_mode = BuildModeFastRelease;
} else if (strcmp(arg, "--release-safe") == 0) {
build_mode = BuildModeSafeRelease;
optimize_mode = BuildModeSafeRelease;
} else if (strcmp(arg, "--release-small") == 0) {
build_mode = BuildModeSmallRelease;
optimize_mode = BuildModeSmallRelease;
} else if (strcmp(arg, "--help") == 0) {
return print_full_usage(arg0, stdout, EXIT_SUCCESS);
} else if (strcmp(arg, "--strip") == 0) {
@ -183,8 +348,6 @@ int main(int argc, char **argv) {
dynamic_linker = argv[i];
} else if (strcmp(arg, "--override-lib-dir") == 0) {
override_lib_dir = argv[i];
} else if (strcmp(arg, "--main-pkg-path") == 0) {
main_pkg_path = argv[i];
} else if (strcmp(arg, "--library") == 0 || strcmp(arg, "-l") == 0) {
if (strcmp(argv[i], "c") == 0) {
link_libc = true;
@ -264,12 +427,13 @@ int main(int argc, char **argv) {
return print_error_usage(arg0);
}
ZigStage1 *stage1 = zig_stage1_create(build_mode,
main_pkg_path, (main_pkg_path == nullptr) ? 0 : strlen(main_pkg_path),
ZigStage1 *stage1 = zig_stage1_create(optimize_mode,
nullptr, 0,
in_file, strlen(in_file),
override_lib_dir, strlen(override_lib_dir), &target, false,
root_progress_node);
override_lib_dir, strlen(override_lib_dir),
&target, false);
stage1->main_progress_node = root_progress_node;
stage1->root_name_ptr = out_name;
stage1->root_name_len = strlen(out_name);
stage1->strip = strip;
@ -295,3 +459,66 @@ int main(int argc, char **argv) {
return main_exit(root_progress_node, EXIT_SUCCESS);
}
void stage2_panic(const char *ptr, size_t len) {
fwrite(ptr, 1, len, stderr);
fprintf(stderr, "\n");
fflush(stderr);
abort();
}
struct Stage2Progress {
int trash;
};
struct Stage2ProgressNode {
int trash;
};
Stage2Progress *stage2_progress_create(void) {
return nullptr;
}
void stage2_progress_destroy(Stage2Progress *progress) {}
Stage2ProgressNode *stage2_progress_start_root(Stage2Progress *progress,
const char *name_ptr, size_t name_len, size_t estimated_total_items)
{
return nullptr;
}
Stage2ProgressNode *stage2_progress_start(Stage2ProgressNode *node,
const char *name_ptr, size_t name_len, size_t estimated_total_items)
{
return nullptr;
}
void stage2_progress_end(Stage2ProgressNode *node) {}
void stage2_progress_complete_one(Stage2ProgressNode *node) {}
void stage2_progress_disable_tty(Stage2Progress *progress) {}
void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){}
const char *stage2_fetch_file(struct ZigStage1 *stage1, const char *path_ptr, size_t path_len,
size_t *result_len)
{
Error err;
Buf contents_buf = BUF_INIT;
Buf path_buf = BUF_INIT;
buf_init_from_mem(&path_buf, path_ptr, path_len);
if ((err = os_fetch_file_path(&path_buf, &contents_buf))) {
return nullptr;
}
*result_len = buf_len(&contents_buf);
return buf_ptr(&contents_buf);
}
const char *stage2_cimport(struct ZigStage1 *stage1) {
const char *msg = "stage0 called stage2_cimport";
stage2_panic(msg, strlen(msg));
}
const char *stage2_add_link_lib(struct ZigStage1 *stage1,
const char *lib_name_ptr, size_t lib_name_len,
const char *symbol_name_ptr, size_t symbol_name_len)
{
return nullptr;
}