| author | |
| committer | |
| log | ae119a9a8d5b8dec21bd314e91afcec122eb8631 |
| tree | b47079e19cee86e8f244be48dd29b0666336743d |
| parent | 2e692312f104e1e5533c9f389d73488ea4a1ef68 |
* no need to move `tmpFilePath` around
* no need for calculating max length of `FileExt` tag name
* provide a canonical file extension name for `FileExt` so that, e.g.
the file will be named `stdin.S` instead of
`stdin.assembly_with_cpp`.
* move temp file cleanup to a function to reduce defer bloat in a large
function.
* fix bug caused by mixing relative and absolute paths in the cleanup
logic.
* remove commented out test and dead code4 files changed, 62 insertions(+), 134 deletions(-)
lib/std/Build/Cache.zig-10| ... | ... | @@ -31,16 +31,6 @@ pub const Directory = struct { |
| 31 | 31 | } |
| 32 | 32 | } |
| 33 | 33 | |
| 34 | pub fn tmpFilePath(self: Directory, ally: Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 { | |
| 35 | const s = std.fs.path.sep_str; | |
| 36 | const rand_int = std.crypto.random.int(u64); | |
| 37 | if (self.path) |p| { | |
| 38 | return std.fmt.allocPrint(ally, "{s}" ++ s ++ "tmp" ++ s ++ "{x}-{s}", .{ p, rand_int, suffix }); | |
| 39 | } else { | |
| 40 | return std.fmt.allocPrint(ally, "tmp" ++ s ++ "{x}-{s}", .{ rand_int, suffix }); | |
| 41 | } | |
| 42 | } | |
| 43 | ||
| 44 | 34 | /// Whether or not the handle should be closed, or the path should be freed |
| 45 | 35 | /// is determined by usage, however this function is provided for convenience |
| 46 | 36 | /// if it happens to be what the caller needs. |
src/Compilation.zig+31-8| ... | ... | @@ -3981,7 +3981,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P |
| 3981 | 3981 | |
| 3982 | 3982 | // We can't know the digest until we do the C compiler invocation, |
| 3983 | 3983 | // so we need a temporary filename. |
| 3984 | const out_obj_path = try comp.local_cache_directory.tmpFilePath(arena, o_basename); | |
| 3984 | const out_obj_path = try comp.tmpFilePath(arena, o_basename); | |
| 3985 | 3985 | var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{}); |
| 3986 | 3986 | defer zig_cache_tmp_dir.close(); |
| 3987 | 3987 | |
| ... | ... | @@ -4129,6 +4129,16 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P |
| 4129 | 4129 | }; |
| 4130 | 4130 | } |
| 4131 | 4131 | |
| 4132 | pub fn tmpFilePath(comp: *Compilation, ally: Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 { | |
| 4133 | const s = std.fs.path.sep_str; | |
| 4134 | const rand_int = std.crypto.random.int(u64); | |
| 4135 | if (comp.local_cache_directory.path) |p| { | |
| 4136 | return std.fmt.allocPrint(ally, "{s}" ++ s ++ "tmp" ++ s ++ "{x}-{s}", .{ p, rand_int, suffix }); | |
| 4137 | } else { | |
| 4138 | return std.fmt.allocPrint(ally, "tmp" ++ s ++ "{x}-{s}", .{ rand_int, suffix }); | |
| 4139 | } | |
| 4140 | } | |
| 4141 | ||
| 4132 | 4142 | pub fn addTranslateCCArgs( |
| 4133 | 4143 | comp: *Compilation, |
| 4134 | 4144 | arena: Allocator, |
| ... | ... | @@ -4588,13 +4598,26 @@ pub const FileExt = enum { |
| 4588 | 4598 | }; |
| 4589 | 4599 | } |
| 4590 | 4600 | |
| 4591 | // maximum length of @tagName(ext: FileExt) | |
| 4592 | pub const max_len = blk: { | |
| 4593 | var max: u16 = 0; | |
| 4594 | inline for (std.meta.tags(FileExt)) |ext| | |
| 4595 | max = std.math.max(@tagName(ext).len, max); | |
| 4596 | break :blk max; | |
| 4597 | }; | |
| 4601 | pub fn canonicalName(ext: FileExt, target: Target) [:0]const u8 { | |
| 4602 | return switch (ext) { | |
| 4603 | .c => ".c", | |
| 4604 | .cpp => ".cpp", | |
| 4605 | .cu => ".cu", | |
| 4606 | .h => ".h", | |
| 4607 | .m => ".m", | |
| 4608 | .mm => ".mm", | |
| 4609 | .ll => ".ll", | |
| 4610 | .bc => ".bc", | |
| 4611 | .assembly => ".s", | |
| 4612 | .assembly_with_cpp => ".S", | |
| 4613 | .shared_library => target.dynamicLibSuffix(), | |
| 4614 | .object => target.ofmt.fileExt(target.cpu.arch), | |
| 4615 | .static_library => target.staticLibSuffix(), | |
| 4616 | .zig => ".zig", | |
| 4617 | .def => ".def", | |
| 4618 | .unknown => "", | |
| 4619 | }; | |
| 4620 | } | |
| 4598 | 4621 | }; |
| 4599 | 4622 | |
| 4600 | 4623 | pub fn hasObjectExt(filename: []const u8) bool { |
src/main.zig+31-23| ... | ... | @@ -705,6 +705,17 @@ const ArgsIterator = struct { |
| 705 | 705 | } |
| 706 | 706 | }; |
| 707 | 707 | |
| 708 | fn cleanupTempStdinFile( | |
| 709 | temp_stdin_file: ?[]const u8, | |
| 710 | local_cache_directory: Compilation.Directory, | |
| 711 | ) void { | |
| 712 | if (temp_stdin_file) |file| { | |
| 713 | // Some garbage may stay in the file system if removal fails; this | |
| 714 | // is harmless so no warning is needed. | |
| 715 | local_cache_directory.handle.deleteFile(file) catch {}; | |
| 716 | } | |
| 717 | } | |
| 718 | ||
| 708 | 719 | fn buildOutputType( |
| 709 | 720 | gpa: Allocator, |
| 710 | 721 | arena: Allocator, |
| ... | ... | @@ -3021,15 +3032,11 @@ fn buildOutputType( |
| 3021 | 3032 | }; |
| 3022 | 3033 | |
| 3023 | 3034 | var temp_stdin_file: ?[]const u8 = null; |
| 3024 | defer { | |
| 3025 | if (temp_stdin_file) |file| { | |
| 3026 | // some garbage may stay in the file system if removal fails. | |
| 3027 | // Alternatively, we could tell the user that the removal failed, | |
| 3028 | // but it's not as much of a deal: it's a temporary cache directory | |
| 3029 | // at all. | |
| 3030 | local_cache_directory.handle.deleteFile(file) catch {}; | |
| 3031 | } | |
| 3032 | } | |
| 3035 | // Note that in one of the happy paths, execve() is used to switch to clang | |
| 3036 | // in which case this cleanup logic does not run and this temp file is | |
| 3037 | // leaked. Oh well. It's a minor punishment for using `-x c` which nobody | |
| 3038 | // should be doing. | |
| 3039 | defer cleanupTempStdinFile(temp_stdin_file, local_cache_directory); | |
| 3033 | 3040 | |
| 3034 | 3041 | for (c_source_files.items) |*src| { |
| 3035 | 3042 | if (!mem.eql(u8, src.src_path, "-")) continue; |
| ... | ... | @@ -3038,21 +3045,22 @@ fn buildOutputType( |
| 3038 | 3045 | fatal("-E or -x is required when reading from a non-regular file", .{}); |
| 3039 | 3046 | |
| 3040 | 3047 | // "-" is stdin. Dump it to a real file. |
| 3041 | const new_file = blk: { | |
| 3042 | var buf: ["stdin.".len + Compilation.FileExt.max_len]u8 = undefined; | |
| 3043 | const fname = try std.fmt.bufPrint(&buf, "stdin.{s}", .{@tagName(ext)}); | |
| 3044 | const new_name = try local_cache_directory.tmpFilePath(arena, fname); | |
| 3045 | ||
| 3048 | const sub_path = blk: { | |
| 3049 | const sep = fs.path.sep_str; | |
| 3050 | const sub_path = try std.fmt.allocPrint(arena, "tmp" ++ sep ++ "{x}-stdin{s}", .{ | |
| 3051 | std.crypto.random.int(u64), ext.canonicalName(target_info.target), | |
| 3052 | }); | |
| 3046 | 3053 | try local_cache_directory.handle.makePath("tmp"); |
| 3047 | var outfile = try local_cache_directory.handle.createFile(new_name, .{}); | |
| 3048 | defer outfile.close(); | |
| 3049 | errdefer local_cache_directory.handle.deleteFile(new_name) catch {}; | |
| 3050 | ||
| 3051 | try outfile.writeFileAll(io.getStdIn(), .{}); | |
| 3052 | break :blk new_name; | |
| 3054 | var f = try local_cache_directory.handle.createFile(sub_path, .{}); | |
| 3055 | defer f.close(); | |
| 3056 | errdefer local_cache_directory.handle.deleteFile(sub_path) catch {}; | |
| 3057 | try f.writeFileAll(io.getStdIn(), .{}); | |
| 3058 | break :blk sub_path; | |
| 3053 | 3059 | }; |
| 3054 | temp_stdin_file = new_file; | |
| 3055 | src.src_path = new_file; | |
| 3060 | // Relative to `local_cache_directory`. | |
| 3061 | temp_stdin_file = sub_path; | |
| 3062 | // Relative to current working directory. | |
| 3063 | src.src_path = try local_cache_directory.join(arena, &.{sub_path}); | |
| 3056 | 3064 | } |
| 3057 | 3065 | |
| 3058 | 3066 | if (build_options.have_llvm and emit_asm != .no) { |
| ... | ... | @@ -3908,7 +3916,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Translate |
| 3908 | 3916 | |
| 3909 | 3917 | const c_src_basename = fs.path.basename(c_source_file.src_path); |
| 3910 | 3918 | const dep_basename = try std.fmt.allocPrint(arena, "{s}.d", .{c_src_basename}); |
| 3911 | const out_dep_path = try comp.local_cache_directory.tmpFilePath(arena, dep_basename); | |
| 3919 | const out_dep_path = try comp.tmpFilePath(arena, dep_basename); | |
| 3912 | 3920 | break :blk out_dep_path; |
| 3913 | 3921 | }; |
| 3914 | 3922 |
test/tests.zig-93| ... | ... | @@ -777,52 +777,6 @@ pub fn addCliTests(b: *std.Build) *Step { |
| 777 | 777 | step.dependOn(&cleanup.step); |
| 778 | 778 | } |
| 779 | 779 | |
| 780 | // Test `zig cc -x c -` | |
| 781 | // Test author was not able to figure out how to start a child process and | |
| 782 | // give an fd to it's stdin. fork/exec works, but we are limiting ourselves | |
| 783 | // to POSIX. | |
| 784 | // | |
| 785 | // TODO: the "zig cc <..." step should be a RunStep.create(...) | |
| 786 | // However, how do I create a command (RunStep) that invokes a command | |
| 787 | // with a specific file descriptor in the stdin? | |
| 788 | //if (builtin.os.tag != .windows) { | |
| 789 | // const tmp_path = b.makeTempPath(); | |
| 790 | // var dir = std.fs.cwd().openDir(tmp_path, .{}) catch @panic("unhandled"); | |
| 791 | // dir.writeFile("truth.c", "int main() { return 42; }") catch @panic("unhandled"); | |
| 792 | // var infile = dir.openFile("truth.c", .{}) catch @panic("unhandled"); | |
| 793 | ||
| 794 | // const outfile = std.fs.path.joinZ( | |
| 795 | // b.allocator, | |
| 796 | // &[_][]const u8{ tmp_path, "truth" }, | |
| 797 | // ) catch @panic("unhandled"); | |
| 798 | ||
| 799 | // const pid_result = std.os.fork() catch @panic("unhandled"); | |
| 800 | // if (pid_result == 0) { // child | |
| 801 | // std.os.dup2(infile.handle, std.os.STDIN_FILENO) catch @panic("unhandled"); | |
| 802 | // const argv = &[_:null]?[*:0]const u8{ | |
| 803 | // b.zig_exe, "cc", | |
| 804 | // "-o", outfile, | |
| 805 | // "-x", "c", | |
| 806 | // "-", | |
| 807 | // }; | |
| 808 | // const envp = &[_:null]?[*:0]const u8{ | |
| 809 | // std.fmt.allocPrintZ(b.allocator, "ZIG_GLOBAL_CACHE_DIR={s}", .{tmp_path}) catch @panic("unhandled"), | |
| 810 | // }; | |
| 811 | // const err = std.os.execveZ(b.zig_exe, argv, envp); | |
| 812 | // std.debug.print("execve error: {any}\n", .{err}); | |
| 813 | // std.os.exit(1); | |
| 814 | // } | |
| 815 | ||
| 816 | // const res = std.os.waitpid(pid_result, 0); | |
| 817 | // assert(0 == res.status); | |
| 818 | ||
| 819 | // // run the compiled executable and check if it's telling the truth. | |
| 820 | // _ = exec(b.allocator, tmp_path, 42, &[_][]const u8{outfile}) catch @panic("unhandled"); | |
| 821 | ||
| 822 | // const cleanup = b.addRemoveDirTree(tmp_path); | |
| 823 | // step.dependOn(&cleanup.step); | |
| 824 | //} | |
| 825 | ||
| 826 | 780 | { |
| 827 | 781 | // Test `zig fmt`. |
| 828 | 782 | // This test must use a temporary directory rather than a cache |
| ... | ... | @@ -1200,50 +1154,3 @@ pub fn addCases( |
| 1200 | 1154 | check_case_exe, |
| 1201 | 1155 | ); |
| 1202 | 1156 | } |
| 1203 | ||
| 1204 | fn exec( | |
| 1205 | allocator: std.mem.Allocator, | |
| 1206 | cwd: []const u8, | |
| 1207 | expect_code: u8, | |
| 1208 | argv: []const []const u8, | |
| 1209 | ) !std.ChildProcess.ExecResult { | |
| 1210 | const max_output_size = 100 * 1024; | |
| 1211 | const result = std.ChildProcess.exec(.{ | |
| 1212 | .allocator = allocator, | |
| 1213 | .argv = argv, | |
| 1214 | .cwd = cwd, | |
| 1215 | .max_output_bytes = max_output_size, | |
| 1216 | }) catch |err| { | |
| 1217 | std.debug.print("The following command failed:\n", .{}); | |
| 1218 | printCmd(cwd, argv); | |
| 1219 | return err; | |
| 1220 | }; | |
| 1221 | switch (result.term) { | |
| 1222 | .Exited => |code| { | |
| 1223 | if (code != expect_code) { | |
| 1224 | std.debug.print( | |
| 1225 | "The following command exited with error code {}, expected {}:\n", | |
| 1226 | .{ code, expect_code }, | |
| 1227 | ); | |
| 1228 | printCmd(cwd, argv); | |
| 1229 | std.debug.print("stderr:\n{s}\n", .{result.stderr}); | |
| 1230 | return error.CommandFailed; | |
| 1231 | } | |
| 1232 | }, | |
| 1233 | else => { | |
| 1234 | std.debug.print("The following command terminated unexpectedly:\n", .{}); | |
| 1235 | printCmd(cwd, argv); | |
| 1236 | std.debug.print("stderr:\n{s}\n", .{result.stderr}); | |
| 1237 | return error.CommandFailed; | |
| 1238 | }, | |
| 1239 | } | |
| 1240 | return result; | |
| 1241 | } | |
| 1242 | ||
| 1243 | fn printCmd(cwd: []const u8, argv: []const []const u8) void { | |
| 1244 | std.debug.print("cd {s} && ", .{cwd}); | |
| 1245 | for (argv) |arg| { | |
| 1246 | std.debug.print("{s} ", .{arg}); | |
| 1247 | } | |
| 1248 | std.debug.print("\n", .{}); | |
| 1249 | } |