| author | |
| committer | |
| log | 2e692312f104e1e5533c9f389d73488ea4a1ef68 |
| tree | 41c075be8388dc374bfd2f01973a6f8dfb612939 |
| parent | b754068fbc7492962953068d31386d4c04e37ae5 |
echo 'some C program' | $CC -x c -
Is a common pattern to test for compiler or linker features. This patch
adds support for reading from non-regular files.
This will make at least one more Go test to pass.4 files changed, 148 insertions(+), 12 deletions(-)
lib/std/Build/Cache.zig+10| ... | ... | @@ -31,6 +31,16 @@ 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 | ||
| 34 | 44 | /// Whether or not the handle should be closed, or the path should be freed |
| 35 | 45 | /// is determined by usage, however this function is provided for convenience |
| 36 | 46 | /// if it happens to be what the caller needs. |
src/Compilation.zig+9-11| ... | ... | @@ -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.tmpFilePath(arena, o_basename); | |
| 3984 | const out_obj_path = try comp.local_cache_directory.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,16 +4129,6 @@ 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 | ||
| 4142 | 4132 | pub fn addTranslateCCArgs( |
| 4143 | 4133 | comp: *Compilation, |
| 4144 | 4134 | arena: Allocator, |
| ... | ... | @@ -4597,6 +4587,14 @@ pub const FileExt = enum { |
| 4597 | 4587 | => false, |
| 4598 | 4588 | }; |
| 4599 | 4589 | } |
| 4590 | ||
| 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 | }; | |
| 4600 | 4598 | }; |
| 4601 | 4599 | |
| 4602 | 4600 | pub fn hasObjectExt(filename: []const u8) bool { |
src/main.zig+36-1| ... | ... | @@ -3020,6 +3020,41 @@ fn buildOutputType( |
| 3020 | 3020 | break :l global_cache_directory; |
| 3021 | 3021 | }; |
| 3022 | 3022 | |
| 3023 | 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 | } | |
| 3033 | ||
| 3034 | for (c_source_files.items) |*src| { | |
| 3035 | if (!mem.eql(u8, src.src_path, "-")) continue; | |
| 3036 | ||
| 3037 | const ext = src.ext orelse | |
| 3038 | fatal("-E or -x is required when reading from a non-regular file", .{}); | |
| 3039 | ||
| 3040 | // "-" 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 | ||
| 3046 | 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; | |
| 3053 | }; | |
| 3054 | temp_stdin_file = new_file; | |
| 3055 | src.src_path = new_file; | |
| 3056 | } | |
| 3057 | ||
| 3023 | 3058 | if (build_options.have_llvm and emit_asm != .no) { |
| 3024 | 3059 | // LLVM has no way to set this non-globally. |
| 3025 | 3060 | const argv = [_][*:0]const u8{ "zig (LLVM option parsing)", "--x86-asm-syntax=intel" }; |
| ... | ... | @@ -3873,7 +3908,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Translate |
| 3873 | 3908 | |
| 3874 | 3909 | const c_src_basename = fs.path.basename(c_source_file.src_path); |
| 3875 | 3910 | const dep_basename = try std.fmt.allocPrint(arena, "{s}.d", .{c_src_basename}); |
| 3876 | const out_dep_path = try comp.tmpFilePath(arena, dep_basename); | |
| 3911 | const out_dep_path = try comp.local_cache_directory.tmpFilePath(arena, dep_basename); | |
| 3877 | 3912 | break :blk out_dep_path; |
| 3878 | 3913 | }; |
| 3879 | 3914 |
test/tests.zig+93| ... | ... | @@ -777,6 +777,52 @@ 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 | ||
| 780 | 826 | { |
| 781 | 827 | // Test `zig fmt`. |
| 782 | 828 | // This test must use a temporary directory rather than a cache |
| ... | ... | @@ -1154,3 +1200,50 @@ pub fn addCases( |
| 1154 | 1200 | check_case_exe, |
| 1155 | 1201 | ); |
| 1156 | 1202 | } |
| 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 | } |