implement -femit-asm, -femit-docs, -femit-llvm-ir, etc

These CLI options are now forwarded to the stage1 backend.

We're not going to support the -mllvm CLI option any longer. As a
compromise, we unconditionally tell LLVM to output intel x86 syntax when
using -femit-asm.

Simplify stage1 logic; it no longer has the concept of an output
directory. --output-dir is no longer a valid CLI option. cmake uses
the `-femit-bin=[path]` option.

Note the changes to test/cli.zig. This breaks the CLI API that Godbolt
is using so we're going to want to open a PR to help them upgrade to the
new CLI for the upcoming Zig 0.7.0 release.
master
Andrew Kelley 2020-09-26 01:42:54 -07:00
parent a337046832
commit 6af2990549
12 changed files with 263 additions and 158 deletions

View File

@ -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)

View File

@ -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

View File

@ -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,

View File

@ -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;

View File

@ -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,

View File

@ -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,

View File

@ -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;

View File

@ -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);
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)));
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);
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;

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);