| 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,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 | /// Whether or not the handle should be closed, or the path should be freed | 34 | /// Whether or not the handle should be closed, or the path should be freed |
| 45 | /// is determined by usage, however this function is provided for convenience | 35 | /// is determined by usage, however this function is provided for convenience |
| 46 | /// if it happens to be what the caller needs. | 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,7 +3981,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P |
| 3981 | 3981 | ||
| 3982 | // We can't know the digest until we do the C compiler invocation, | 3982 | // We can't know the digest until we do the C compiler invocation, |
| 3983 | // so we need a temporary filename. | 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 | var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{}); | 3985 | var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{}); |
| 3986 | defer zig_cache_tmp_dir.close(); | 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,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 | pub fn addTranslateCCArgs( | 4142 | pub fn addTranslateCCArgs( |
| 4133 | comp: *Compilation, | 4143 | comp: *Compilation, |
| 4134 | arena: Allocator, | 4144 | arena: Allocator, |
| ... | @@ -4588,13 +4598,26 @@ pub const FileExt = enum { | ... | @@ -4588,13 +4598,26 @@ pub const FileExt = enum { |
| 4588 | }; | 4598 | }; |
| 4589 | } | 4599 | } |
| 4590 | 4600 | ||
| 4591 | // maximum length of @tagName(ext: FileExt) | 4601 | pub fn canonicalName(ext: FileExt, target: Target) [:0]const u8 { |
| 4592 | pub const max_len = blk: { | 4602 | return switch (ext) { |
| 4593 | var max: u16 = 0; | 4603 | .c => ".c", |
| 4594 | inline for (std.meta.tags(FileExt)) |ext| | 4604 | .cpp => ".cpp", |
| 4595 | max = std.math.max(@tagName(ext).len, max); | 4605 | .cu => ".cu", |
| 4596 | break :blk max; | 4606 | .h => ".h", |
| 4597 | }; | 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 | pub fn hasObjectExt(filename: []const u8) bool { | 4623 | pub fn hasObjectExt(filename: []const u8) bool { |
src/main.zig+31-23| ... | @@ -705,6 +705,17 @@ const ArgsIterator = struct { | ... | @@ -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 | fn buildOutputType( | 719 | fn buildOutputType( |
| 709 | gpa: Allocator, | 720 | gpa: Allocator, |
| 710 | arena: Allocator, | 721 | arena: Allocator, |
| ... | @@ -3021,15 +3032,11 @@ fn buildOutputType( | ... | @@ -3021,15 +3032,11 @@ fn buildOutputType( |
| 3021 | }; | 3032 | }; |
| 3022 | 3033 | ||
| 3023 | var temp_stdin_file: ?[]const u8 = null; | 3034 | var temp_stdin_file: ?[]const u8 = null; |
| 3024 | defer { | 3035 | // Note that in one of the happy paths, execve() is used to switch to clang |
| 3025 | if (temp_stdin_file) |file| { | 3036 | // in which case this cleanup logic does not run and this temp file is |
| 3026 | // some garbage may stay in the file system if removal fails. | 3037 | // leaked. Oh well. It's a minor punishment for using `-x c` which nobody |
| 3027 | // Alternatively, we could tell the user that the removal failed, | 3038 | // should be doing. |
| 3028 | // but it's not as much of a deal: it's a temporary cache directory | 3039 | defer cleanupTempStdinFile(temp_stdin_file, local_cache_directory); |
| 3029 | // at all. | ||
| 3030 | local_cache_directory.handle.deleteFile(file) catch {}; | ||
| 3031 | } | ||
| 3032 | } | ||
| 3033 | 3040 | ||
| 3034 | for (c_source_files.items) |*src| { | 3041 | for (c_source_files.items) |*src| { |
| 3035 | if (!mem.eql(u8, src.src_path, "-")) continue; | 3042 | if (!mem.eql(u8, src.src_path, "-")) continue; |
| ... | @@ -3038,21 +3045,22 @@ fn buildOutputType( | ... | @@ -3038,21 +3045,22 @@ fn buildOutputType( |
| 3038 | fatal("-E or -x is required when reading from a non-regular file", .{}); | 3045 | fatal("-E or -x is required when reading from a non-regular file", .{}); |
| 3039 | 3046 | ||
| 3040 | // "-" is stdin. Dump it to a real file. | 3047 | // "-" is stdin. Dump it to a real file. |
| 3041 | const new_file = blk: { | 3048 | const sub_path = blk: { |
| 3042 | var buf: ["stdin.".len + Compilation.FileExt.max_len]u8 = undefined; | 3049 | const sep = fs.path.sep_str; |
| 3043 | const fname = try std.fmt.bufPrint(&buf, "stdin.{s}", .{@tagName(ext)}); | 3050 | const sub_path = try std.fmt.allocPrint(arena, "tmp" ++ sep ++ "{x}-stdin{s}", .{ |
| 3044 | const new_name = try local_cache_directory.tmpFilePath(arena, fname); | 3051 | std.crypto.random.int(u64), ext.canonicalName(target_info.target), |
| 3045 | 3052 | }); | |
| 3046 | try local_cache_directory.handle.makePath("tmp"); | 3053 | try local_cache_directory.handle.makePath("tmp"); |
| 3047 | var outfile = try local_cache_directory.handle.createFile(new_name, .{}); | 3054 | var f = try local_cache_directory.handle.createFile(sub_path, .{}); |
| 3048 | defer outfile.close(); | 3055 | defer f.close(); |
| 3049 | errdefer local_cache_directory.handle.deleteFile(new_name) catch {}; | 3056 | errdefer local_cache_directory.handle.deleteFile(sub_path) catch {}; |
| 3050 | 3057 | try f.writeFileAll(io.getStdIn(), .{}); | |
| 3051 | try outfile.writeFileAll(io.getStdIn(), .{}); | 3058 | break :blk sub_path; |
| 3052 | break :blk new_name; | ||
| 3053 | }; | 3059 | }; |
| 3054 | temp_stdin_file = new_file; | 3060 | // Relative to `local_cache_directory`. |
| 3055 | src.src_path = new_file; | 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 | if (build_options.have_llvm and emit_asm != .no) { | 3066 | if (build_options.have_llvm and emit_asm != .no) { |
| ... | @@ -3908,7 +3916,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Translate | ... | @@ -3908,7 +3916,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Translate |
| 3908 | 3916 | ||
| 3909 | const c_src_basename = fs.path.basename(c_source_file.src_path); | 3917 | const c_src_basename = fs.path.basename(c_source_file.src_path); |
| 3910 | const dep_basename = try std.fmt.allocPrint(arena, "{s}.d", .{c_src_basename}); | 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 | break :blk out_dep_path; | 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,52 +777,6 @@ pub fn addCliTests(b: *std.Build) *Step { |
| 777 | step.dependOn(&cleanup.step); | 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 | // Test `zig fmt`. | 781 | // Test `zig fmt`. |
| 828 | // This test must use a temporary directory rather than a cache | 782 | // This test must use a temporary directory rather than a cache |
| ... | @@ -1200,50 +1154,3 @@ pub fn addCases( | ... | @@ -1200,50 +1154,3 @@ pub fn addCases( |
| 1200 | check_case_exe, | 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 | } |