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
parent
a337046832
commit
6af2990549
13
BRANCH_TODO
13
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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
157
src/main.zig
157
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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
19
test/cli.zig
19
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);
|
||||
|
|
Loading…
Reference in New Issue