| ... | ... | @@ -16,6 +16,7 @@ const warn = std.log.warn; |
| 16 | 16 | const introspect = @import("introspect.zig"); |
| 17 | 17 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; |
| 18 | 18 | const translate_c = @import("translate_c.zig"); |
| 19 | const Cache = @import("Cache.zig"); |
| 19 | 20 | |
| 20 | 21 | pub fn fatal(comptime format: []const u8, args: anytype) noreturn { |
| 21 | 22 | std.log.emerg(format, args); |
| ... | ... | @@ -481,12 +482,19 @@ fn buildOutputType( |
| 481 | 482 | switch (arg_mode) { |
| 482 | 483 | .build, .translate_c, .zig_test, .run => { |
| 483 | 484 | var optimize_mode_string: ?[]const u8 = null; |
| 484 | | output_mode = switch (arg_mode) { |
| 485 | | .build => |m| m, |
| 486 | | .translate_c => .Obj, |
| 487 | | .zig_test, .run => .Exe, |
| 485 | switch (arg_mode) { |
| 486 | .build => |m| { |
| 487 | output_mode = m; |
| 488 | }, |
| 489 | .translate_c => { |
| 490 | emit_bin = .no; |
| 491 | output_mode = .Obj; |
| 492 | }, |
| 493 | .zig_test, .run => { |
| 494 | output_mode = .Exe; |
| 495 | }, |
| 488 | 496 | else => unreachable, |
| 489 | | }; |
| 497 | } |
| 490 | 498 | // TODO finish self-hosted and add support for emitting C header files |
| 491 | 499 | emit_h = .no; |
| 492 | 500 | //switch (arg_mode) { |
| ... | ... | @@ -1537,7 +1545,7 @@ fn buildOutputType( |
| 1537 | 1545 | return std.io.getStdOut().writeAll(try comp.generateBuiltinZigSource(arena)); |
| 1538 | 1546 | } |
| 1539 | 1547 | if (arg_mode == .translate_c) { |
| 1540 | | return cmdTranslateC(comp, arena); |
| 1548 | return cmdTranslateC(comp, arena, have_enable_cache); |
| 1541 | 1549 | } |
| 1542 | 1550 | |
| 1543 | 1551 | const hook: AfterUpdateHook = blk: { |
| ... | ... | @@ -1556,7 +1564,7 @@ fn buildOutputType( |
| 1556 | 1564 | try updateModule(gpa, comp, zir_out_path, hook); |
| 1557 | 1565 | |
| 1558 | 1566 | if (build_options.is_stage1 and comp.stage1_lock != null and watch) { |
| 1559 | | std.log.warn("--watch is not recommended with the stage1 backend; it leaks memory and is not capable of incremental compilation", .{}); |
| 1567 | warn("--watch is not recommended with the stage1 backend; it leaks memory and is not capable of incremental compilation", .{}); |
| 1560 | 1568 | } |
| 1561 | 1569 | |
| 1562 | 1570 | switch (arg_mode) { |
| ... | ... | @@ -1701,61 +1709,121 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, zir_out_path: ?[]const u8, |
| 1701 | 1709 | } |
| 1702 | 1710 | } |
| 1703 | 1711 | |
| 1704 | | fn cmdTranslateC(comp: *Compilation, arena: *Allocator) !void { |
| 1712 | fn cmdTranslateC(comp: *Compilation, arena: *Allocator, enable_cache: bool) !void { |
| 1705 | 1713 | if (!build_options.have_llvm) |
| 1706 | 1714 | fatal("cannot translate-c: compiler built without LLVM extensions", .{}); |
| 1707 | 1715 | |
| 1708 | 1716 | assert(comp.c_source_files.len == 1); |
| 1717 | const c_source_file = comp.c_source_files[0]; |
| 1709 | 1718 | |
| 1710 | | var argv = std.ArrayList([]const u8).init(arena); |
| 1719 | const translated_zig_basename = try std.fmt.allocPrint(arena, "{}.zig", .{comp.bin_file.options.root_name}); |
| 1711 | 1720 | |
| 1712 | | const c_source_file = comp.c_source_files[0]; |
| 1713 | | const file_ext = Compilation.classifyFileExt(c_source_file.src_path); |
| 1714 | | try comp.addTranslateCCArgs(arena, &argv, file_ext, null); |
| 1715 | | try argv.append(c_source_file.src_path); |
| 1721 | var man: Cache.Manifest = comp.obtainCObjectCacheManifest(); |
| 1722 | defer if (enable_cache) man.deinit(); |
| 1716 | 1723 | |
| 1717 | | if (comp.verbose_cc) { |
| 1718 | | std.debug.print("clang ", .{}); |
| 1719 | | Compilation.dump_argv(argv.items); |
| 1720 | | } |
| 1724 | man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects |
| 1725 | _ = man.addFile(c_source_file.src_path, null) catch |err| { |
| 1726 | fatal("unable to process '{}': {}", .{ c_source_file.src_path, @errorName(err) }); |
| 1727 | }; |
| 1721 | 1728 | |
| 1722 | | // Convert to null terminated args. |
| 1723 | | const new_argv_with_sentinel = try arena.alloc(?[*:0]const u8, argv.items.len + 1); |
| 1724 | | new_argv_with_sentinel[argv.items.len] = null; |
| 1725 | | const new_argv = new_argv_with_sentinel[0..argv.items.len :null]; |
| 1726 | | for (argv.items) |arg, i| { |
| 1727 | | new_argv[i] = try arena.dupeZ(u8, arg); |
| 1728 | | } |
| 1729 | const digest = if (try man.hit()) man.final() else digest: { |
| 1730 | var argv = std.ArrayList([]const u8).init(arena); |
| 1729 | 1731 | |
| 1730 | | const c_headers_dir_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{"include"}); |
| 1731 | | const c_headers_dir_path_z = try arena.dupeZ(u8, c_headers_dir_path); |
| 1732 | | var clang_errors: []translate_c.ClangErrMsg = &[0]translate_c.ClangErrMsg{}; |
| 1733 | | const tree = translate_c.translate( |
| 1734 | | comp.gpa, |
| 1735 | | new_argv.ptr, |
| 1736 | | new_argv.ptr + new_argv.len, |
| 1737 | | &clang_errors, |
| 1738 | | c_headers_dir_path_z, |
| 1739 | | ) catch |err| switch (err) { |
| 1740 | | error.OutOfMemory => return error.OutOfMemory, |
| 1741 | | error.ASTUnitFailure => fatal("clang API returned errors but due to a clang bug, it is not exposing the errors for zig to see. For more details: https://github.com/ziglang/zig/issues/4455", .{}), |
| 1742 | | error.SemanticAnalyzeFail => { |
| 1743 | | for (clang_errors) |clang_err| { |
| 1744 | | std.debug.print("{}:{}:{}: {}\n", .{ |
| 1745 | | if (clang_err.filename_ptr) |p| p[0..clang_err.filename_len] else "(no file)", |
| 1746 | | clang_err.line + 1, |
| 1747 | | clang_err.column + 1, |
| 1748 | | clang_err.msg_ptr[0..clang_err.msg_len], |
| 1749 | | }); |
| 1750 | | } |
| 1751 | | process.exit(1); |
| 1752 | | }, |
| 1732 | var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{}); |
| 1733 | defer zig_cache_tmp_dir.close(); |
| 1734 | |
| 1735 | const ext = Compilation.classifyFileExt(c_source_file.src_path); |
| 1736 | const out_dep_path: ?[]const u8 = blk: { |
| 1737 | if (comp.disable_c_depfile or !ext.clangSupportsDepFile()) |
| 1738 | break :blk null; |
| 1739 | |
| 1740 | const c_src_basename = fs.path.basename(c_source_file.src_path); |
| 1741 | const dep_basename = try std.fmt.allocPrint(arena, "{}.d", .{c_src_basename}); |
| 1742 | const out_dep_path = try comp.tmpFilePath(arena, dep_basename); |
| 1743 | break :blk out_dep_path; |
| 1744 | }; |
| 1745 | |
| 1746 | try comp.addTranslateCCArgs(arena, &argv, ext, out_dep_path); |
| 1747 | try argv.append(c_source_file.src_path); |
| 1748 | |
| 1749 | if (comp.verbose_cc) { |
| 1750 | std.debug.print("clang ", .{}); |
| 1751 | Compilation.dump_argv(argv.items); |
| 1752 | } |
| 1753 | |
| 1754 | // Convert to null terminated args. |
| 1755 | const new_argv_with_sentinel = try arena.alloc(?[*:0]const u8, argv.items.len + 1); |
| 1756 | new_argv_with_sentinel[argv.items.len] = null; |
| 1757 | const new_argv = new_argv_with_sentinel[0..argv.items.len :null]; |
| 1758 | for (argv.items) |arg, i| { |
| 1759 | new_argv[i] = try arena.dupeZ(u8, arg); |
| 1760 | } |
| 1761 | |
| 1762 | const c_headers_dir_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{"include"}); |
| 1763 | const c_headers_dir_path_z = try arena.dupeZ(u8, c_headers_dir_path); |
| 1764 | var clang_errors: []translate_c.ClangErrMsg = &[0]translate_c.ClangErrMsg{}; |
| 1765 | const tree = translate_c.translate( |
| 1766 | comp.gpa, |
| 1767 | new_argv.ptr, |
| 1768 | new_argv.ptr + new_argv.len, |
| 1769 | &clang_errors, |
| 1770 | c_headers_dir_path_z, |
| 1771 | ) catch |err| switch (err) { |
| 1772 | error.OutOfMemory => return error.OutOfMemory, |
| 1773 | error.ASTUnitFailure => fatal("clang API returned errors but due to a clang bug, it is not exposing the errors for zig to see. For more details: https://github.com/ziglang/zig/issues/4455", .{}), |
| 1774 | error.SemanticAnalyzeFail => { |
| 1775 | for (clang_errors) |clang_err| { |
| 1776 | std.debug.print("{}:{}:{}: {}\n", .{ |
| 1777 | if (clang_err.filename_ptr) |p| p[0..clang_err.filename_len] else "(no file)", |
| 1778 | clang_err.line + 1, |
| 1779 | clang_err.column + 1, |
| 1780 | clang_err.msg_ptr[0..clang_err.msg_len], |
| 1781 | }); |
| 1782 | } |
| 1783 | process.exit(1); |
| 1784 | }, |
| 1785 | }; |
| 1786 | defer tree.deinit(); |
| 1787 | |
| 1788 | if (out_dep_path) |dep_file_path| { |
| 1789 | const dep_basename = std.fs.path.basename(dep_file_path); |
| 1790 | // Add the files depended on to the cache system. |
| 1791 | try man.addDepFilePost(zig_cache_tmp_dir, dep_basename); |
| 1792 | // Just to save disk space, we delete the file because it is never needed again. |
| 1793 | zig_cache_tmp_dir.deleteFile(dep_basename) catch |err| { |
| 1794 | warn("failed to delete '{}': {}", .{ dep_file_path, @errorName(err) }); |
| 1795 | }; |
| 1796 | } |
| 1797 | |
| 1798 | const digest = man.final(); |
| 1799 | const o_sub_path = try fs.path.join(arena, &[_][]const u8{ "o", &digest }); |
| 1800 | var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{}); |
| 1801 | defer o_dir.close(); |
| 1802 | var zig_file = try o_dir.createFile(translated_zig_basename, .{}); |
| 1803 | defer zig_file.close(); |
| 1804 | |
| 1805 | var bos = io.bufferedOutStream(zig_file.writer()); |
| 1806 | _ = try std.zig.render(comp.gpa, bos.writer(), tree); |
| 1807 | try bos.flush(); |
| 1808 | |
| 1809 | man.writeManifest() catch |err| warn("failed to write cache manifest: {}", .{@errorName(err)}); |
| 1810 | |
| 1811 | break :digest digest; |
| 1753 | 1812 | }; |
| 1754 | | defer tree.deinit(); |
| 1755 | 1813 | |
| 1756 | | var bos = io.bufferedOutStream(io.getStdOut().writer()); |
| 1757 | | _ = try std.zig.render(comp.gpa, bos.writer(), tree); |
| 1758 | | try bos.flush(); |
| 1814 | if (enable_cache) { |
| 1815 | const full_zig_path = try comp.local_cache_directory.join(arena, &[_][]const u8{ |
| 1816 | "o", &digest, translated_zig_basename, |
| 1817 | }); |
| 1818 | try io.getStdOut().writer().print("{}\n", .{full_zig_path}); |
| 1819 | return cleanExit(); |
| 1820 | } else { |
| 1821 | const out_zig_path = try fs.path.join(arena, &[_][]const u8{ "o", &digest, translated_zig_basename }); |
| 1822 | const zig_file = try comp.local_cache_directory.handle.openFile(out_zig_path, .{}); |
| 1823 | defer zig_file.close(); |
| 1824 | try io.getStdOut().writeFileAll(zig_file, .{}); |
| 1825 | return cleanExit(); |
| 1826 | } |
| 1759 | 1827 | } |
| 1760 | 1828 | |
| 1761 | 1829 | pub const usage_libc = |