authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-26 16:48:02-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-26 16:48:02-07:00
logfe4c348f578903d53c490673b1b1dcf5513ae049
tree4d0fa2750f0ee1699eca05bedd1076f087b6ba83
parent26f2f9bf1c774caf246317b3fc032449e982a150

stage2: `zig translate-c` supports --enable-cache

This matches master branch behavior and makes the test-translate-c tests pass.

3 files changed, 123 insertions(+), 54 deletions(-)

BRANCH_TODO-1
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1 * restore the legacy -femit-h feature using the stage1 backend1 * restore the legacy -femit-h feature using the stage1 backend
2 * figure out why test-translate-c is failing
3 * tests passing with -Dskip-non-native2 * tests passing with -Dskip-non-native
4 * `-ftime-report`3 * `-ftime-report`
5 * -fstack-report print stack size diagnostics\n"4 * -fstack-report print stack size diagnostics\n"
src/Compilation.zig+4-2
...@@ -1251,7 +1251,7 @@ pub fn performAllTheWork(self: *Compilation) error{OutOfMemory}!void {...@@ -1251,7 +1251,7 @@ pub fn performAllTheWork(self: *Compilation) error{OutOfMemory}!void {
1251 };1251 };
1252}1252}
12531253
1254fn obtainCObjectCacheManifest(comp: *Compilation) Cache.Manifest {1254pub fn obtainCObjectCacheManifest(comp: *Compilation) Cache.Manifest {
1255 var man = comp.cache_parent.obtain();1255 var man = comp.cache_parent.obtain();
12561256
1257 // Only things that need to be added on top of the base hash, and only things1257 // Only things that need to be added on top of the base hash, and only things
...@@ -1289,6 +1289,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {...@@ -1289,6 +1289,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
1289 var man = comp.obtainCObjectCacheManifest();1289 var man = comp.obtainCObjectCacheManifest();
1290 defer man.deinit();1290 defer man.deinit();
12911291
1292 man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects
1292 man.hash.addBytes(c_src);1293 man.hash.addBytes(c_src);
12931294
1294 // If the previous invocation resulted in clang errors, we will see a hit1295 // If the previous invocation resulted in clang errors, we will see a hit
...@@ -1581,7 +1582,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void {...@@ -1581,7 +1582,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void {
1581 };1582 };
1582}1583}
15831584
1584fn tmpFilePath(comp: *Compilation, arena: *Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 {1585pub fn tmpFilePath(comp: *Compilation, arena: *Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 {
1585 const s = std.fs.path.sep_str;1586 const s = std.fs.path.sep_str;
1586 const rand_int = comp.rand.int(u64);1587 const rand_int = comp.rand.int(u64);
1587 if (comp.local_cache_directory.path) |p| {1588 if (comp.local_cache_directory.path) |p| {
...@@ -1598,6 +1599,7 @@ pub fn addTranslateCCArgs(...@@ -1598,6 +1599,7 @@ pub fn addTranslateCCArgs(
1598 ext: FileExt,1599 ext: FileExt,
1599 out_dep_path: ?[]const u8,1600 out_dep_path: ?[]const u8,
1600) !void {1601) !void {
1602 try argv.appendSlice(&[_][]const u8{ "-x", "c" });
1601 try comp.addCCArgs(arena, argv, ext, out_dep_path);1603 try comp.addCCArgs(arena, argv, ext, out_dep_path);
1602 // This gives us access to preprocessing entities, presumably at the cost of performance.1604 // This gives us access to preprocessing entities, presumably at the cost of performance.
1603 try argv.appendSlice(&[_][]const u8{ "-Xclang", "-detailed-preprocessing-record" });1605 try argv.appendSlice(&[_][]const u8{ "-Xclang", "-detailed-preprocessing-record" });
src/main.zig+119-51
...@@ -16,6 +16,7 @@ const warn = std.log.warn;...@@ -16,6 +16,7 @@ const warn = std.log.warn;
16const introspect = @import("introspect.zig");16const introspect = @import("introspect.zig");
17const LibCInstallation = @import("libc_installation.zig").LibCInstallation;17const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
18const translate_c = @import("translate_c.zig");18const translate_c = @import("translate_c.zig");
19const Cache = @import("Cache.zig");
1920
20pub fn fatal(comptime format: []const u8, args: anytype) noreturn {21pub fn fatal(comptime format: []const u8, args: anytype) noreturn {
21 std.log.emerg(format, args);22 std.log.emerg(format, args);
...@@ -481,12 +482,19 @@ fn buildOutputType(...@@ -481,12 +482,19 @@ fn buildOutputType(
481 switch (arg_mode) {482 switch (arg_mode) {
482 .build, .translate_c, .zig_test, .run => {483 .build, .translate_c, .zig_test, .run => {
483 var optimize_mode_string: ?[]const u8 = null;484 var optimize_mode_string: ?[]const u8 = null;
484 output_mode = switch (arg_mode) {485 switch (arg_mode) {
485 .build => |m| m,486 .build => |m| {
486 .translate_c => .Obj,487 output_mode = m;
487 .zig_test, .run => .Exe,488 },
489 .translate_c => {
490 emit_bin = .no;
491 output_mode = .Obj;
492 },
493 .zig_test, .run => {
494 output_mode = .Exe;
495 },
488 else => unreachable,496 else => unreachable,
489 };497 }
490 // TODO finish self-hosted and add support for emitting C header files498 // TODO finish self-hosted and add support for emitting C header files
491 emit_h = .no;499 emit_h = .no;
492 //switch (arg_mode) {500 //switch (arg_mode) {
...@@ -1537,7 +1545,7 @@ fn buildOutputType(...@@ -1537,7 +1545,7 @@ fn buildOutputType(
1537 return std.io.getStdOut().writeAll(try comp.generateBuiltinZigSource(arena));1545 return std.io.getStdOut().writeAll(try comp.generateBuiltinZigSource(arena));
1538 }1546 }
1539 if (arg_mode == .translate_c) {1547 if (arg_mode == .translate_c) {
1540 return cmdTranslateC(comp, arena);1548 return cmdTranslateC(comp, arena, have_enable_cache);
1541 }1549 }
15421550
1543 const hook: AfterUpdateHook = blk: {1551 const hook: AfterUpdateHook = blk: {
...@@ -1556,7 +1564,7 @@ fn buildOutputType(...@@ -1556,7 +1564,7 @@ fn buildOutputType(
1556 try updateModule(gpa, comp, zir_out_path, hook);1564 try updateModule(gpa, comp, zir_out_path, hook);
15571565
1558 if (build_options.is_stage1 and comp.stage1_lock != null and watch) {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 }
15611569
1562 switch (arg_mode) {1570 switch (arg_mode) {
...@@ -1701,61 +1709,121 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, zir_out_path: ?[]const u8,...@@ -1701,61 +1709,121 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, zir_out_path: ?[]const u8,
1701 }1709 }
1702}1710}
17031711
1704fn cmdTranslateC(comp: *Compilation, arena: *Allocator) !void {1712fn cmdTranslateC(comp: *Compilation, arena: *Allocator, enable_cache: bool) !void {
1705 if (!build_options.have_llvm)1713 if (!build_options.have_llvm)
1706 fatal("cannot translate-c: compiler built without LLVM extensions", .{});1714 fatal("cannot translate-c: compiler built without LLVM extensions", .{});
17071715
1708 assert(comp.c_source_files.len == 1);1716 assert(comp.c_source_files.len == 1);
1717 const c_source_file = comp.c_source_files[0];
17091718
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});
17111720
1712 const c_source_file = comp.c_source_files[0];1721 var man: Cache.Manifest = comp.obtainCObjectCacheManifest();
1713 const file_ext = Compilation.classifyFileExt(c_source_file.src_path);1722 defer if (enable_cache) man.deinit();
1714 try comp.addTranslateCCArgs(arena, &argv, file_ext, null);
1715 try argv.append(c_source_file.src_path);
17161723
1717 if (comp.verbose_cc) {1724 man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects
1718 std.debug.print("clang ", .{});1725 _ = man.addFile(c_source_file.src_path, null) catch |err| {
1719 Compilation.dump_argv(argv.items);1726 fatal("unable to process '{}': {}", .{ c_source_file.src_path, @errorName(err) });
1720 }1727 };
17211728
1722 // Convert to null terminated args.1729 const digest = if (try man.hit()) man.final() else digest: {
1723 const new_argv_with_sentinel = try arena.alloc(?[*:0]const u8, argv.items.len + 1);1730 var argv = std.ArrayList([]const u8).init(arena);
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 }
17291731
1730 const c_headers_dir_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{"include"});1732 var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{});
1731 const c_headers_dir_path_z = try arena.dupeZ(u8, c_headers_dir_path);1733 defer zig_cache_tmp_dir.close();
1732 var clang_errors: []translate_c.ClangErrMsg = &[0]translate_c.ClangErrMsg{};1734
1733 const tree = translate_c.translate(1735 const ext = Compilation.classifyFileExt(c_source_file.src_path);
1734 comp.gpa,1736 const out_dep_path: ?[]const u8 = blk: {
1735 new_argv.ptr,1737 if (comp.disable_c_depfile or !ext.clangSupportsDepFile())
1736 new_argv.ptr + new_argv.len,1738 break :blk null;
1737 &clang_errors,1739
1738 c_headers_dir_path_z,1740 const c_src_basename = fs.path.basename(c_source_file.src_path);
1739 ) catch |err| switch (err) {1741 const dep_basename = try std.fmt.allocPrint(arena, "{}.d", .{c_src_basename});
1740 error.OutOfMemory => return error.OutOfMemory,1742 const out_dep_path = try comp.tmpFilePath(arena, dep_basename);
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", .{}),1743 break :blk out_dep_path;
1742 error.SemanticAnalyzeFail => {1744 };
1743 for (clang_errors) |clang_err| {1745
1744 std.debug.print("{}:{}:{}: {}\n", .{1746 try comp.addTranslateCCArgs(arena, &argv, ext, out_dep_path);
1745 if (clang_err.filename_ptr) |p| p[0..clang_err.filename_len] else "(no file)",1747 try argv.append(c_source_file.src_path);
1746 clang_err.line + 1,1748
1747 clang_err.column + 1,1749 if (comp.verbose_cc) {
1748 clang_err.msg_ptr[0..clang_err.msg_len],1750 std.debug.print("clang ", .{});
1749 });1751 Compilation.dump_argv(argv.items);
1750 }1752 }
1751 process.exit(1);1753
1752 },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();
17551813
1756 var bos = io.bufferedOutStream(io.getStdOut().writer());1814 if (enable_cache) {
1757 _ = try std.zig.render(comp.gpa, bos.writer(), tree);1815 const full_zig_path = try comp.local_cache_directory.join(arena, &[_][]const u8{
1758 try bos.flush();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}
17601828
1761pub const usage_libc =1829pub const usage_libc =