Commit 6af2990549
Changed files (12)
src/stage1/all_types.hpp
@@ -2116,12 +2116,12 @@ struct CodeGen {
Buf llvm_triple_str;
Buf global_asm;
Buf o_file_output_path;
+ Buf h_file_output_path;
Buf asm_file_output_path;
Buf llvm_ir_file_output_path;
+ Buf analysis_json_output_path;
+ Buf docs_output_path;
Buf *cache_dir;
- // As an input parameter, mutually exclusive with enable_cache. But it gets
- // populated in codegen_build_and_link.
- Buf *output_dir;
Buf *c_artifact_dir;
const char **libc_include_dir_list;
size_t libc_include_dir_len;
@@ -2186,11 +2186,6 @@ struct CodeGen {
bool dll_export_fns;
bool have_stack_probing;
bool function_sections;
- bool enable_dump_analysis;
- bool enable_doc_generation;
- bool emit_bin;
- bool emit_asm;
- bool emit_llvm_ir;
bool test_is_evented;
bool valgrind_enabled;
src/stage1/codegen.cpp
@@ -8243,9 +8243,9 @@ static void zig_llvm_emit_output(CodeGen *g) {
const char *bin_filename = nullptr;
const char *llvm_ir_filename = nullptr;
- if (g->emit_bin) bin_filename = buf_ptr(&g->o_file_output_path);
- if (g->emit_asm) asm_filename = buf_ptr(&g->asm_file_output_path);
- if (g->emit_llvm_ir) llvm_ir_filename = buf_ptr(&g->llvm_ir_file_output_path);
+ if (buf_len(&g->o_file_output_path) != 0) bin_filename = buf_ptr(&g->o_file_output_path);
+ if (buf_len(&g->asm_file_output_path) != 0) asm_filename = buf_ptr(&g->asm_file_output_path);
+ if (buf_len(&g->llvm_ir_file_output_path) != 0) llvm_ir_filename = buf_ptr(&g->llvm_ir_file_output_path);
// Unfortunately, LLVM shits the bed when we ask for both binary and assembly. So we call the entire
// pipeline multiple times if this is requested.
@@ -8858,8 +8858,10 @@ static Error define_builtin_compile_vars(CodeGen *g) {
Buf *contents;
if (g->builtin_zig_path == nullptr) {
// Then this is zig0 building stage2. We can make many assumptions about the compilation.
+ Buf *out_dir = buf_alloc();
+ os_path_split(&g->o_file_output_path, out_dir, nullptr);
g->builtin_zig_path = buf_alloc();
- os_path_join(g->output_dir, buf_create_from_str(builtin_zig_basename), g->builtin_zig_path);
+ os_path_join(out_dir, buf_create_from_str(builtin_zig_basename), g->builtin_zig_path);
Buf *resolve_paths[] = { g->builtin_zig_path, };
*g->builtin_zig_path = os_path_resolve(resolve_paths, 1);
@@ -8870,7 +8872,7 @@ static Error define_builtin_compile_vars(CodeGen *g) {
exit(1);
}
- g->compile_var_package = new_package(buf_ptr(g->output_dir), builtin_zig_basename, "builtin");
+ g->compile_var_package = new_package(buf_ptr(out_dir), builtin_zig_basename, "builtin");
} else {
Buf *resolve_paths[] = { g->builtin_zig_path, };
*g->builtin_zig_path = os_path_resolve(resolve_paths, 1);
@@ -9232,33 +9234,20 @@ void codegen_add_time_event(CodeGen *g, const char *name) {
g->timing_events.append({seconds, name});
}
-static void resolve_out_paths(CodeGen *g) {
- assert(g->output_dir != nullptr);
- assert(g->root_out_name != nullptr);
+void codegen_build_object(CodeGen *g) {
+ g->have_err_ret_tracing = detect_err_ret_tracing(g);
- if (g->emit_bin) {
- Buf *o_basename = buf_create_from_buf(g->root_out_name);
- buf_append_str(o_basename, target_o_file_ext(g->zig_target));
- os_path_join(g->output_dir, o_basename, &g->o_file_output_path);
- }
- if (g->emit_asm) {
- Buf *asm_basename = buf_create_from_buf(g->root_out_name);
- const char *asm_ext = target_asm_file_ext(g->zig_target);
- buf_append_str(asm_basename, asm_ext);
- os_path_join(g->output_dir, asm_basename, &g->asm_file_output_path);
- }
- if (g->emit_llvm_ir) {
- Buf *llvm_ir_basename = buf_create_from_buf(g->root_out_name);
- const char *llvm_ir_ext = target_llvm_ir_file_ext(g->zig_target);
- buf_append_str(llvm_ir_basename, llvm_ir_ext);
- os_path_join(g->output_dir, llvm_ir_basename, &g->llvm_ir_file_output_path);
- }
-}
+ init(g);
+
+ codegen_add_time_event(g, "Semantic Analysis");
+ const char *progress_name = "Semantic Analysis";
+ codegen_switch_sub_prog_node(g, stage2_progress_start(g->main_progress_node,
+ progress_name, strlen(progress_name), 0));
-static void output_type_information(CodeGen *g) {
- if (g->enable_dump_analysis) {
- const char *analysis_json_filename = buf_ptr(buf_sprintf("%s" OS_SEP "%s-analysis.json",
- buf_ptr(g->output_dir), buf_ptr(g->root_out_name)));
+ gen_root_source(g);
+
+ if (buf_len(&g->analysis_json_output_path) != 0) {
+ const char *analysis_json_filename = buf_ptr(&g->analysis_json_output_path);
FILE *f = fopen(analysis_json_filename, "wb");
if (f == nullptr) {
fprintf(stderr, "Unable to open '%s': %s\n", analysis_json_filename, strerror(errno));
@@ -9270,9 +9259,9 @@ static void output_type_information(CodeGen *g) {
exit(1);
}
}
- if (g->enable_doc_generation) {
+ if (buf_len(&g->docs_output_path) != 0) {
Error err;
- Buf *doc_dir_path = buf_sprintf("%s" OS_SEP "docs", buf_ptr(g->output_dir));
+ Buf *doc_dir_path = &g->docs_output_path;
if ((err = os_make_path(doc_dir_path))) {
fprintf(stderr, "Unable to create directory %s: %s\n", buf_ptr(doc_dir_path), err_str(err));
exit(1);
@@ -9308,27 +9297,6 @@ static void output_type_information(CodeGen *g) {
exit(1);
}
}
-}
-
-void codegen_build_object(CodeGen *g) {
- assert(g->output_dir != nullptr);
-
- g->have_err_ret_tracing = detect_err_ret_tracing(g);
-
- init(g);
-
- codegen_add_time_event(g, "Semantic Analysis");
- const char *progress_name = "Semantic Analysis";
- codegen_switch_sub_prog_node(g, stage2_progress_start(g->main_progress_node,
- progress_name, strlen(progress_name), 0));
-
- gen_root_source(g);
-
- resolve_out_paths(g);
-
- if (g->enable_dump_analysis || g->enable_doc_generation) {
- output_type_information(g);
- }
codegen_add_time_event(g, "Code Generation");
{
@@ -9379,7 +9347,6 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget
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->subsystem = TargetSubsystemAuto;
src/stage1/stage1.cpp
@@ -69,7 +69,13 @@ 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->output_dir = buf_create_from_mem(stage1->output_dir_ptr, stage1->output_dir_len);
+ buf_init_from_mem(&g->o_file_output_path, stage1->emit_o_ptr, stage1->emit_o_len);
+ buf_init_from_mem(&g->h_file_output_path, stage1->emit_h_ptr, stage1->emit_h_len);
+ buf_init_from_mem(&g->asm_file_output_path, stage1->emit_asm_ptr, stage1->emit_asm_len);
+ buf_init_from_mem(&g->llvm_ir_file_output_path, stage1->emit_llvm_ir_ptr, stage1->emit_llvm_ir_len);
+ buf_init_from_mem(&g->analysis_json_output_path, stage1->emit_analysis_json_ptr, stage1->emit_analysis_json_len);
+ buf_init_from_mem(&g->docs_output_path, stage1->emit_docs_ptr, stage1->emit_docs_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);
}
@@ -94,11 +100,6 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {
g->enable_time_report = stage1->enable_time_report;
g->enable_stack_report = stage1->enable_stack_report;
- g->enable_dump_analysis = stage1->dump_analysis;
- g->enable_doc_generation = stage1->enable_doc_generation;
- g->emit_bin = stage1->emit_bin;
- g->emit_asm = stage1->emit_asm;
- g->emit_llvm_ir = stage1->emit_llvm_ir;
g->test_is_evented = stage1->test_is_evented;
g->verbose_tokenize = stage1->verbose_tokenize;
src/stage1/stage1.h
@@ -141,8 +141,23 @@ struct ZigStage1 {
const char *root_name_ptr;
size_t root_name_len;
- const char *output_dir_ptr;
- size_t output_dir_len;
+ const char *emit_o_ptr;
+ size_t emit_o_len;
+
+ const char *emit_h_ptr;
+ size_t emit_h_len;
+
+ const char *emit_asm_ptr;
+ size_t emit_asm_len;
+
+ const char *emit_llvm_ir_ptr;
+ size_t emit_llvm_ir_len;
+
+ const char *emit_analysis_json_ptr;
+ size_t emit_analysis_json_len;
+
+ const char *emit_docs_ptr;
+ size_t emit_docs_len;
const char *builtin_zig_path_ptr;
size_t builtin_zig_path_len;
@@ -173,11 +188,6 @@ struct ZigStage1 {
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;
src/stage1/zig0.cpp
@@ -241,7 +241,7 @@ int main(int argc, char **argv) {
Error err;
const char *in_file = nullptr;
- const char *output_dir = nullptr;
+ const char *emit_bin_path = nullptr;
bool strip = false;
const char *out_name = nullptr;
bool verbose_tokenize = false;
@@ -324,14 +324,14 @@ int main(int argc, char **argv) {
cur_pkg = cur_pkg->parent;
} else if (str_starts_with(arg, "-mcpu=")) {
mcpu = arg + strlen("-mcpu=");
+ } else if (str_starts_with(arg, "-femit-bin=")) {
+ emit_bin_path = arg + strlen("-femit-bin=");
} else if (i + 1 >= argc) {
fprintf(stderr, "Expected another argument after %s\n", arg);
return print_error_usage(arg0);
} else {
i += 1;
- if (strcmp(arg, "--output-dir") == 0) {
- output_dir = argv[i];
- } else if (strcmp(arg, "--color") == 0) {
+ if (strcmp(arg, "--color") == 0) {
if (strcmp(argv[i], "auto") == 0) {
color = ErrColorAuto;
} else if (strcmp(argv[i], "on") == 0) {
@@ -443,15 +443,14 @@ int main(int argc, char **argv) {
stage1->verbose_llvm_ir = verbose_llvm_ir;
stage1->verbose_cimport = verbose_cimport;
stage1->verbose_llvm_cpu_features = verbose_llvm_cpu_features;
- stage1->output_dir_ptr = output_dir;
- stage1->output_dir_len = strlen(output_dir);
+ stage1->emit_o_ptr = emit_bin_path;
+ stage1->emit_o_len = strlen(emit_bin_path);
stage1->root_pkg = cur_pkg;
stage1->err_color = color;
stage1->link_libc = link_libc;
stage1->link_libcpp = link_libcpp;
stage1->subsystem = subsystem;
stage1->pic = true;
- stage1->emit_bin = true;
zig_stage1_build_object(stage1);
src/Compilation.zig
@@ -107,6 +107,12 @@ test_filter: ?[]const u8,
test_name_prefix: ?[]const u8,
test_evented_io: bool,
+emit_h: ?EmitLoc,
+emit_asm: ?EmitLoc,
+emit_llvm_ir: ?EmitLoc,
+emit_analysis: ?EmitLoc,
+emit_docs: ?EmitLoc,
+
pub const InnerError = Module.InnerError;
pub const CRTFile = struct {
@@ -296,6 +302,12 @@ pub const InitOptions = struct {
emit_h: ?EmitLoc = null,
/// `null` means to not emit assembly.
emit_asm: ?EmitLoc = null,
+ /// `null` means to not emit LLVM IR.
+ emit_llvm_ir: ?EmitLoc = null,
+ /// `null` means to not emit semantic analysis JSON.
+ emit_analysis: ?EmitLoc = null,
+ /// `null` means to not emit docs.
+ emit_docs: ?EmitLoc = null,
link_mode: ?std.builtin.LinkMode = null,
dll_export_fns: ?bool = false,
/// Normally when using LLD to link, Zig uses a file named "lld.id" in the
@@ -442,7 +454,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
break :blk false;
};
-
const link_libc = options.link_libc or
(is_exe_or_dyn_lib and target_util.osRequiresLibC(options.target));
@@ -489,9 +500,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
break :pic explicit;
} else must_pic;
- if (options.emit_h != null) fatal("-femit-h not supported yet", .{}); // TODO
- if (options.emit_asm != null) fatal("-femit-asm not supported yet", .{}); // TODO
-
const emit_bin = options.emit_bin orelse fatal("-fno-emit-bin not supported yet", .{}); // TODO
// Make a decision on whether to use Clang for translate-c and compiling C files.
@@ -579,6 +587,12 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
cache.hash.add(options.link_libcpp);
cache.hash.add(options.output_mode);
cache.hash.add(options.machine_code_model);
+ cache.hash.add(options.emit_bin != null);
+ cache.hash.add(options.emit_h != null);
+ cache.hash.add(options.emit_asm != null);
+ cache.hash.add(options.emit_llvm_ir != null);
+ cache.hash.add(options.emit_analysis != null);
+ cache.hash.add(options.emit_docs != null);
// TODO audit this and make sure everything is in it
const module: ?*Module = if (options.root_pkg) |root_pkg| blk: {
@@ -752,6 +766,11 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.local_cache_directory = options.local_cache_directory,
.global_cache_directory = options.global_cache_directory,
.bin_file = bin_file,
+ .emit_h = options.emit_h,
+ .emit_asm = options.emit_asm,
+ .emit_llvm_ir = options.emit_llvm_ir,
+ .emit_analysis = options.emit_analysis,
+ .emit_docs = options.emit_docs,
.work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),
.keep_source_files_loaded = options.keep_source_files_loaded,
.use_clang = use_clang,
@@ -1450,8 +1469,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void {
try argv.ensureCapacity(argv.items.len + 3);
switch (comp.clang_preprocessor_mode) {
- .no => argv.appendSliceAssumeCapacity(&[_][]const u8{"-c", "-o", out_obj_path}),
- .yes => argv.appendSliceAssumeCapacity(&[_][]const u8{"-E", "-o", out_obj_path}),
+ .no => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-c", "-o", out_obj_path }),
+ .yes => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-E", "-o", out_obj_path }),
.stdout => argv.appendAssumeCapacity("-E"),
}
@@ -2498,15 +2517,35 @@ fn updateStage1Module(comp: *Compilation) !void {
comp.is_test,
) orelse return error.OutOfMemory;
+ const bin_basename = try std.zig.binNameAlloc(arena, .{
+ .root_name = comp.bin_file.options.root_name,
+ .target = target,
+ .output_mode = .Obj,
+ });
+ const emit_bin_path = try directory.join(arena, &[_][]const u8{bin_basename});
+ const emit_h_path = try stage1LocPath(arena, comp.emit_h, directory);
+ const emit_asm_path = try stage1LocPath(arena, comp.emit_asm, directory);
+ const emit_llvm_ir_path = try stage1LocPath(arena, comp.emit_llvm_ir, directory);
+ const emit_analysis_path = try stage1LocPath(arena, comp.emit_analysis, directory);
+ const emit_docs_path = try stage1LocPath(arena, comp.emit_docs, directory);
const stage1_pkg = try createStage1Pkg(arena, "root", mod.root_pkg, null);
- const output_dir = directory.path orelse ".";
const test_filter = comp.test_filter orelse ""[0..0];
const test_name_prefix = comp.test_name_prefix orelse ""[0..0];
stage1_module.* = .{
.root_name_ptr = comp.bin_file.options.root_name.ptr,
.root_name_len = comp.bin_file.options.root_name.len,
- .output_dir_ptr = output_dir.ptr,
- .output_dir_len = output_dir.len,
+ .emit_o_ptr = emit_bin_path.ptr,
+ .emit_o_len = emit_bin_path.len,
+ .emit_h_ptr = emit_h_path.ptr,
+ .emit_h_len = emit_h_path.len,
+ .emit_asm_ptr = emit_asm_path.ptr,
+ .emit_asm_len = emit_asm_path.len,
+ .emit_llvm_ir_ptr = emit_llvm_ir_path.ptr,
+ .emit_llvm_ir_len = emit_llvm_ir_path.len,
+ .emit_analysis_json_ptr = emit_analysis_path.ptr,
+ .emit_analysis_json_len = emit_analysis_path.len,
+ .emit_docs_ptr = emit_docs_path.ptr,
+ .emit_docs_len = emit_docs_path.len,
.builtin_zig_path_ptr = builtin_zig_path.ptr,
.builtin_zig_path_len = builtin_zig_path.len,
.test_filter_ptr = test_filter.ptr,
@@ -2530,11 +2569,6 @@ fn updateStage1Module(comp: *Compilation) !void {
.enable_stack_probing = comp.bin_file.options.stack_check,
.enable_time_report = comp.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 = comp.test_evented_io,
.verbose_tokenize = comp.verbose_tokenize,
.verbose_ast = comp.verbose_ast,
@@ -2565,6 +2599,12 @@ fn updateStage1Module(comp: *Compilation) !void {
comp.stage1_lock = man.toOwnedLock();
}
+fn stage1LocPath(arena: *Allocator, opt_loc: ?EmitLoc, cache_directory: Directory) ![]const u8 {
+ const loc = opt_loc orelse return "";
+ const directory = loc.directory orelse cache_directory;
+ return directory.join(arena, &[_][]const u8{loc.basename});
+}
+
fn createStage1Pkg(
arena: *Allocator,
name: []const u8,
src/llvm.zig
@@ -72,3 +72,6 @@ pub const OSType = extern enum(c_int) {
WASI = 34,
Emscripten = 35,
};
+
+pub const ParseCommandLineOptions = ZigLLVMParseCommandLineOptions;
+extern fn ZigLLVMParseCommandLineOptions(argc: usize, argv: [*]const [*:0]const u8) void;
src/main.zig
@@ -195,8 +195,20 @@ const usage_build_generic =
\\ -h, --help Print this help and exit
\\ --watch Enable compiler REPL
\\ --color [auto|off|on] Enable or disable colored error messages
- \\ -femit-bin[=path] (default) output machine code
+ \\ -femit-bin[=path] (default) Output machine code
\\ -fno-emit-bin Do not output machine code
+ \\ -femit-asm[=path] Output .s (assembly code)
+ \\ -fno-emit-asm (default) Do not output .s (assembly code)
+ \\ -femit-zir[=path] Produce a .zir file with Zig IR
+ \\ -fno-emit-zir (default) Do not produce a .zir file with Zig IR
+ \\ -femit-llvm-ir[=path] Produce a .ll file with LLVM IR (requires LLVM extensions)
+ \\ -fno-emit-llvm-ir (default) Do not produce a .ll file with LLVM IR
+ \\ -femit-h[=path] Generate a C header file (.h)
+ \\ -fno-emit-h (default) Do not generate a C header file (.h)
+ \\ -femit-docs[=path] Create a docs/ dir with html documentation
+ \\ -fno-emit-docs (default) Do not produce docs/ dir with html documentation
+ \\ -femit-analysis[=path] Write analysis JSON file with type information
+ \\ -fno-emit-analysis (default) Do not write analysis JSON file with type information
\\ --show-builtin Output the source of @import("builtin") then exit
\\ --cache-dir [path] Override the local cache directory
\\ --global-cache-dir [path] Override the global cache directory
@@ -210,10 +222,11 @@ const usage_build_generic =
\\ small|kernel|
\\ medium|large]
\\ --name [name] Override root name (not a file path)
- \\ -ODebug (default) optimizations off, safety on
- \\ -OReleaseFast Optimizations on, safety off
- \\ -OReleaseSafe Optimizations on, safety on
- \\ -OReleaseSmall Optimize for small binary, safety off
+ \\ -O [mode] Choose what to optimize for
+ \\ Debug (default) Optimizations off, safety on
+ \\ ReleaseFast Optimizations on, safety off
+ \\ ReleaseSafe Optimizations on, safety on
+ \\ ReleaseSmall Optimize for small binary, safety off
\\ --pkg-begin [name] [path] Make pkg available to import and push current pkg
\\ --pkg-end Pop current pkg
\\ --main-pkg-path Set the directory of the root package
@@ -290,9 +303,57 @@ const Emit = union(enum) {
no,
yes_default_path,
yes: []const u8,
+
+ const Resolved = struct {
+ data: ?Compilation.EmitLoc,
+ dir: ?fs.Dir,
+
+ fn deinit(self: *Resolved) void {
+ if (self.dir) |*dir| {
+ dir.close();
+ }
+ }
+ };
+
+ fn resolve(emit: Emit, default_basename: []const u8) !Resolved {
+ var resolved: Resolved = .{ .data = null, .dir = null };
+ errdefer resolved.deinit();
+
+ switch (emit) {
+ .no => {},
+ .yes_default_path => {
+ resolved.data = Compilation.EmitLoc{
+ .directory = .{ .path = null, .handle = fs.cwd() },
+ .basename = default_basename,
+ };
+ },
+ .yes => |full_path| {
+ const basename = fs.path.basename(full_path);
+ if (fs.path.dirname(full_path)) |dirname| {
+ const handle = try fs.cwd().openDir(dirname, .{});
+ resolved = .{
+ .dir = handle,
+ .data = Compilation.EmitLoc{
+ .basename = basename,
+ .directory = .{
+ .path = dirname,
+ .handle = handle,
+ },
+ },
+ };
+ } else {
+ resolved.data = Compilation.EmitLoc{
+ .basename = basename,
+ .directory = .{ .path = null, .handle = fs.cwd() },
+ };
+ }
+ },
+ }
+ return resolved;
+ }
};
-pub fn buildOutputType(
+fn buildOutputType(
gpa: *Allocator,
arena: *Allocator,
all_args: []const []const u8,
@@ -328,7 +389,10 @@ pub fn buildOutputType(
var show_builtin = false;
var emit_bin: Emit = .yes_default_path;
var emit_asm: Emit = .no;
+ var emit_llvm_ir: Emit = .no;
var emit_zir: Emit = .no;
+ var emit_docs: Emit = .no;
+ var emit_analysis: Emit = .no;
var target_arch_os_abi: []const u8 = "native";
var target_mcpu: ?[]const u8 = null;
var target_dynamic_linker: ?[]const u8 = null;
@@ -667,6 +731,30 @@ pub fn buildOutputType(
emit_h = .{ .yes = arg["-femit-h=".len..] };
} else if (mem.eql(u8, arg, "-fno-emit-h")) {
emit_h = .no;
+ } else if (mem.eql(u8, arg, "-femit-asm")) {
+ emit_asm = .yes_default_path;
+ } else if (mem.startsWith(u8, arg, "-femit-asm=")) {
+ emit_asm = .{ .yes = arg["-femit-asm=".len..] };
+ } else if (mem.eql(u8, arg, "-fno-emit-asm")) {
+ emit_asm = .no;
+ } else if (mem.eql(u8, arg, "-femit-llvm-ir")) {
+ emit_llvm_ir = .yes_default_path;
+ } else if (mem.startsWith(u8, arg, "-femit-llvm-ir=")) {
+ emit_llvm_ir = .{ .yes = arg["-femit-llvm-ir=".len..] };
+ } else if (mem.eql(u8, arg, "-fno-emit-llvm-ir")) {
+ emit_llvm_ir = .no;
+ } else if (mem.eql(u8, arg, "-femit-docs")) {
+ emit_docs = .yes_default_path;
+ } else if (mem.startsWith(u8, arg, "-femit-docs=")) {
+ emit_docs = .{ .yes = arg["-femit-docs=".len..] };
+ } else if (mem.eql(u8, arg, "-fno-emit-docs")) {
+ emit_docs = .no;
+ } else if (mem.eql(u8, arg, "-femit-analysis")) {
+ emit_analysis = .yes_default_path;
+ } else if (mem.startsWith(u8, arg, "-femit-analysis=")) {
+ emit_analysis = .{ .yes = arg["-femit-analysis=".len..] };
+ } else if (mem.eql(u8, arg, "-fno-emit-analysis")) {
+ emit_analysis = .no;
} else if (mem.eql(u8, arg, "-dynamic")) {
link_mode = .Dynamic;
} else if (mem.eql(u8, arg, "-static")) {
@@ -1237,35 +1325,24 @@ pub fn buildOutputType(
},
};
- var cleanup_emit_h_dir: ?fs.Dir = null;
- defer if (cleanup_emit_h_dir) |*dir| dir.close();
+ const default_h_basename = try std.fmt.allocPrint(arena, "{}.h", .{root_name});
+ var emit_h_resolved = try emit_h.resolve(default_h_basename);
+ defer emit_h_resolved.deinit();
- const emit_h_loc: ?Compilation.EmitLoc = switch (emit_h) {
- .no => null,
- .yes_default_path => Compilation.EmitLoc{
- .directory = .{ .path = null, .handle = fs.cwd() },
- .basename = try std.fmt.allocPrint(arena, "{}.h", .{root_name}),
- },
- .yes => |full_path| b: {
- const basename = fs.path.basename(full_path);
- if (fs.path.dirname(full_path)) |dirname| {
- const handle = try fs.cwd().openDir(dirname, .{});
- cleanup_emit_h_dir = handle;
- break :b Compilation.EmitLoc{
- .basename = basename,
- .directory = .{
- .path = dirname,
- .handle = handle,
- },
- };
- } else {
- break :b Compilation.EmitLoc{
- .basename = basename,
- .directory = .{ .path = null, .handle = fs.cwd() },
- };
- }
- },
- };
+ const default_asm_basename = try std.fmt.allocPrint(arena, "{}.s", .{root_name});
+ var emit_asm_resolved = try emit_asm.resolve(default_asm_basename);
+ defer emit_asm_resolved.deinit();
+
+ const default_llvm_ir_basename = try std.fmt.allocPrint(arena, "{}.ll", .{root_name});
+ var emit_llvm_ir_resolved = try emit_llvm_ir.resolve(default_llvm_ir_basename);
+ defer emit_llvm_ir_resolved.deinit();
+
+ const default_analysis_basename = try std.fmt.allocPrint(arena, "{}-analysis.json", .{root_name});
+ var emit_analysis_resolved = try emit_analysis.resolve(default_analysis_basename);
+ defer emit_analysis_resolved.deinit();
+
+ var emit_docs_resolved = try emit_docs.resolve("docs");
+ defer emit_docs_resolved.deinit();
const zir_out_path: ?[]const u8 = switch (emit_zir) {
.no => null,
@@ -1365,6 +1442,12 @@ pub fn buildOutputType(
};
};
+ if (build_options.have_llvm and emit_asm != .no) {
+ // LLVM has no way to set this non-globally.
+ const argv = [_][*:0]const u8{ "zig (LLVM option parsing)", "--x86-asm-syntax=intel" };
+ @import("llvm.zig").ParseCommandLineOptions(argv.len, &argv);
+ }
+
gimmeMoreOfThoseSweetSweetFileDescriptors();
const comp = Compilation.create(gpa, .{
@@ -1378,7 +1461,11 @@ pub fn buildOutputType(
.output_mode = output_mode,
.root_pkg = root_pkg,
.emit_bin = emit_bin_loc,
- .emit_h = emit_h_loc,
+ .emit_h = emit_h_resolved.data,
+ .emit_asm = emit_asm_resolved.data,
+ .emit_llvm_ir = emit_llvm_ir_resolved.data,
+ .emit_docs = emit_docs_resolved.data,
+ .emit_analysis = emit_analysis_resolved.data,
.link_mode = link_mode,
.dll_export_fns = dll_export_fns,
.object_format = object_format,
src/stage1.zig
@@ -75,8 +75,18 @@ pub const Pkg = extern struct {
pub const Module = extern struct {
root_name_ptr: [*]const u8,
root_name_len: usize,
- output_dir_ptr: [*]const u8,
- output_dir_len: usize,
+ emit_o_ptr: [*]const u8,
+ emit_o_len: usize,
+ emit_h_ptr: [*]const u8,
+ emit_h_len: usize,
+ emit_asm_ptr: [*]const u8,
+ emit_asm_len: usize,
+ emit_llvm_ir_ptr: [*]const u8,
+ emit_llvm_ir_len: usize,
+ emit_analysis_json_ptr: [*]const u8,
+ emit_analysis_json_len: usize,
+ emit_docs_ptr: [*]const u8,
+ emit_docs_len: usize,
builtin_zig_path_ptr: [*]const u8,
builtin_zig_path_len: usize,
test_filter_ptr: [*]const u8,
@@ -101,11 +111,6 @@ pub const Module = extern struct {
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,
test/cli.zig
@@ -118,17 +118,20 @@ fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void {
\\}
);
- const args = [_][]const u8{
+ var args = std.ArrayList([]const u8).init(a);
+ try args.appendSlice(&[_][]const u8{
zig_exe, "build-obj",
"--cache-dir", dir_path,
"--name", "example",
- "--output-dir", dir_path,
- "--emit", "asm",
- "-mllvm", "--x86-asm-syntax=intel",
- "--strip", "--release-fast",
- example_zig_path, "--disable-gen-h",
- };
- _ = try exec(dir_path, &args);
+ "-fno-emit-bin", "-fno-emit-h",
+ "--strip", "-OReleaseFast",
+ example_zig_path,
+ });
+
+ const emit_asm_arg = try std.fmt.allocPrint(a, "-femit-asm={s}", .{example_s_path});
+ try args.append(emit_asm_arg);
+
+ _ = try exec(dir_path, args.items);
const out_asm = try std.fs.cwd().readFileAlloc(a, example_s_path, std.math.maxInt(usize));
testing.expect(std.mem.indexOf(u8, out_asm, "square:") != null);
BRANCH_TODO
@@ -1,13 +1,7 @@
+ * support -fno-emit-bin for godbolt
* tests passing with -Dskip-non-native
* `-ftime-report`
* -fstack-report print stack size diagnostics\n"
- * -fdump-analysis write analysis.json file with type information\n"
- * -femit-docs create a docs/ dir with html documentation\n"
- * -fno-emit-docs do not produce docs/ dir with html documentation\n"
- * -femit-asm output .s (assembly code)\n"
- * -fno-emit-asm (default) do not output .s (assembly code)\n"
- * -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"
* mingw-w64
* MachO LLD linking
* COFF LLD linking
@@ -17,8 +11,8 @@
* On operating systems that support it, do an execve for `zig test` and `zig run` rather than child process.
* restore error messages for stage2_add_link_lib
* windows CUSTOMBUILD : error : unable to build compiler_rt: FileNotFound [D:\a\1\s\build\zig_install_lib_files.vcxproj]
- * try building some software with zig cc
- * implement support for -femit-asm
+ * try building some software with zig cc to make sure it didn't regress
+ * restore the legacy -femit-h feature using the stage1 backend
* implement proper parsing of clang stderr/stdout and exposing compile errors with the Compilation API
* implement proper parsing of LLD stderr/stdout and exposing compile errors with the Compilation API
@@ -56,3 +50,4 @@
* make std.Progress support multithreaded
* update musl.zig static data to use native path separator in static data rather than replacing '/' at runtime
* linking hello world with LLD, lld is silently calling exit(1) instead of reporting ok=false. when run standalone the error message is: ld.lld: error: section [index 3] has a sh_offset (0x57000) + sh_size (0x68) that is greater than the file size (0x57060)
+ * submit PR to godbolt and update the CLI options (see changes to test/cli.zig)
CMakeLists.txt
@@ -449,7 +449,7 @@ endif()
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
set(ZIG1_RELEASE_ARG "")
else()
- set(ZIG1_RELEASE_ARG --release-fast --strip)
+ set(ZIG1_RELEASE_ARG -OReleaseFast --strip)
endif()
set(BUILD_ZIG1_ARGS
@@ -458,8 +458,8 @@ set(BUILD_ZIG1_ARGS
"-mcpu=${ZIG_TARGET_MCPU}"
--name zig1
--override-lib-dir "${CMAKE_SOURCE_DIR}/lib"
- --output-dir "${CMAKE_BINARY_DIR}"
- ${ZIG1_RELEASE_ARG}
+ "-femit-bin=${ZIG1_OBJECT}"
+ "${ZIG1_RELEASE_ARG}"
-lc
--pkg-begin build_options "${ZIG_CONFIG_ZIG_OUT}"
--pkg-end