| author | |
| committer | |
| log | 26f2f9bf1c774caf246317b3fc032449e982a150 |
| tree | 43bc4d4b19cea9a245d87f105841d075ab75f5ab |
| parent | 9b83112a1f6af758a1a995ea8838a2319d2fbc1e |
we are now passing the cli tests12 files changed, 137 insertions(+), 102 deletions(-)
BRANCH_TODO-1| ... | ... | @@ -1,4 +1,3 @@ |
| 1 | * support -fno-emit-bin for godbolt | |
| 2 | 1 | * restore the legacy -femit-h feature using the stage1 backend |
| 3 | 2 | * figure out why test-translate-c is failing |
| 4 | 3 | * tests passing with -Dskip-non-native |
src/Compilation.zig+73-56| ... | ... | @@ -500,8 +500,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 500 | 500 | break :pic explicit; |
| 501 | 501 | } else must_pic; |
| 502 | 502 | |
| 503 | const emit_bin = options.emit_bin orelse fatal("-fno-emit-bin not supported yet", .{}); // TODO | |
| 504 | ||
| 505 | 503 | // Make a decision on whether to use Clang for translate-c and compiling C files. |
| 506 | 504 | const use_clang = if (options.use_clang) |explicit| explicit else blk: { |
| 507 | 505 | if (build_options.have_llvm) { |
| ... | ... | @@ -667,13 +665,29 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 667 | 665 | } else null; |
| 668 | 666 | errdefer if (module) |zm| zm.deinit(); |
| 669 | 667 | |
| 668 | const error_return_tracing = !options.strip and switch (options.optimize_mode) { | |
| 669 | .Debug, .ReleaseSafe => true, | |
| 670 | .ReleaseFast, .ReleaseSmall => false, | |
| 671 | }; | |
| 672 | ||
| 670 | 673 | // For resource management purposes. |
| 671 | 674 | var owned_link_dir: ?std.fs.Dir = null; |
| 672 | 675 | errdefer if (owned_link_dir) |*dir| dir.close(); |
| 673 | 676 | |
| 674 | const bin_directory = emit_bin.directory orelse blk: { | |
| 675 | if (module) |zm| break :blk zm.zig_cache_artifact_directory; | |
| 676 | ||
| 677 | const bin_file_emit: ?link.Emit = blk: { | |
| 678 | const emit_bin = options.emit_bin orelse break :blk null; | |
| 679 | if (emit_bin.directory) |directory| { | |
| 680 | break :blk link.Emit{ | |
| 681 | .directory = directory, | |
| 682 | .sub_path = emit_bin.basename, | |
| 683 | }; | |
| 684 | } | |
| 685 | if (module) |zm| { | |
| 686 | break :blk link.Emit{ | |
| 687 | .directory = zm.zig_cache_artifact_directory, | |
| 688 | .sub_path = emit_bin.basename, | |
| 689 | }; | |
| 690 | } | |
| 677 | 691 | // We could use the cache hash as is no problem, however, we increase |
| 678 | 692 | // the likelihood of cache hits by adding the first C source file |
| 679 | 693 | // path name (not contents) to the hash. This way if the user is compiling |
| ... | ... | @@ -694,17 +708,14 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 694 | 708 | .handle = artifact_dir, |
| 695 | 709 | .path = try options.local_cache_directory.join(arena, &[_][]const u8{artifact_sub_dir}), |
| 696 | 710 | }; |
| 697 | break :blk link_artifact_directory; | |
| 698 | }; | |
| 699 | ||
| 700 | const error_return_tracing = !options.strip and switch (options.optimize_mode) { | |
| 701 | .Debug, .ReleaseSafe => true, | |
| 702 | .ReleaseFast, .ReleaseSmall => false, | |
| 711 | break :blk link.Emit{ | |
| 712 | .directory = link_artifact_directory, | |
| 713 | .sub_path = emit_bin.basename, | |
| 714 | }; | |
| 703 | 715 | }; |
| 704 | 716 | |
| 705 | 717 | const bin_file = try link.File.openPath(gpa, .{ |
| 706 | .directory = bin_directory, | |
| 707 | .sub_path = emit_bin.basename, | |
| 718 | .emit = bin_file_emit, | |
| 708 | 719 | .root_name = root_name, |
| 709 | 720 | .module = module, |
| 710 | 721 | .target = options.target, |
| ... | ... | @@ -815,43 +826,46 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 815 | 826 | comp.c_object_table.putAssumeCapacityNoClobber(c_object, {}); |
| 816 | 827 | } |
| 817 | 828 | |
| 818 | // If we need to build glibc for the target, add work items for it. | |
| 819 | // We go through the work queue so that building can be done in parallel. | |
| 820 | if (comp.wantBuildGLibCFromSource()) { | |
| 821 | try comp.addBuildingGLibCJobs(); | |
| 822 | } | |
| 823 | if (comp.wantBuildMuslFromSource()) { | |
| 824 | try comp.work_queue.write(&[_]Job{ | |
| 825 | .{ .musl_crt_file = .crti_o }, | |
| 826 | .{ .musl_crt_file = .crtn_o }, | |
| 827 | .{ .musl_crt_file = .crt1_o }, | |
| 828 | .{ .musl_crt_file = .scrt1_o }, | |
| 829 | .{ .musl_crt_file = .libc_a }, | |
| 830 | }); | |
| 831 | } | |
| 832 | if (comp.wantBuildMinGWW64FromSource()) { | |
| 833 | @panic("TODO"); | |
| 834 | } | |
| 835 | if (comp.wantBuildLibUnwindFromSource()) { | |
| 836 | try comp.work_queue.writeItem(.{ .libunwind = {} }); | |
| 837 | } | |
| 838 | if (build_options.have_llvm and comp.bin_file.options.output_mode != .Obj and | |
| 839 | comp.bin_file.options.link_libcpp) | |
| 840 | { | |
| 841 | try comp.work_queue.writeItem(.libcxx); | |
| 842 | try comp.work_queue.writeItem(.libcxxabi); | |
| 829 | if (comp.bin_file.options.emit != null) { | |
| 830 | // If we need to build glibc for the target, add work items for it. | |
| 831 | // We go through the work queue so that building can be done in parallel. | |
| 832 | if (comp.wantBuildGLibCFromSource()) { | |
| 833 | try comp.addBuildingGLibCJobs(); | |
| 834 | } | |
| 835 | if (comp.wantBuildMuslFromSource()) { | |
| 836 | try comp.work_queue.write(&[_]Job{ | |
| 837 | .{ .musl_crt_file = .crti_o }, | |
| 838 | .{ .musl_crt_file = .crtn_o }, | |
| 839 | .{ .musl_crt_file = .crt1_o }, | |
| 840 | .{ .musl_crt_file = .scrt1_o }, | |
| 841 | .{ .musl_crt_file = .libc_a }, | |
| 842 | }); | |
| 843 | } | |
| 844 | if (comp.wantBuildMinGWW64FromSource()) { | |
| 845 | @panic("TODO"); | |
| 846 | } | |
| 847 | if (comp.wantBuildLibUnwindFromSource()) { | |
| 848 | try comp.work_queue.writeItem(.{ .libunwind = {} }); | |
| 849 | } | |
| 850 | if (build_options.have_llvm and comp.bin_file.options.output_mode != .Obj and | |
| 851 | comp.bin_file.options.link_libcpp) | |
| 852 | { | |
| 853 | try comp.work_queue.writeItem(.libcxx); | |
| 854 | try comp.work_queue.writeItem(.libcxxabi); | |
| 855 | } | |
| 856 | if (is_exe_or_dyn_lib and !comp.bin_file.options.is_compiler_rt_or_libc and | |
| 857 | build_options.is_stage1) | |
| 858 | { | |
| 859 | try comp.work_queue.writeItem(.{ .libcompiler_rt = {} }); | |
| 860 | if (!comp.bin_file.options.link_libc) { | |
| 861 | try comp.work_queue.writeItem(.{ .zig_libc = {} }); | |
| 862 | } | |
| 863 | } | |
| 843 | 864 | } |
| 865 | ||
| 844 | 866 | if (build_options.is_stage1 and comp.bin_file.options.use_llvm) { |
| 845 | 867 | try comp.work_queue.writeItem(.{ .stage1_module = {} }); |
| 846 | 868 | } |
| 847 | if (is_exe_or_dyn_lib and !comp.bin_file.options.is_compiler_rt_or_libc and | |
| 848 | build_options.is_stage1) | |
| 849 | { | |
| 850 | try comp.work_queue.writeItem(.{ .libcompiler_rt = {} }); | |
| 851 | if (!comp.bin_file.options.link_libc) { | |
| 852 | try comp.work_queue.writeItem(.{ .zig_libc = {} }); | |
| 853 | } | |
| 854 | } | |
| 855 | 869 | |
| 856 | 870 | return comp; |
| 857 | 871 | } |
| ... | ... | @@ -2408,8 +2422,8 @@ fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CR |
| 2408 | 2422 | |
| 2409 | 2423 | assert(out.* == null); |
| 2410 | 2424 | out.* = Compilation.CRTFile{ |
| 2411 | .full_object_path = try sub_compilation.bin_file.options.directory.join(comp.gpa, &[_][]const u8{ | |
| 2412 | sub_compilation.bin_file.options.sub_path, | |
| 2425 | .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{ | |
| 2426 | sub_compilation.bin_file.options.emit.?.sub_path, | |
| 2413 | 2427 | }), |
| 2414 | 2428 | .lock = sub_compilation.bin_file.toOwnedLock(), |
| 2415 | 2429 | }; |
| ... | ... | @@ -2452,6 +2466,7 @@ fn updateStage1Module(comp: *Compilation) !void { |
| 2452 | 2466 | man.hash.add(comp.bin_file.options.dll_export_fns); |
| 2453 | 2467 | man.hash.add(comp.bin_file.options.function_sections); |
| 2454 | 2468 | man.hash.add(comp.is_test); |
| 2469 | man.hash.add(comp.bin_file.options.emit != null); | |
| 2455 | 2470 | man.hash.add(comp.emit_h != null); |
| 2456 | 2471 | man.hash.add(comp.emit_asm != null); |
| 2457 | 2472 | man.hash.add(comp.emit_llvm_ir != null); |
| ... | ... | @@ -2517,12 +2532,14 @@ fn updateStage1Module(comp: *Compilation) !void { |
| 2517 | 2532 | comp.is_test, |
| 2518 | 2533 | ) orelse return error.OutOfMemory; |
| 2519 | 2534 | |
| 2520 | const bin_basename = try std.zig.binNameAlloc(arena, .{ | |
| 2521 | .root_name = comp.bin_file.options.root_name, | |
| 2522 | .target = target, | |
| 2523 | .output_mode = .Obj, | |
| 2524 | }); | |
| 2525 | const emit_bin_path = try directory.join(arena, &[_][]const u8{bin_basename}); | |
| 2535 | const emit_bin_path = if (comp.bin_file.options.emit != null) blk: { | |
| 2536 | const bin_basename = try std.zig.binNameAlloc(arena, .{ | |
| 2537 | .root_name = comp.bin_file.options.root_name, | |
| 2538 | .target = target, | |
| 2539 | .output_mode = .Obj, | |
| 2540 | }); | |
| 2541 | break :blk try directory.join(arena, &[_][]const u8{bin_basename}); | |
| 2542 | } else ""; | |
| 2526 | 2543 | const emit_h_path = try stage1LocPath(arena, comp.emit_h, directory); |
| 2527 | 2544 | const emit_asm_path = try stage1LocPath(arena, comp.emit_asm, directory); |
| 2528 | 2545 | const emit_llvm_ir_path = try stage1LocPath(arena, comp.emit_llvm_ir, directory); |
| ... | ... | @@ -2697,8 +2714,8 @@ pub fn build_crt_file( |
| 2697 | 2714 | try comp.crt_files.ensureCapacity(comp.gpa, comp.crt_files.count() + 1); |
| 2698 | 2715 | |
| 2699 | 2716 | comp.crt_files.putAssumeCapacityNoClobber(basename, .{ |
| 2700 | .full_object_path = try sub_compilation.bin_file.options.directory.join(comp.gpa, &[_][]const u8{ | |
| 2701 | sub_compilation.bin_file.options.sub_path, | |
| 2717 | .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{ | |
| 2718 | sub_compilation.bin_file.options.emit.?.sub_path, | |
| 2702 | 2719 | }), |
| 2703 | 2720 | .lock = sub_compilation.bin_file.toOwnedLock(), |
| 2704 | 2721 | }); |
src/libcxx.zig+8-2| ... | ... | @@ -189,7 +189,10 @@ pub fn buildLibCXX(comp: *Compilation) !void { |
| 189 | 189 | |
| 190 | 190 | assert(comp.libcxx_static_lib == null); |
| 191 | 191 | comp.libcxx_static_lib = Compilation.CRTFile{ |
| 192 | .full_object_path = try sub_compilation.bin_file.options.directory.join(comp.gpa, &[_][]const u8{basename}), | |
| 192 | .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join( | |
| 193 | comp.gpa, | |
| 194 | &[_][]const u8{basename}, | |
| 195 | ), | |
| 193 | 196 | .lock = sub_compilation.bin_file.toOwnedLock(), |
| 194 | 197 | }; |
| 195 | 198 | } |
| ... | ... | @@ -303,7 +306,10 @@ pub fn buildLibCXXABI(comp: *Compilation) !void { |
| 303 | 306 | |
| 304 | 307 | assert(comp.libcxxabi_static_lib == null); |
| 305 | 308 | comp.libcxxabi_static_lib = Compilation.CRTFile{ |
| 306 | .full_object_path = try sub_compilation.bin_file.options.directory.join(comp.gpa, &[_][]const u8{basename}), | |
| 309 | .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join( | |
| 310 | comp.gpa, | |
| 311 | &[_][]const u8{basename}, | |
| 312 | ), | |
| 307 | 313 | .lock = sub_compilation.bin_file.toOwnedLock(), |
| 308 | 314 | }; |
| 309 | 315 | } |
src/libunwind.zig+4-1| ... | ... | @@ -126,7 +126,10 @@ pub fn buildStaticLib(comp: *Compilation) !void { |
| 126 | 126 | |
| 127 | 127 | assert(comp.libunwind_static_lib == null); |
| 128 | 128 | comp.libunwind_static_lib = Compilation.CRTFile{ |
| 129 | .full_object_path = try sub_compilation.bin_file.options.directory.join(comp.gpa, &[_][]const u8{basename}), | |
| 129 | .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join( | |
| 130 | comp.gpa, | |
| 131 | &[_][]const u8{basename}, | |
| 132 | ), | |
| 130 | 133 | .lock = sub_compilation.bin_file.toOwnedLock(), |
| 131 | 134 | }; |
| 132 | 135 | } |
src/link.zig+18-13| ... | ... | @@ -16,11 +16,17 @@ const LibCInstallation = @import("libc_installation.zig").LibCInstallation; |
| 16 | 16 | |
| 17 | 17 | pub const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version; |
| 18 | 18 | |
| 19 | pub const Options = struct { | |
| 19 | pub const Emit = struct { | |
| 20 | 20 | /// Where the output will go. |
| 21 | 21 | directory: Compilation.Directory, |
| 22 | 22 | /// Path to the output file, relative to `directory`. |
| 23 | 23 | sub_path: []const u8, |
| 24 | }; | |
| 25 | ||
| 26 | pub const Options = struct { | |
| 27 | /// This is `null` when -fno-emit-bin is used. When `openPath` or `flush` is called, | |
| 28 | /// it will have already been null-checked. | |
| 29 | emit: ?Emit, | |
| 24 | 30 | target: std.Target, |
| 25 | 31 | output_mode: std.builtin.OutputMode, |
| 26 | 32 | link_mode: std.builtin.LinkMode, |
| ... | ... | @@ -141,7 +147,7 @@ pub const File = struct { |
| 141 | 147 | /// and does not cause Illegal Behavior. This operation is not atomic. |
| 142 | 148 | pub fn openPath(allocator: *Allocator, options: Options) !*File { |
| 143 | 149 | const use_stage1 = build_options.is_stage1 and options.use_llvm; |
| 144 | if (use_stage1) { | |
| 150 | if (use_stage1 or options.emit == null) { | |
| 145 | 151 | return switch (options.object_format) { |
| 146 | 152 | .coff, .pe => &(try Coff.createEmpty(allocator, options)).base, |
| 147 | 153 | .elf => &(try Elf.createEmpty(allocator, options)).base, |
| ... | ... | @@ -152,6 +158,7 @@ pub const File = struct { |
| 152 | 158 | .raw => return error.RawObjectFormatUnimplemented, |
| 153 | 159 | }; |
| 154 | 160 | } |
| 161 | const emit = options.emit.?; | |
| 155 | 162 | const use_lld = build_options.have_llvm and options.use_lld; // comptime known false when !have_llvm |
| 156 | 163 | const sub_path = if (use_lld) blk: { |
| 157 | 164 | if (options.module == null) { |
| ... | ... | @@ -167,8 +174,8 @@ pub const File = struct { |
| 167 | 174 | }; |
| 168 | 175 | } |
| 169 | 176 | // Open a temporary object file, not the final output file because we want to link with LLD. |
| 170 | break :blk try std.fmt.allocPrint(allocator, "{}{}", .{ options.sub_path, options.target.oFileExt() }); | |
| 171 | } else options.sub_path; | |
| 177 | break :blk try std.fmt.allocPrint(allocator, "{}{}", .{ emit.sub_path, options.target.oFileExt() }); | |
| 178 | } else emit.sub_path; | |
| 172 | 179 | errdefer if (use_lld) allocator.free(sub_path); |
| 173 | 180 | |
| 174 | 181 | const file: *File = switch (options.object_format) { |
| ... | ... | @@ -199,7 +206,8 @@ pub const File = struct { |
| 199 | 206 | switch (base.tag) { |
| 200 | 207 | .coff, .elf, .macho => { |
| 201 | 208 | if (base.file != null) return; |
| 202 | base.file = try base.options.directory.handle.createFile(base.options.sub_path, .{ | |
| 209 | const emit = base.options.emit orelse return; | |
| 210 | base.file = try emit.directory.handle.createFile(emit.sub_path, .{ | |
| 203 | 211 | .truncate = false, |
| 204 | 212 | .read = true, |
| 205 | 213 | .mode = determineMode(base.options), |
| ... | ... | @@ -305,14 +313,14 @@ pub const File = struct { |
| 305 | 313 | /// Commit pending changes and write headers. Takes into account final output mode |
| 306 | 314 | /// and `use_lld`, not only `effectiveOutputMode`. |
| 307 | 315 | pub fn flush(base: *File, comp: *Compilation) !void { |
| 316 | const emit = base.options.emit orelse return; // -fno-emit-bin | |
| 317 | ||
| 308 | 318 | if (comp.clang_preprocessor_mode == .yes) { |
| 309 | 319 | // TODO: avoid extra link step when it's just 1 object file (the `zig cc -c` case) |
| 310 | 320 | // Until then, we do `lld -r -o output.o input.o` even though the output is the same |
| 311 | 321 | // as the input. For the preprocessing case (`zig cc -E -o foo`) we copy the file |
| 312 | 322 | // to the final location. |
| 313 | const full_out_path = try base.options.directory.join(comp.gpa, &[_][]const u8{ | |
| 314 | base.options.sub_path, | |
| 315 | }); | |
| 323 | const full_out_path = try emit.directory.join(comp.gpa, &[_][]const u8{emit.sub_path}); | |
| 316 | 324 | defer comp.gpa.free(full_out_path); |
| 317 | 325 | assert(comp.c_object_table.count() == 1); |
| 318 | 326 | const the_entry = comp.c_object_table.items()[0]; |
| ... | ... | @@ -402,7 +410,7 @@ pub const File = struct { |
| 402 | 410 | defer arena_allocator.deinit(); |
| 403 | 411 | const arena = &arena_allocator.allocator; |
| 404 | 412 | |
| 405 | const directory = base.options.directory; // Just an alias to make it shorter to type. | |
| 413 | const directory = base.options.emit.?.directory; // Just an alias to make it shorter to type. | |
| 406 | 414 | |
| 407 | 415 | // If there is no Zig code to compile, then we should skip flushing the output file because it |
| 408 | 416 | // will not be part of the linker line anyway. |
| ... | ... | @@ -471,10 +479,7 @@ pub const File = struct { |
| 471 | 479 | object_files.appendAssumeCapacity(try arena.dupeZ(u8, p)); |
| 472 | 480 | } |
| 473 | 481 | |
| 474 | const full_out_path = if (directory.path) |dir_path| | |
| 475 | try std.fs.path.join(arena, &[_][]const u8{ dir_path, base.options.sub_path }) | |
| 476 | else | |
| 477 | base.options.sub_path; | |
| 482 | const full_out_path = try directory.join(arena, &[_][]const u8{base.options.emit.?.sub_path}); | |
| 478 | 483 | const full_out_path_z = try arena.dupeZ(u8, full_out_path); |
| 479 | 484 | |
| 480 | 485 | if (base.options.verbose_link) { |
src/link/C.zig+1-1| ... | ... | @@ -30,7 +30,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 30 | 30 | if (options.use_llvm) return error.LLVMHasNoCBackend; |
| 31 | 31 | if (options.use_lld) return error.LLDHasNoCBackend; |
| 32 | 32 | |
| 33 | const file = try options.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true, .mode = link.determineMode(options) }); | |
| 33 | const file = try options.emit.?.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true, .mode = link.determineMode(options) }); | |
| 34 | 34 | errdefer file.close(); |
| 35 | 35 | |
| 36 | 36 | var c_file = try allocator.create(C); |
src/link/Coff.zig+1-1| ... | ... | @@ -120,7 +120,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 120 | 120 | if (options.use_llvm) return error.LLVM_BackendIsTODO_ForCoff; // TODO |
| 121 | 121 | if (options.use_lld) return error.LLD_LinkingIsTODO_ForCoff; // TODO |
| 122 | 122 | |
| 123 | const file = try options.directory.handle.createFile(sub_path, .{ | |
| 123 | const file = try options.emit.?.directory.handle.createFile(sub_path, .{ | |
| 124 | 124 | .truncate = false, |
| 125 | 125 | .read = true, |
| 126 | 126 | .mode = link.determineMode(options), |
src/link/Elf.zig+3-3| ... | ... | @@ -229,7 +229,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 229 | 229 | |
| 230 | 230 | if (options.use_llvm) return error.LLVMBackendUnimplementedForELF; // TODO |
| 231 | 231 | |
| 232 | const file = try options.directory.handle.createFile(sub_path, .{ | |
| 232 | const file = try options.emit.?.directory.handle.createFile(sub_path, .{ | |
| 233 | 233 | .truncate = false, |
| 234 | 234 | .read = true, |
| 235 | 235 | .mode = link.determineMode(options), |
| ... | ... | @@ -1218,7 +1218,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1218 | 1218 | defer arena_allocator.deinit(); |
| 1219 | 1219 | const arena = &arena_allocator.allocator; |
| 1220 | 1220 | |
| 1221 | const directory = self.base.options.directory; // Just an alias to make it shorter to type. | |
| 1221 | const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type. | |
| 1222 | 1222 | |
| 1223 | 1223 | // If there is no Zig code to compile, then we should skip flushing the output file because it |
| 1224 | 1224 | // will not be part of the linker line anyway. |
| ... | ... | @@ -1401,7 +1401,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1401 | 1401 | try argv.append("-pie"); |
| 1402 | 1402 | } |
| 1403 | 1403 | |
| 1404 | const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.sub_path}); | |
| 1404 | const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path}); | |
| 1405 | 1405 | try argv.append("-o"); |
| 1406 | 1406 | try argv.append(full_out_path); |
| 1407 | 1407 |
src/link/MachO.zig+1-1| ... | ... | @@ -142,7 +142,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 142 | 142 | if (options.use_llvm) return error.LLVM_BackendIsTODO_ForMachO; // TODO |
| 143 | 143 | if (options.use_lld) return error.LLD_LinkingIsTODO_ForMachO; // TODO |
| 144 | 144 | |
| 145 | const file = try options.directory.handle.createFile(sub_path, .{ | |
| 145 | const file = try options.emit.?.directory.handle.createFile(sub_path, .{ | |
| 146 | 146 | .truncate = false, |
| 147 | 147 | .read = true, |
| 148 | 148 | .mode = link.determineMode(options), |
src/link/Wasm.zig+1-1| ... | ... | @@ -59,7 +59,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 59 | 59 | if (options.use_lld) return error.LLD_LinkingIsTODO_ForWasm; // TODO |
| 60 | 60 | |
| 61 | 61 | // TODO: read the file and keep vaild parts instead of truncating |
| 62 | const file = try options.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true }); | |
| 62 | const file = try options.emit.?.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true }); | |
| 63 | 63 | errdefer file.close(); |
| 64 | 64 | |
| 65 | 65 | const wasm = try createEmpty(allocator, options); |
src/main.zig+11-6| ... | ... | @@ -1307,7 +1307,9 @@ fn buildOutputType( |
| 1307 | 1307 | }; |
| 1308 | 1308 | } |
| 1309 | 1309 | if (fs.path.dirname(full_path)) |dirname| { |
| 1310 | const handle = try fs.cwd().openDir(dirname, .{}); | |
| 1310 | const handle = fs.cwd().openDir(dirname, .{}) catch |err| { | |
| 1311 | fatal("unable to open output directory '{}': {}", .{ dirname, @errorName(err) }); | |
| 1312 | }; | |
| 1311 | 1313 | cleanup_emit_bin_dir = handle; |
| 1312 | 1314 | break :b Compilation.EmitLoc{ |
| 1313 | 1315 | .basename = basename, |
| ... | ... | @@ -1545,7 +1547,7 @@ fn buildOutputType( |
| 1545 | 1547 | switch (emit_bin) { |
| 1546 | 1548 | .no => break :blk .none, |
| 1547 | 1549 | .yes_default_path => break :blk .{ |
| 1548 | .print = comp.bin_file.options.directory.path orelse ".", | |
| 1550 | .print = comp.bin_file.options.emit.?.directory.path orelse ".", | |
| 1549 | 1551 | }, |
| 1550 | 1552 | .yes => |full_path| break :blk .{ .update = full_path }, |
| 1551 | 1553 | } |
| ... | ... | @@ -1560,7 +1562,7 @@ fn buildOutputType( |
| 1560 | 1562 | switch (arg_mode) { |
| 1561 | 1563 | .run, .zig_test => run: { |
| 1562 | 1564 | const exe_loc = emit_bin_loc orelse break :run; |
| 1563 | const exe_directory = exe_loc.directory orelse comp.bin_file.options.directory; | |
| 1565 | const exe_directory = exe_loc.directory orelse comp.bin_file.options.emit.?.directory; | |
| 1564 | 1566 | const exe_path = try fs.path.join(arena, &[_][]const u8{ |
| 1565 | 1567 | exe_directory.path orelse ".", exe_loc.basename, |
| 1566 | 1568 | }); |
| ... | ... | @@ -1676,8 +1678,8 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, zir_out_path: ?[]const u8, |
| 1676 | 1678 | } else switch (hook) { |
| 1677 | 1679 | .none => {}, |
| 1678 | 1680 | .print => |bin_path| try io.getStdOut().writer().print("{s}\n", .{bin_path}), |
| 1679 | .update => |full_path| _ = try comp.bin_file.options.directory.handle.updateFile( | |
| 1680 | comp.bin_file.options.sub_path, | |
| 1681 | .update => |full_path| _ = try comp.bin_file.options.emit.?.directory.handle.updateFile( | |
| 1682 | comp.bin_file.options.emit.?.sub_path, | |
| 1681 | 1683 | fs.cwd(), |
| 1682 | 1684 | full_path, |
| 1683 | 1685 | .{}, |
| ... | ... | @@ -2106,7 +2108,10 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v |
| 2106 | 2108 | |
| 2107 | 2109 | try updateModule(gpa, comp, null, .none); |
| 2108 | 2110 | |
| 2109 | child_argv.items[argv_index_exe] = try comp.bin_file.options.directory.join(arena, &[_][]const u8{exe_basename}); | |
| 2111 | child_argv.items[argv_index_exe] = try comp.bin_file.options.emit.?.directory.join( | |
| 2112 | arena, | |
| 2113 | &[_][]const u8{exe_basename}, | |
| 2114 | ); | |
| 2110 | 2115 | |
| 2111 | 2116 | break :lock_and_argv .{ |
| 2112 | 2117 | .child_argv = child_argv.items, |
test/cli.zig+16-16| ... | ... | @@ -58,7 +58,7 @@ fn printCmd(cwd: []const u8, argv: []const []const u8) void { |
| 58 | 58 | std.debug.warn("\n", .{}); |
| 59 | 59 | } |
| 60 | 60 | |
| 61 | fn exec(cwd: []const u8, argv: []const []const u8) !ChildProcess.ExecResult { | |
| 61 | fn exec(cwd: []const u8, expect_0: bool, argv: []const []const u8) !ChildProcess.ExecResult { | |
| 62 | 62 | const max_output_size = 100 * 1024; |
| 63 | 63 | const result = ChildProcess.exec(.{ |
| 64 | 64 | .allocator = a, |
| ... | ... | @@ -72,7 +72,7 @@ fn exec(cwd: []const u8, argv: []const []const u8) !ChildProcess.ExecResult { |
| 72 | 72 | }; |
| 73 | 73 | switch (result.term) { |
| 74 | 74 | .Exited => |code| { |
| 75 | if (code != 0) { | |
| 75 | if ((code != 0) == expect_0) { | |
| 76 | 76 | std.debug.warn("The following command exited with error code {}:\n", .{code}); |
| 77 | 77 | printCmd(cwd, argv); |
| 78 | 78 | std.debug.warn("stderr:\n{}\n", .{result.stderr}); |
| ... | ... | @@ -90,14 +90,14 @@ fn exec(cwd: []const u8, argv: []const []const u8) !ChildProcess.ExecResult { |
| 90 | 90 | } |
| 91 | 91 | |
| 92 | 92 | fn testZigInitLib(zig_exe: []const u8, dir_path: []const u8) !void { |
| 93 | _ = try exec(dir_path, &[_][]const u8{ zig_exe, "init-lib" }); | |
| 94 | const test_result = try exec(dir_path, &[_][]const u8{ zig_exe, "build", "test" }); | |
| 93 | _ = try exec(dir_path, true, &[_][]const u8{ zig_exe, "init-lib" }); | |
| 94 | const test_result = try exec(dir_path, true, &[_][]const u8{ zig_exe, "build", "test" }); | |
| 95 | 95 | testing.expect(std.mem.endsWith(u8, test_result.stderr, "All 1 tests passed.\n")); |
| 96 | 96 | } |
| 97 | 97 | |
| 98 | 98 | fn testZigInitExe(zig_exe: []const u8, dir_path: []const u8) !void { |
| 99 | _ = try exec(dir_path, &[_][]const u8{ zig_exe, "init-exe" }); | |
| 100 | const run_result = try exec(dir_path, &[_][]const u8{ zig_exe, "build", "run" }); | |
| 99 | _ = try exec(dir_path, true, &[_][]const u8{ zig_exe, "init-exe" }); | |
| 100 | const run_result = try exec(dir_path, true, &[_][]const u8{ zig_exe, "build", "run" }); | |
| 101 | 101 | testing.expect(std.mem.eql(u8, run_result.stderr, "info: All your codebase are belong to us.\n")); |
| 102 | 102 | } |
| 103 | 103 | |
| ... | ... | @@ -131,7 +131,7 @@ fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void { |
| 131 | 131 | const emit_asm_arg = try std.fmt.allocPrint(a, "-femit-asm={s}", .{example_s_path}); |
| 132 | 132 | try args.append(emit_asm_arg); |
| 133 | 133 | |
| 134 | _ = try exec(dir_path, args.items); | |
| 134 | _ = try exec(dir_path, true, args.items); | |
| 135 | 135 | |
| 136 | 136 | const out_asm = try std.fs.cwd().readFileAlloc(a, example_s_path, std.math.maxInt(usize)); |
| 137 | 137 | testing.expect(std.mem.indexOf(u8, out_asm, "square:") != null); |
| ... | ... | @@ -140,23 +140,23 @@ fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void { |
| 140 | 140 | } |
| 141 | 141 | |
| 142 | 142 | fn testMissingOutputPath(zig_exe: []const u8, dir_path: []const u8) !void { |
| 143 | _ = try exec(dir_path, &[_][]const u8{ zig_exe, "init-exe" }); | |
| 144 | const output_path = try fs.path.join(a, &[_][]const u8{ "does", "not", "exist" }); | |
| 143 | _ = try exec(dir_path, true, &[_][]const u8{ zig_exe, "init-exe" }); | |
| 144 | const output_path = try fs.path.join(a, &[_][]const u8{ "does", "not", "exist", "foo.exe" }); | |
| 145 | const output_arg = try std.fmt.allocPrint(a, "-femit-bin={s}", .{output_path}); | |
| 145 | 146 | const source_path = try fs.path.join(a, &[_][]const u8{ "src", "main.zig" }); |
| 146 | _ = try exec(dir_path, &[_][]const u8{ | |
| 147 | zig_exe, "build-exe", source_path, "--output-dir", output_path, | |
| 148 | }); | |
| 147 | const result = try exec(dir_path, false, &[_][]const u8{ zig_exe, "build-exe", source_path, output_arg }); | |
| 148 | testing.expect(std.mem.eql(u8, result.stderr, "error: unable to open output directory 'does/not/exist': FileNotFound\n")); | |
| 149 | 149 | } |
| 150 | 150 | |
| 151 | 151 | fn testZigFmt(zig_exe: []const u8, dir_path: []const u8) !void { |
| 152 | _ = try exec(dir_path, &[_][]const u8{ zig_exe, "init-exe" }); | |
| 152 | _ = try exec(dir_path, true, &[_][]const u8{ zig_exe, "init-exe" }); | |
| 153 | 153 | |
| 154 | 154 | const unformatted_code = " // no reason for indent"; |
| 155 | 155 | |
| 156 | 156 | const fmt1_zig_path = try fs.path.join(a, &[_][]const u8{ dir_path, "fmt1.zig" }); |
| 157 | 157 | try fs.cwd().writeFile(fmt1_zig_path, unformatted_code); |
| 158 | 158 | |
| 159 | const run_result1 = try exec(dir_path, &[_][]const u8{ zig_exe, "fmt", fmt1_zig_path }); | |
| 159 | const run_result1 = try exec(dir_path, true, &[_][]const u8{ zig_exe, "fmt", fmt1_zig_path }); | |
| 160 | 160 | // stderr should be file path + \n |
| 161 | 161 | testing.expect(std.mem.startsWith(u8, run_result1.stderr, fmt1_zig_path)); |
| 162 | 162 | testing.expect(run_result1.stderr.len == fmt1_zig_path.len + 1 and run_result1.stderr[run_result1.stderr.len - 1] == '\n'); |
| ... | ... | @@ -164,12 +164,12 @@ fn testZigFmt(zig_exe: []const u8, dir_path: []const u8) !void { |
| 164 | 164 | const fmt2_zig_path = try fs.path.join(a, &[_][]const u8{ dir_path, "fmt2.zig" }); |
| 165 | 165 | try fs.cwd().writeFile(fmt2_zig_path, unformatted_code); |
| 166 | 166 | |
| 167 | const run_result2 = try exec(dir_path, &[_][]const u8{ zig_exe, "fmt", dir_path }); | |
| 167 | const run_result2 = try exec(dir_path, true, &[_][]const u8{ zig_exe, "fmt", dir_path }); | |
| 168 | 168 | // running it on the dir, only the new file should be changed |
| 169 | 169 | testing.expect(std.mem.startsWith(u8, run_result2.stderr, fmt2_zig_path)); |
| 170 | 170 | testing.expect(run_result2.stderr.len == fmt2_zig_path.len + 1 and run_result2.stderr[run_result2.stderr.len - 1] == '\n'); |
| 171 | 171 | |
| 172 | const run_result3 = try exec(dir_path, &[_][]const u8{ zig_exe, "fmt", dir_path }); | |
| 172 | const run_result3 = try exec(dir_path, true, &[_][]const u8{ zig_exe, "fmt", dir_path }); | |
| 173 | 173 | // both files have been formatted, nothing should change now |
| 174 | 174 | testing.expect(run_result3.stderr.len == 0); |
| 175 | 175 | } |