stage2: implement --show-builtin

This takes the place of `zig builtin`. This is an improvement over the
command because now the generated source will correctly show LinkMode
and OutputMode, whereas before it was always stuck as Static and Obj,
respectively.
master
Andrew Kelley 2020-09-17 23:27:24 -07:00
parent dc478687d9
commit a9b18023a4
11 changed files with 247 additions and 64 deletions

View File

@ -1,9 +1,5 @@
* `zig builtin`
* `zig translate-c`
* `zig test`
* `zig run`
* `zig init-lib`
* `zig init-exe`
* `zig build`
* `-ftime-report`
* -fstack-report print stack size diagnostics\n"
@ -15,14 +11,14 @@
* -femit-llvm-ir produce a .ll file with LLVM IR\n"
* -fno-emit-llvm-ir (default) do not produce a .ll file with LLVM IR\n"
* --cache-dir [path] override the local cache directory\n"
* move main.cpp to stage2
* make sure zig cc works
- 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
* build & link againstn freestanding libc
* 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
@ -41,6 +37,9 @@
* implement -fno-emit-bin
* audit the base cache hash
* audit the CLI options for stage2
* `zig init-lib`
* `zig init-exe`
* `zig run`
* implement serialization/deserialization of incremental compilation metadata
* incremental compilation - implement detection of which source files changed
@ -69,3 +68,6 @@
* rename src-self-hosted/ to src/
* improve Directory.join to only use 1 allocation in a clean way.
* tracy builds with lc++
* some kind of "zig identifier escape" function rather than unconditionally using @"" syntax
in builtin.zig
* rename Mode to OptimizeMode

View File

@ -29,7 +29,7 @@ c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{},
link_error_flags: link.File.ErrorFlags = .{},
work_queue: std.fifo.LinearFifo(WorkItem, .Dynamic),
work_queue: std.fifo.LinearFifo(Job, .Dynamic),
/// The ErrorMsg memory is owned by the `CObject`, using Compilation's general purpose allocator.
failed_c_objects: std.AutoArrayHashMapUnmanaged(*CObject, *ErrorMsg) = .{},
@ -43,8 +43,9 @@ sanitize_c: bool,
/// This is `true` for `zig cc`, `zig c++`, and `zig translate-c`.
clang_passthrough_mode: bool,
/// Whether to print clang argvs to stdout.
debug_cc: bool,
verbose_cc: bool,
disable_c_depfile: bool,
is_test: bool,
c_source_files: []const CSourceFile,
clang_argv: []const []const u8,
@ -56,16 +57,16 @@ zig_cache_directory: Directory,
libc_include_dir_list: []const []const u8,
rand: *std.rand.Random,
/// Populated when we build libc++.a. A WorkItem to build this is placed in the queue
/// Populated when we build libc++.a. A Job to build this is placed in the queue
/// and resolved before calling linker.flush().
libcxx_static_lib: ?[]const u8 = null,
/// Populated when we build libc++abi.a. A WorkItem to build this is placed in the queue
/// Populated when we build libc++abi.a. A Job to build this is placed in the queue
/// and resolved before calling linker.flush().
libcxxabi_static_lib: ?[]const u8 = null,
/// Populated when we build libunwind.a. A WorkItem to build this is placed in the queue
/// Populated when we build libunwind.a. A Job to build this is placed in the queue
/// and resolved before calling linker.flush().
libunwind_static_lib: ?CRTFile = null,
/// Populated when we build c.a. A WorkItem to build this is placed in the queue
/// Populated when we build c.a. A Job to build this is placed in the queue
/// and resolved before calling linker.flush().
libc_static_lib: ?[]const u8 = null,
@ -98,7 +99,7 @@ pub const CSourceFile = struct {
extra_flags: []const []const u8 = &[0][]const u8{},
};
const WorkItem = union(enum) {
const Job = union(enum) {
/// Write the machine code for a Decl to the output file.
codegen_decl: *Module.Decl,
/// The Decl needs to be analyzed and possibly export itself.
@ -116,8 +117,11 @@ const WorkItem = union(enum) {
glibc_crt_file: glibc.CRTFile,
/// all of the glibc shared objects
glibc_shared_objects,
/// libunwind.a, usually needed when linking libc
libunwind: void,
/// Generate builtin.zig source code and write it into the correct place.
generate_builtin_zig: void,
};
pub const CObject = struct {
@ -282,8 +286,9 @@ pub const InitOptions = struct {
linker_z_nodelete: bool = false,
linker_z_defs: bool = false,
clang_passthrough_mode: bool = false,
debug_cc: bool = false,
debug_link: bool = false,
verbose_cc: bool = false,
verbose_link: bool = false,
is_test: bool = false,
stack_size_override: ?u64 = null,
self_exe_path: ?[]const u8 = null,
version: ?std.builtin.Version = null,
@ -570,6 +575,11 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
break :blk link_artifact_directory;
};
const error_return_tracing = !options.strip and switch (options.optimize_mode) {
.Debug, .ReleaseSafe => true,
.ReleaseFast, .ReleaseSmall => false,
};
const bin_file = try link.File.openPath(gpa, .{
.directory = bin_directory,
.sub_path = emit_bin.basename,
@ -612,9 +622,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.valgrind = valgrind,
.stack_check = stack_check,
.single_threaded = single_threaded,
.debug_link = options.debug_link,
.verbose_link = options.verbose_link,
.machine_code_model = options.machine_code_model,
.dll_export_fns = dll_export_fns,
.error_return_tracing = error_return_tracing,
});
errdefer bin_file.destroy();
@ -624,7 +635,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,
.work_queue = std.fifo.LinearFifo(WorkItem, .Dynamic).init(gpa),
.work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),
.keep_source_files_loaded = options.keep_source_files_loaded,
.use_clang = use_clang,
.clang_argv = options.clang_argv,
@ -635,14 +646,19 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.sanitize_c = sanitize_c,
.rand = options.rand,
.clang_passthrough_mode = options.clang_passthrough_mode,
.debug_cc = options.debug_cc,
.verbose_cc = options.verbose_cc,
.disable_c_depfile = options.disable_c_depfile,
.owned_link_dir = owned_link_dir,
.is_test = options.is_test,
};
break :comp comp;
};
errdefer comp.destroy();
if (comp.bin_file.options.module) |mod| {
try comp.work_queue.writeItem(.{ .generate_builtin_zig = {} });
}
// Add a `CObject` for each `c_source_files`.
try comp.c_object_table.ensureCapacity(gpa, options.c_source_files.len);
for (options.c_source_files) |c_source_file| {
@ -659,7 +675,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
// If we need to build glibc for the target, add work items for it.
// We go through the work queue so that building can be done in parallel.
if (comp.wantBuildGLibCFromSource()) {
try comp.addBuildingGLibCWorkItems();
try comp.addBuildingGLibCJobs();
}
if (comp.wantBuildLibUnwindFromSource()) {
try comp.work_queue.writeItem(.{ .libunwind = {} });
@ -715,7 +731,7 @@ pub fn update(self: *Compilation) !void {
defer tracy.end();
// For compiling C objects, we rely on the cache hash system to avoid duplicating work.
// Add a WorkItem for each C object.
// Add a Job for each C object.
try self.work_queue.ensureUnusedCapacity(self.c_object_table.items().len);
for (self.c_object_table.items()) |entry| {
self.work_queue.writeItemAssumeCapacity(.{ .c_object = entry.key });
@ -974,6 +990,13 @@ pub fn performAllTheWork(self: *Compilation) error{OutOfMemory}!void {
fatal("unable to build libunwind: {}", .{@errorName(err)});
};
},
.generate_builtin_zig => {
// This Job is only queued up if there is a zig module.
self.updateBuiltinZigFile(self.bin_file.options.module.?) catch |err| {
// TODO Expose this as a normal compile error rather than crashing here.
fatal("unable to update builtin.zig file: {}", .{@errorName(err)});
};
},
};
}
@ -1057,7 +1080,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void {
try argv.append(c_object.src.src_path);
try argv.appendSlice(c_object.src.extra_flags);
if (comp.debug_cc) {
if (comp.verbose_cc) {
for (argv.items[0 .. argv.items.len - 1]) |arg| {
std.debug.print("{} ", .{arg});
}
@ -1616,8 +1639,8 @@ pub fn get_libc_crt_file(comp: *Compilation, arena: *Allocator, basename: []cons
return full_path;
}
fn addBuildingGLibCWorkItems(comp: *Compilation) !void {
try comp.work_queue.write(&[_]WorkItem{
fn addBuildingGLibCJobs(comp: *Compilation) !void {
try comp.work_queue.write(&[_]Job{
.{ .glibc_crt_file = .crti_o },
.{ .glibc_crt_file = .crtn_o },
.{ .glibc_crt_file = .scrt1_o },
@ -1646,3 +1669,163 @@ fn wantBuildLibUnwindFromSource(comp: *Compilation) bool {
return comp.bin_file.options.link_libc and is_exe_or_dyn_lib and
comp.bin_file.options.libc_installation == null;
}
fn updateBuiltinZigFile(comp: *Compilation, mod: *Module) !void {
const source = try comp.generateBuiltinZigSource();
defer comp.gpa.free(source);
try mod.zig_cache_artifact_directory.handle.writeFile("builtin.zig", source);
}
pub fn generateBuiltinZigSource(comp: *Compilation) ![]u8 {
var buffer = std.ArrayList(u8).init(comp.gpa);
defer buffer.deinit();
const target = comp.getTarget();
const generic_arch_name = target.cpu.arch.genericName();
@setEvalBranchQuota(4000);
try buffer.writer().print(
\\usingnamespace @import("std").builtin;
\\/// Deprecated
\\pub const arch = std.Target.current.cpu.arch;
\\/// Deprecated
\\pub const endian = std.Target.current.cpu.arch.endian();
\\pub const output_mode = OutputMode.{};
\\pub const link_mode = LinkMode.{};
\\pub const is_test = {};
\\pub const single_threaded = {};
\\pub const abi = Abi.{};
\\pub const cpu: Cpu = Cpu{{
\\ .arch = .{},
\\ .model = &Target.{}.cpu.{},
\\ .features = Target.{}.featureSet(&[_]Target.{}.Feature{{
\\
, .{
@tagName(comp.bin_file.options.output_mode),
@tagName(comp.bin_file.options.link_mode),
comp.is_test,
comp.bin_file.options.single_threaded,
@tagName(target.abi),
@tagName(target.cpu.arch),
generic_arch_name,
target.cpu.model.name,
generic_arch_name,
generic_arch_name,
});
for (target.cpu.arch.allFeaturesList()) |feature, index_usize| {
const index = @intCast(std.Target.Cpu.Feature.Set.Index, index_usize);
const is_enabled = target.cpu.features.isEnabled(index);
if (is_enabled) {
// TODO some kind of "zig identifier escape" function rather than
// unconditionally using @"" syntax
try buffer.appendSlice(" .@\"");
try buffer.appendSlice(feature.name);
try buffer.appendSlice("\",\n");
}
}
try buffer.writer().print(
\\ }}),
\\}};
\\pub const os = Os{{
\\ .tag = .{},
\\ .version_range = .{{
,
.{@tagName(target.os.tag)},
);
switch (target.os.getVersionRange()) {
.none => try buffer.appendSlice(" .none = {} }\n"),
.semver => |semver| try buffer.outStream().print(
\\ .semver = .{{
\\ .min = .{{
\\ .major = {},
\\ .minor = {},
\\ .patch = {},
\\ }},
\\ .max = .{{
\\ .major = {},
\\ .minor = {},
\\ .patch = {},
\\ }},
\\ }}}},
\\
, .{
semver.min.major,
semver.min.minor,
semver.min.patch,
semver.max.major,
semver.max.minor,
semver.max.patch,
}),
.linux => |linux| try buffer.outStream().print(
\\ .linux = .{{
\\ .range = .{{
\\ .min = .{{
\\ .major = {},
\\ .minor = {},
\\ .patch = {},
\\ }},
\\ .max = .{{
\\ .major = {},
\\ .minor = {},
\\ .patch = {},
\\ }},
\\ }},
\\ .glibc = .{{
\\ .major = {},
\\ .minor = {},
\\ .patch = {},
\\ }},
\\ }}}},
\\
, .{
linux.range.min.major,
linux.range.min.minor,
linux.range.min.patch,
linux.range.max.major,
linux.range.max.minor,
linux.range.max.patch,
linux.glibc.major,
linux.glibc.minor,
linux.glibc.patch,
}),
.windows => |windows| try buffer.outStream().print(
\\ .windows = .{{
\\ .min = {s},
\\ .max = {s},
\\ }}}},
\\
,
.{ windows.min, windows.max },
),
}
try buffer.appendSlice("};\n");
try buffer.writer().print(
\\pub const object_format = ObjectFormat.{};
\\pub const mode = Mode.{};
\\pub const link_libc = {};
\\pub const link_libcpp = {};
\\pub const have_error_return_tracing = {};
\\pub const valgrind_support = {};
\\pub const position_independent_code = {};
\\pub const strip_debug_info = {};
\\pub const code_model = CodeModel.{};
\\
, .{
@tagName(comp.bin_file.options.object_format),
@tagName(comp.bin_file.options.optimize_mode),
comp.bin_file.options.link_libc,
comp.bin_file.options.link_libcpp,
comp.bin_file.options.error_return_tracing,
comp.bin_file.options.valgrind,
comp.bin_file.options.pic,
comp.bin_file.options.strip,
@tagName(comp.bin_file.options.machine_code_model),
});
return buffer.toOwnedSlice();
}

View File

@ -711,8 +711,8 @@ fn build_crt_file(
.is_native_os = comp.bin_file.options.is_native_os,
.self_exe_path = comp.self_exe_path,
.c_source_files = c_source_files,
.debug_cc = comp.debug_cc,
.debug_link = comp.bin_file.options.debug_link,
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.bin_file.options.verbose_link,
.clang_passthrough_mode = comp.clang_passthrough_mode,
});
defer sub_compilation.destroy();
@ -987,8 +987,8 @@ fn buildSharedLib(
.strip = comp.bin_file.options.strip,
.is_native_os = false,
.self_exe_path = comp.self_exe_path,
.debug_cc = comp.debug_cc,
.debug_link = comp.bin_file.options.debug_link,
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.bin_file.options.verbose_link,
.clang_passthrough_mode = comp.clang_passthrough_mode,
.version = version,
.version_script = map_file_path,

View File

@ -107,8 +107,8 @@ pub fn buildStaticLib(comp: *Compilation) !void {
.is_native_os = comp.bin_file.options.is_native_os,
.self_exe_path = comp.self_exe_path,
.c_source_files = &c_source_files,
.debug_cc = comp.debug_cc,
.debug_link = comp.bin_file.options.debug_link,
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.bin_file.options.verbose_link,
.clang_passthrough_mode = comp.clang_passthrough_mode,
.link_libc = true,
});

View File

@ -61,8 +61,9 @@ pub const Options = struct {
valgrind: bool,
stack_check: bool,
single_threaded: bool,
debug_link: bool = false,
verbose_link: bool = false,
dll_export_fns: bool,
error_return_tracing: bool,
gc_sections: ?bool = null,
allow_shlib_undefined: ?bool = null,
linker_script: ?[]const u8 = null,
@ -441,7 +442,7 @@ pub const File = struct {
base.options.sub_path;
const full_out_path_z = try arena.dupeZ(u8, full_out_path);
if (base.options.debug_link) {
if (base.options.verbose_link) {
std.debug.print("ar rcs {}", .{full_out_path_z});
for (object_files.items) |arg| {
std.debug.print(" {}", .{arg});

View File

@ -1569,7 +1569,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
try argv.append("-Bsymbolic");
}
if (self.base.options.debug_link) {
if (self.base.options.verbose_link) {
for (argv.items[0 .. argv.items.len - 1]) |arg| {
std.debug.print("{} ", .{arg});
}

View File

@ -179,6 +179,7 @@ const usage_build_generic =
\\ --color [auto|off|on] Enable or disable colored error messages
\\ -femit-bin[=path] (default) output machine code
\\ -fno-emit-bin Do not output machine code
\\ --show-builtin Output the source of @import("builtin") then exit
\\
\\Compile Options:
\\ -target [name] <arch><sub>-<os>-<abi> see the targets command
@ -233,8 +234,8 @@ const usage_build_generic =
\\
\\Debug Options (Zig Compiler Development):
\\ -ftime-report Print timing diagnostics
\\ --debug-link Verbose linker invocation
\\ --debug-cc Verbose C compiler invocation
\\ --verbose-link Display linker invocations
\\ --verbose-cc Display C compiler invocations
\\
;
@ -274,9 +275,10 @@ pub fn buildOutputType(
var strip = false;
var single_threaded = false;
var watch = false;
var debug_link = false;
var debug_cc = false;
var verbose_link = false;
var verbose_cc = false;
var time_report = false;
var show_builtin = false;
var emit_bin: Emit = .yes_default_path;
var emit_zir: Emit = .no;
var target_arch_os_abi: []const u8 = "native";
@ -531,6 +533,8 @@ pub fn buildOutputType(
dll_export_fns = true;
} else if (mem.eql(u8, arg, "-fno-dll-export-fns")) {
dll_export_fns = false;
} else if (mem.eql(u8, arg, "--show-builtin")) {
show_builtin = true;
} else if (mem.eql(u8, arg, "--strip")) {
strip = true;
} else if (mem.eql(u8, arg, "--single-threaded")) {
@ -539,10 +543,10 @@ pub fn buildOutputType(
link_eh_frame_hdr = true;
} else if (mem.eql(u8, arg, "-Bsymbolic")) {
linker_bind_global_refs_locally = true;
} else if (mem.eql(u8, arg, "--debug-link")) {
debug_link = true;
} else if (mem.eql(u8, arg, "--debug-cc")) {
debug_cc = true;
} else if (mem.eql(u8, arg, "--verbose-link")) {
verbose_link = true;
} else if (mem.eql(u8, arg, "--verbose-cc")) {
verbose_cc = true;
} else if (mem.startsWith(u8, arg, "-T")) {
linker_script = arg[2..];
} else if (mem.startsWith(u8, arg, "-L")) {
@ -680,8 +684,8 @@ pub fn buildOutputType(
},
.linker_script => linker_script = it.only_arg,
.verbose_cmds => {
debug_cc = true;
debug_link = true;
verbose_cc = true;
verbose_link = true;
},
.for_linker => try linker_args.append(it.only_arg),
.linker_input_z => {
@ -873,6 +877,8 @@ pub fn buildOutputType(
} else if (emit_bin == .yes) {
const basename = fs.path.basename(emit_bin.yes);
break :blk mem.split(basename, ".").next().?;
} else if (show_builtin) {
break :blk "builtin";
} else {
fatal("--name [name] not provided and unable to infer", .{});
}
@ -1160,17 +1166,20 @@ pub fn buildOutputType(
.clang_passthrough_mode = arg_mode != .build,
.version = if (have_version) version else null,
.libc_installation = if (libc_installation) |*lci| lci else null,
.debug_cc = debug_cc,
.debug_link = debug_link,
.verbose_cc = verbose_cc,
.verbose_link = verbose_link,
.machine_code_model = machine_code_model,
}) catch |err| {
fatal("unable to create compilation: {}", .{@errorName(err)});
};
defer comp.destroy();
const stdin = std.io.getStdIn().inStream();
const stderr = std.io.getStdErr().outStream();
var repl_buf: [1024]u8 = undefined;
if (show_builtin) {
const source = try comp.generateBuiltinZigSource();
defer comp.gpa.free(source);
try std.io.getStdOut().writeAll(source);
return;
}
try updateModule(gpa, comp, zir_out_path);
@ -1179,6 +1188,10 @@ pub fn buildOutputType(
fatal("TODO: implement `zig cc` when using it as a preprocessor", .{});
}
const stdin = std.io.getStdIn().inStream();
const stderr = std.io.getStdErr().outStream();
var repl_buf: [1024]u8 = undefined;
while (watch) {
try stderr.print("🦎 ", .{});
if (output_mode == .Exe) {

View File

@ -2161,11 +2161,9 @@ struct CodeGen {
bool have_err_ret_tracing;
bool verbose_tokenize;
bool verbose_ast;
bool verbose_link;
bool verbose_ir;
bool verbose_llvm_ir;
bool verbose_cimport;
bool verbose_cc;
bool verbose_llvm_cpu_features;
bool error_during_imports;
bool generate_error_name_table;

View File

@ -104,11 +104,9 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {
g->verbose_tokenize = stage1->verbose_tokenize;
g->verbose_ast = stage1->verbose_ast;
g->verbose_link = stage1->verbose_link;
g->verbose_ir = stage1->verbose_ir;
g->verbose_llvm_ir = stage1->verbose_llvm_ir;
g->verbose_cimport = stage1->verbose_cimport;
g->verbose_cc = stage1->verbose_cc;
g->verbose_llvm_cpu_features = stage1->verbose_llvm_cpu_features;
g->err_color = stage1->err_color;

View File

@ -194,11 +194,9 @@ struct ZigStage1 {
bool test_is_evented;
bool verbose_tokenize;
bool verbose_ast;
bool verbose_link;
bool verbose_ir;
bool verbose_llvm_ir;
bool verbose_cimport;
bool verbose_cc;
bool verbose_llvm_cpu_features;
};

View File

@ -44,11 +44,9 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
" -mcpu [cpu] specify target CPU and feature set\n"
" --verbose-tokenize enable compiler debug output for tokenization\n"
" --verbose-ast enable compiler debug output for AST parsing\n"
" --verbose-link enable compiler debug output for linking\n"
" --verbose-ir enable compiler debug output for Zig IR\n"
" --verbose-llvm-ir enable compiler debug output for LLVM IR\n"
" --verbose-cimport enable compiler debug output for C imports\n"
" --verbose-cc enable compiler debug output for C compilation\n"
" --verbose-llvm-cpu-features enable compiler debug output for LLVM CPU features\n"
"\n"
, arg0);
@ -82,11 +80,9 @@ int main(int argc, char **argv) {
const char *out_name = nullptr;
bool verbose_tokenize = false;
bool verbose_ast = false;
bool verbose_link = false;
bool verbose_ir = false;
bool verbose_llvm_ir = false;
bool verbose_cimport = false;
bool verbose_cc = false;
bool verbose_llvm_cpu_features = false;
ErrColor color = ErrColorAuto;
const char *dynamic_linker = nullptr;
@ -120,16 +116,12 @@ int main(int argc, char **argv) {
verbose_tokenize = true;
} else if (strcmp(arg, "--verbose-ast") == 0) {
verbose_ast = true;
} else if (strcmp(arg, "--verbose-link") == 0) {
verbose_link = true;
} else if (strcmp(arg, "--verbose-ir") == 0) {
verbose_ir = true;
} else if (strcmp(arg, "--verbose-llvm-ir") == 0) {
verbose_llvm_ir = true;
} else if (strcmp(arg, "--verbose-cimport") == 0) {
verbose_cimport = true;
} else if (strcmp(arg, "--verbose-cc") == 0) {
verbose_cc = true;
} else if (strcmp(arg, "--verbose-llvm-cpu-features") == 0) {
verbose_llvm_cpu_features = true;
} else if (arg[1] == 'l' && arg[2] != 0) {
@ -283,11 +275,9 @@ int main(int argc, char **argv) {
stage1->strip = strip;
stage1->verbose_tokenize = verbose_tokenize;
stage1->verbose_ast = verbose_ast;
stage1->verbose_link = verbose_link;
stage1->verbose_ir = verbose_ir;
stage1->verbose_llvm_ir = verbose_llvm_ir;
stage1->verbose_cimport = verbose_cimport;
stage1->verbose_cc = verbose_cc;
stage1->verbose_llvm_cpu_features = verbose_llvm_cpu_features;
stage1->output_dir_ptr = output_dir;
stage1->output_dir_len = strlen(output_dir);