| ... | @@ -849,10 +849,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -849,10 +849,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 849 | if (options.use_llvm) |explicit| | 849 | if (options.use_llvm) |explicit| |
| 850 | break :blk explicit; | 850 | break :blk explicit; |
| 851 | | 851 | |
| 852 | // If we have no zig code to compile, no need for LLVM. | | |
| 853 | if (options.main_pkg == null) | | |
| 854 | break :blk false; | | |
| 855 | | | |
| 856 | // If we are outputting .c code we must use Zig backend. | 852 | // If we are outputting .c code we must use Zig backend. |
| 857 | if (ofmt == .c) | 853 | if (ofmt == .c) |
| 858 | break :blk false; | 854 | break :blk false; |
| ... | @@ -861,6 +857,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -861,6 +857,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 861 | if (options.emit_llvm_ir != null or options.emit_llvm_bc != null) | 857 | if (options.emit_llvm_ir != null or options.emit_llvm_bc != null) |
| 862 | break :blk true; | 858 | break :blk true; |
| 863 | | 859 | |
| | 860 | // If we have no zig code to compile, no need for LLVM. |
| | 861 | if (options.main_pkg == null) |
| | 862 | break :blk false; |
| | 863 | |
| 864 | // The stage1 compiler depends on the stage1 C++ LLVM backend | 864 | // The stage1 compiler depends on the stage1 C++ LLVM backend |
| 865 | // to compile zig code. | 865 | // to compile zig code. |
| 866 | if (use_stage1) | 866 | if (use_stage1) |
| ... | @@ -876,9 +876,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -876,9 +876,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 876 | if (options.use_llvm == true) { | 876 | if (options.use_llvm == true) { |
| 877 | return error.ZigCompilerNotBuiltWithLLVMExtensions; | 877 | return error.ZigCompilerNotBuiltWithLLVMExtensions; |
| 878 | } | 878 | } |
| 879 | if (options.machine_code_model != .default) { | | |
| 880 | return error.MachineCodeModelNotSupportedWithoutLlvm; | | |
| 881 | } | | |
| 882 | if (options.emit_llvm_ir != null or options.emit_llvm_bc != null) { | 879 | if (options.emit_llvm_ir != null or options.emit_llvm_bc != null) { |
| 883 | return error.EmittingLlvmModuleRequiresUsingLlvmBackend; | 880 | return error.EmittingLlvmModuleRequiresUsingLlvmBackend; |
| 884 | } | 881 | } |
| ... | @@ -1793,6 +1790,10 @@ pub fn update(self: *Compilation) !void { | ... | @@ -1793,6 +1790,10 @@ pub fn update(self: *Compilation) !void { |
| 1793 | } | 1790 | } |
| 1794 | } | 1791 | } |
| 1795 | | 1792 | |
| | 1793 | // Flush takes care of -femit-bin, but we still have -femit-llvm-ir, -femit-llvm-bc, and |
| | 1794 | // -femit-asm to handle, in the case of C objects. |
| | 1795 | try self.emitOthers(); |
| | 1796 | |
| 1796 | // If there are any errors, we anticipate the source files being loaded | 1797 | // If there are any errors, we anticipate the source files being loaded |
| 1797 | // to report error messages. Otherwise we unload all source files to save memory. | 1798 | // to report error messages. Otherwise we unload all source files to save memory. |
| 1798 | // The ZIR needs to stay loaded in memory because (1) Decl objects contain references | 1799 | // The ZIR needs to stay loaded in memory because (1) Decl objects contain references |
| ... | @@ -1808,6 +1809,37 @@ pub fn update(self: *Compilation) !void { | ... | @@ -1808,6 +1809,37 @@ pub fn update(self: *Compilation) !void { |
| 1808 | } | 1809 | } |
| 1809 | } | 1810 | } |
| 1810 | | 1811 | |
| | 1812 | fn emitOthers(comp: *Compilation) !void { |
| | 1813 | if (comp.bin_file.options.output_mode != .Obj or comp.bin_file.options.module != null or |
| | 1814 | comp.c_object_table.count() == 0) |
| | 1815 | { |
| | 1816 | return; |
| | 1817 | } |
| | 1818 | const obj_path = comp.c_object_table.keys()[0].status.success.object_path; |
| | 1819 | const cwd = std.fs.cwd(); |
| | 1820 | const ext = std.fs.path.extension(obj_path); |
| | 1821 | const basename = obj_path[0 .. obj_path.len - ext.len]; |
| | 1822 | // This obj path always ends with the object file extension, but if we change the |
| | 1823 | // extension to .ll, .bc, or .s, then it will be the path to those things. |
| | 1824 | const outs = [_]struct { |
| | 1825 | emit: ?EmitLoc, |
| | 1826 | ext: []const u8, |
| | 1827 | }{ |
| | 1828 | .{ .emit = comp.emit_asm, .ext = ".s" }, |
| | 1829 | .{ .emit = comp.emit_llvm_ir, .ext = ".ll" }, |
| | 1830 | .{ .emit = comp.emit_llvm_bc, .ext = ".bc" }, |
| | 1831 | }; |
| | 1832 | for (outs) |out| { |
| | 1833 | if (out.emit) |loc| { |
| | 1834 | if (loc.directory) |directory| { |
| | 1835 | const src_path = try std.fmt.allocPrint(comp.gpa, "{s}{s}", .{ basename, out.ext }); |
| | 1836 | defer comp.gpa.free(src_path); |
| | 1837 | try cwd.copyFile(src_path, directory.handle, loc.basename, .{}); |
| | 1838 | } |
| | 1839 | } |
| | 1840 | } |
| | 1841 | } |
| | 1842 | |
| 1811 | /// Having the file open for writing is problematic as far as executing the | 1843 | /// Having the file open for writing is problematic as far as executing the |
| 1812 | /// binary is concerned. This will remove the write flag, or close the file, | 1844 | /// binary is concerned. This will remove the write flag, or close the file, |
| 1813 | /// or whatever is needed so that it can be executed. | 1845 | /// or whatever is needed so that it can be executed. |
| ... | @@ -2764,6 +2796,9 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P | ... | @@ -2764,6 +2796,9 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P |
| 2764 | defer man.deinit(); | 2796 | defer man.deinit(); |
| 2765 | | 2797 | |
| 2766 | man.hash.add(comp.clang_preprocessor_mode); | 2798 | man.hash.add(comp.clang_preprocessor_mode); |
| | 2799 | man.hash.addOptionalEmitLoc(comp.emit_asm); |
| | 2800 | man.hash.addOptionalEmitLoc(comp.emit_llvm_ir); |
| | 2801 | man.hash.addOptionalEmitLoc(comp.emit_llvm_bc); |
| 2767 | | 2802 | |
| 2768 | try man.hashCSource(c_object.src); | 2803 | try man.hashCSource(c_object.src); |
| 2769 | | 2804 | |
| ... | @@ -2787,16 +2822,29 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P | ... | @@ -2787,16 +2822,29 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P |
| 2787 | comp.bin_file.options.root_name | 2822 | comp.bin_file.options.root_name |
| 2788 | else | 2823 | else |
| 2789 | c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len]; | 2824 | c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len]; |
| 2790 | const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ | | |
| 2791 | o_basename_noext, | | |
| 2792 | comp.bin_file.options.object_format.fileExt(comp.bin_file.options.target.cpu.arch), | | |
| 2793 | }); | | |
| 2794 | | 2825 | |
| | 2826 | const o_ext = comp.bin_file.options.object_format.fileExt(comp.bin_file.options.target.cpu.arch); |
| 2795 | const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: { | 2827 | const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: { |
| 2796 | var argv = std.ArrayList([]const u8).init(comp.gpa); | 2828 | var argv = std.ArrayList([]const u8).init(comp.gpa); |
| 2797 | defer argv.deinit(); | 2829 | defer argv.deinit(); |
| 2798 | | 2830 | |
| 2799 | // We can't know the digest until we do the C compiler invocation, so we need a temporary filename. | 2831 | // In case we are doing passthrough mode, we need to detect -S and -emit-llvm. |
| | 2832 | const out_ext = e: { |
| | 2833 | if (!comp.clang_passthrough_mode) |
| | 2834 | break :e o_ext; |
| | 2835 | if (comp.emit_asm != null) |
| | 2836 | break :e ".s"; |
| | 2837 | if (comp.emit_llvm_ir != null) |
| | 2838 | break :e ".ll"; |
| | 2839 | if (comp.emit_llvm_bc != null) |
| | 2840 | break :e ".bc"; |
| | 2841 | |
| | 2842 | break :e o_ext; |
| | 2843 | }; |
| | 2844 | const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, out_ext }); |
| | 2845 | |
| | 2846 | // We can't know the digest until we do the C compiler invocation, |
| | 2847 | // so we need a temporary filename. |
| 2800 | const out_obj_path = try comp.tmpFilePath(arena, o_basename); | 2848 | const out_obj_path = try comp.tmpFilePath(arena, o_basename); |
| 2801 | var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{}); | 2849 | var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{}); |
| 2802 | defer zig_cache_tmp_dir.close(); | 2850 | defer zig_cache_tmp_dir.close(); |
| ... | @@ -2810,15 +2858,23 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P | ... | @@ -2810,15 +2858,23 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P |
| 2810 | try std.fmt.allocPrint(arena, "{s}.d", .{out_obj_path}); | 2858 | try std.fmt.allocPrint(arena, "{s}.d", .{out_obj_path}); |
| 2811 | try comp.addCCArgs(arena, &argv, ext, out_dep_path); | 2859 | try comp.addCCArgs(arena, &argv, ext, out_dep_path); |
| 2812 | | 2860 | |
| 2813 | try argv.ensureCapacity(argv.items.len + 3); | 2861 | try argv.ensureUnusedCapacity(6 + c_object.src.extra_flags.len); |
| 2814 | switch (comp.clang_preprocessor_mode) { | 2862 | switch (comp.clang_preprocessor_mode) { |
| 2815 | .no => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-c", "-o", out_obj_path }), | 2863 | .no => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-c", "-o", out_obj_path }), |
| 2816 | .yes => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-E", "-o", out_obj_path }), | 2864 | .yes => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-E", "-o", out_obj_path }), |
| 2817 | .stdout => argv.appendAssumeCapacity("-E"), | 2865 | .stdout => argv.appendAssumeCapacity("-E"), |
| 2818 | } | 2866 | } |
| 2819 | | 2867 | if (comp.clang_passthrough_mode) { |
| 2820 | try argv.append(c_object.src.src_path); | 2868 | if (comp.emit_asm != null) { |
| 2821 | try argv.appendSlice(c_object.src.extra_flags); | 2869 | argv.appendAssumeCapacity("-S"); |
| | 2870 | } else if (comp.emit_llvm_ir != null) { |
| | 2871 | argv.appendSliceAssumeCapacity(&[_][]const u8{ "-emit-llvm", "-S" }); |
| | 2872 | } else if (comp.emit_llvm_bc != null) { |
| | 2873 | argv.appendAssumeCapacity("-emit-llvm"); |
| | 2874 | } |
| | 2875 | } |
| | 2876 | argv.appendAssumeCapacity(c_object.src.src_path); |
| | 2877 | argv.appendSliceAssumeCapacity(c_object.src.extra_flags); |
| 2822 | | 2878 | |
| 2823 | if (comp.verbose_cc) { | 2879 | if (comp.verbose_cc) { |
| 2824 | dump_argv(argv.items); | 2880 | dump_argv(argv.items); |
| ... | @@ -2838,8 +2894,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P | ... | @@ -2838,8 +2894,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P |
| 2838 | switch (term) { | 2894 | switch (term) { |
| 2839 | .Exited => |code| { | 2895 | .Exited => |code| { |
| 2840 | if (code != 0) { | 2896 | if (code != 0) { |
| 2841 | // TODO https://github.com/ziglang/zig/issues/6342 | 2897 | std.process.exit(code); |
| 2842 | std.process.exit(1); | | |
| 2843 | } | 2898 | } |
| 2844 | if (comp.clang_preprocessor_mode == .stdout) | 2899 | if (comp.clang_preprocessor_mode == .stdout) |
| 2845 | std.process.exit(0); | 2900 | std.process.exit(0); |
| ... | @@ -2855,9 +2910,6 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P | ... | @@ -2855,9 +2910,6 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P |
| 2855 | | 2910 | |
| 2856 | const stderr_reader = child.stderr.?.reader(); | 2911 | const stderr_reader = child.stderr.?.reader(); |
| 2857 | | 2912 | |
| 2858 | // TODO https://github.com/ziglang/zig/issues/6343 | | |
| 2859 | // Please uncomment and use stdout once this issue is fixed | | |
| 2860 | // const stdout = try stdout_reader.readAllAlloc(arena, std.math.maxInt(u32)); | | |
| 2861 | const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024); | 2913 | const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024); |
| 2862 | | 2914 | |
| 2863 | const term = child.wait() catch |err| { | 2915 | const term = child.wait() catch |err| { |
| ... | @@ -2907,6 +2959,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P | ... | @@ -2907,6 +2959,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P |
| 2907 | break :blk digest; | 2959 | break :blk digest; |
| 2908 | }; | 2960 | }; |
| 2909 | | 2961 | |
| | 2962 | const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, o_ext }); |
| | 2963 | |
| 2910 | c_object.status = .{ | 2964 | c_object.status = .{ |
| 2911 | .success = .{ | 2965 | .success = .{ |
| 2912 | .object_path = try comp.local_cache_directory.join(comp.gpa, &[_][]const u8{ | 2966 | .object_path = try comp.local_cache_directory.join(comp.gpa, &[_][]const u8{ |