authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-17 02:58:42-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-17 06:47:20-04:00
log47336abae3992ef343bd9cb6099b89bad1dfb634
tree4b05465b2d964d8110b9c912b81d82d6dfcada19
parentd16ce67106796011706e9f3653bb843c21c9d708

improvements to zig build system and unwrap error safety

* zig build system: create standard dynamic library sym links * unwrapping an error results in a panic message that contains the error name * rename error.SysResources to error.SystemResources * add std.os.symLink * add std.os.deleteFile

7 files changed, 260 insertions(+), 89 deletions(-)

src/all_types.hpp+2-1
...@@ -1211,7 +1211,6 @@ enum PanicMsgId {...@@ -1211,7 +1211,6 @@ enum PanicMsgId {
1211 PanicMsgIdExactDivisionRemainder,1211 PanicMsgIdExactDivisionRemainder,
1212 PanicMsgIdSliceWidenRemainder,1212 PanicMsgIdSliceWidenRemainder,
1213 PanicMsgIdUnwrapMaybeFail,1213 PanicMsgIdUnwrapMaybeFail,
1214 PanicMsgIdUnwrapErrFail,
1215 PanicMsgIdInvalidErrorCode,1214 PanicMsgIdInvalidErrorCode,
12161215
1217 PanicMsgIdCount,1216 PanicMsgIdCount,
...@@ -1445,6 +1444,8 @@ struct CodeGen {...@@ -1445,6 +1444,8 @@ struct CodeGen {
1445 ZigList<AstNode *> error_decls;1444 ZigList<AstNode *> error_decls;
1446 bool generate_error_name_table;1445 bool generate_error_name_table;
1447 LLVMValueRef err_name_table;1446 LLVMValueRef err_name_table;
1447 size_t largest_err_name_len;
1448 LLVMValueRef safety_crash_err_fn;
14481449
1449 IrInstruction *invalid_instruction;1450 IrInstruction *invalid_instruction;
1450 ConstExprValue const_void_val;1451 ConstExprValue const_void_val;
src/codegen.cpp+141-39
...@@ -255,6 +255,7 @@ void codegen_set_linker_script(CodeGen *g, const char *linker_script) {...@@ -255,6 +255,7 @@ void codegen_set_linker_script(CodeGen *g, const char *linker_script) {
255static void render_const_val(CodeGen *g, ConstExprValue *const_val);255static void render_const_val(CodeGen *g, ConstExprValue *const_val);
256static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const char *name);256static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const char *name);
257static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val);257static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val);
258static void generate_error_name_table(CodeGen *g);
258259
259static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const char *attr_name) {260static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const char *attr_name) {
260 unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name));261 unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name));
...@@ -545,6 +546,34 @@ static bool ir_want_debug_safety(CodeGen *g, IrInstruction *instruction) {...@@ -545,6 +546,34 @@ static bool ir_want_debug_safety(CodeGen *g, IrInstruction *instruction) {
545 return true;546 return true;
546}547}
547548
549static bool is_array_of_at_least_n_bytes(CodeGen *g, TypeTableEntry *type_entry, uint32_t n) {
550 if (type_entry->id != TypeTableEntryIdArray)
551 return false;
552
553 TypeTableEntry *child_type = type_entry->data.array.child_type;
554 if (child_type->id != TypeTableEntryIdInt)
555 return false;
556
557 if (child_type != g->builtin_types.entry_u8)
558 return false;
559
560 if (type_entry->data.array.len < n)
561 return false;
562
563 return true;
564}
565
566static uint32_t get_type_alignment(CodeGen *g, TypeTableEntry *type_entry) {
567 uint32_t alignment = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, type_entry->type_ref);
568 uint32_t dbl_ptr_bytes = g->pointer_size_bytes * 2;
569 if (is_array_of_at_least_n_bytes(g, type_entry, dbl_ptr_bytes)) {
570 return (alignment < dbl_ptr_bytes) ? dbl_ptr_bytes : alignment;
571 } else {
572 return alignment;
573 }
574}
575
576
548static Buf *panic_msg_buf(PanicMsgId msg_id) {577static Buf *panic_msg_buf(PanicMsgId msg_id) {
549 switch (msg_id) {578 switch (msg_id) {
550 case PanicMsgIdCount:579 case PanicMsgIdCount:
...@@ -569,8 +598,6 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {...@@ -569,8 +598,6 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
569 return buf_create_from_str("slice widening size mismatch");598 return buf_create_from_str("slice widening size mismatch");
570 case PanicMsgIdUnwrapMaybeFail:599 case PanicMsgIdUnwrapMaybeFail:
571 return buf_create_from_str("attempt to unwrap null");600 return buf_create_from_str("attempt to unwrap null");
572 case PanicMsgIdUnwrapErrFail:
573 return buf_create_from_str("attempt to unwrap error");
574 case PanicMsgIdUnreachable:601 case PanicMsgIdUnreachable:
575 return buf_create_from_str("reached unreachable code");602 return buf_create_from_str("reached unreachable code");
576 case PanicMsgIdInvalidErrorCode:603 case PanicMsgIdInvalidErrorCode:
...@@ -595,28 +622,128 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {...@@ -595,28 +622,128 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {
595 return val->llvm_global;622 return val->llvm_global;
596}623}
597624
598static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) {625static void gen_panic_raw(CodeGen *g, LLVMValueRef msg_ptr, LLVMValueRef msg_len) {
599 FnTableEntry *panic_fn = get_extern_panic_fn(g);626 FnTableEntry *panic_fn = get_extern_panic_fn(g);
600 LLVMValueRef fn_val = fn_llvm_value(g, panic_fn);627 LLVMValueRef fn_val = fn_llvm_value(g, panic_fn);
628 LLVMValueRef args[] = { msg_ptr, msg_len };
629 ZigLLVMBuildCall(g->builder, fn_val, args, 2, panic_fn->type_entry->data.fn.calling_convention, false, "");
630 LLVMBuildUnreachable(g->builder);
631}
601632
633static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) {
602 TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true);634 TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true);
603 size_t ptr_index = str_type->data.structure.fields[slice_ptr_index].gen_index;635 size_t ptr_index = str_type->data.structure.fields[slice_ptr_index].gen_index;
604 size_t len_index = str_type->data.structure.fields[slice_len_index].gen_index;636 size_t len_index = str_type->data.structure.fields[slice_len_index].gen_index;
605 LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, msg_arg, (unsigned)ptr_index, "");637 LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, msg_arg, (unsigned)ptr_index, "");
606 LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, msg_arg, (unsigned)len_index, "");638 LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, msg_arg, (unsigned)len_index, "");
607639
608 LLVMValueRef args[] = {640 LLVMValueRef msg_ptr = LLVMBuildLoad(g->builder, ptr_ptr, "");
609 LLVMBuildLoad(g->builder, ptr_ptr, ""),641 LLVMValueRef msg_len = LLVMBuildLoad(g->builder, len_ptr, "");
610 LLVMBuildLoad(g->builder, len_ptr, ""),642 gen_panic_raw(g, msg_ptr, msg_len);
611 };
612 ZigLLVMBuildCall(g->builder, fn_val, args, 2, panic_fn->type_entry->data.fn.calling_convention, false, "");
613 LLVMBuildUnreachable(g->builder);
614}643}
615644
616static void gen_debug_safety_crash(CodeGen *g, PanicMsgId msg_id) {645static void gen_debug_safety_crash(CodeGen *g, PanicMsgId msg_id) {
617 gen_panic(g, get_panic_msg_ptr_val(g, msg_id));646 gen_panic(g, get_panic_msg_ptr_val(g, msg_id));
618}647}
619648
649static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
650 if (g->safety_crash_err_fn != nullptr)
651 return g->safety_crash_err_fn;
652
653 static const char *unwrap_err_msg_text = "attempt to unwrap error: ";
654
655 g->generate_error_name_table = true;
656 generate_error_name_table(g);
657
658 size_t unwrap_err_msg_text_len = strlen(unwrap_err_msg_text);
659 size_t err_buf_len = strlen(unwrap_err_msg_text) + g->largest_err_name_len;
660 LLVMValueRef *err_buf_vals = allocate<LLVMValueRef>(err_buf_len);
661 size_t i = 0;
662 for (; i < unwrap_err_msg_text_len; i += 1) {
663 err_buf_vals[i] = LLVMConstInt(LLVMInt8Type(), unwrap_err_msg_text[i], false);
664 }
665 for (; i < err_buf_len; i += 1) {
666 err_buf_vals[i] = LLVMGetUndef(LLVMInt8Type());
667 }
668 LLVMValueRef init_value = LLVMConstArray(LLVMInt8Type(), err_buf_vals, err_buf_len);
669 Buf *global_name = get_mangled_name(g, buf_create_from_str("__zig_panic_buf"), false);
670 LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(init_value), buf_ptr(global_name));
671 LLVMSetInitializer(global_value, init_value);
672 LLVMSetLinkage(global_value, LLVMInternalLinkage);
673 LLVMSetGlobalConstant(global_value, false);
674 LLVMSetUnnamedAddr(global_value, true);
675 LLVMSetAlignment(global_value, get_type_alignment(g, g->builtin_types.entry_u8));
676
677 TypeTableEntry *usize = g->builtin_types.entry_usize;
678 LLVMValueRef full_buf_ptr_indices[] = {
679 LLVMConstNull(usize->type_ref),
680 LLVMConstNull(usize->type_ref),
681 };
682 LLVMValueRef full_buf_ptr = LLVMConstInBoundsGEP(global_value, full_buf_ptr_indices, 2);
683
684 LLVMValueRef offset_ptr_indices[] = {
685 LLVMConstNull(usize->type_ref),
686 LLVMConstInt(usize->type_ref, unwrap_err_msg_text_len, false),
687 };
688 LLVMValueRef offset_buf_ptr = LLVMConstInBoundsGEP(global_value, offset_ptr_indices, 2);
689
690 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_fail_unwrap"), false);
691 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), &g->err_tag_type->type_ref, 1, false);
692 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
693 addLLVMFnAttr(fn_val, "noreturn");
694 addLLVMFnAttr(fn_val, "cold");
695 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
696 LLVMSetFunctionCallConv(fn_val, LLVMFastCallConv);
697
698 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
699 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
700 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
701 LLVMPositionBuilderAtEnd(g->builder, entry_block);
702 ZigLLVMClearCurrentDebugLocation(g->builder);
703
704 LLVMValueRef err_val = LLVMGetParam(fn_val, 0);
705
706 LLVMValueRef err_table_indices[] = {
707 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
708 err_val,
709 };
710 LLVMValueRef err_name_val = LLVMBuildInBoundsGEP(g->builder, g->err_name_table, err_table_indices, 2, "");
711
712 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, err_name_val, slice_ptr_index, "");
713 LLVMValueRef err_name_ptr = LLVMBuildLoad(g->builder, ptr_field_ptr, "");
714
715 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, err_name_val, slice_len_index, "");
716 LLVMValueRef err_name_len = LLVMBuildLoad(g->builder, len_field_ptr, "");
717
718 LLVMValueRef params[] = {
719 offset_buf_ptr, // dest pointer
720 err_name_ptr, // source pointer
721 err_name_len, // size bytes
722 LLVMConstInt(LLVMInt32Type(), 1, false), // align bytes
723 LLVMConstNull(LLVMInt1Type()), // is volatile
724 };
725
726 LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, "");
727
728 LLVMValueRef const_prefix_len = LLVMConstInt(LLVMTypeOf(err_name_len), strlen(unwrap_err_msg_text), false);
729 LLVMValueRef full_buf_len = LLVMBuildNUWAdd(g->builder, const_prefix_len, err_name_len, "");
730
731 gen_panic_raw(g, full_buf_ptr, full_buf_len);
732
733 LLVMPositionBuilderAtEnd(g->builder, prev_block);
734 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
735
736 g->safety_crash_err_fn = fn_val;
737 return fn_val;
738}
739
740static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {
741 LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g);
742 LLVMBuildCall(g->builder, safety_crash_err_fn, &err_val, 1, "");
743 LLVMBuildUnreachable(g->builder);
744
745}
746
620static void add_bounds_check(CodeGen *g, LLVMValueRef target_val,747static void add_bounds_check(CodeGen *g, LLVMValueRef target_val,
621 LLVMIntPredicate lower_pred, LLVMValueRef lower_value,748 LLVMIntPredicate lower_pred, LLVMValueRef lower_value,
622 LLVMIntPredicate upper_pred, LLVMValueRef upper_value)749 LLVMIntPredicate upper_pred, LLVMValueRef upper_value)
...@@ -790,33 +917,6 @@ static LLVMRealPredicate cmp_op_to_real_predicate(IrBinOp cmp_op) {...@@ -790,33 +917,6 @@ static LLVMRealPredicate cmp_op_to_real_predicate(IrBinOp cmp_op) {
790 }917 }
791}918}
792919
793static bool is_array_of_at_least_n_bytes(CodeGen *g, TypeTableEntry *type_entry, uint32_t n) {
794 if (type_entry->id != TypeTableEntryIdArray)
795 return false;
796
797 TypeTableEntry *child_type = type_entry->data.array.child_type;
798 if (child_type->id != TypeTableEntryIdInt)
799 return false;
800
801 if (child_type != g->builtin_types.entry_u8)
802 return false;
803
804 if (type_entry->data.array.len < n)
805 return false;
806
807 return true;
808}
809
810static uint32_t get_type_alignment(CodeGen *g, TypeTableEntry *type_entry) {
811 uint32_t alignment = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, type_entry->type_ref);
812 uint32_t dbl_ptr_bytes = g->pointer_size_bytes * 2;
813 if (is_array_of_at_least_n_bytes(g, type_entry, dbl_ptr_bytes)) {
814 return (alignment < dbl_ptr_bytes) ? dbl_ptr_bytes : alignment;
815 } else {
816 return alignment;
817 }
818}
819
820static LLVMValueRef gen_struct_memcpy(CodeGen *g, LLVMValueRef src, LLVMValueRef dest,920static LLVMValueRef gen_struct_memcpy(CodeGen *g, LLVMValueRef src, LLVMValueRef dest,
821 TypeTableEntry *type_entry)921 TypeTableEntry *type_entry)
822{922{
...@@ -2522,7 +2622,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu...@@ -2522,7 +2622,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
2522 LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block);2622 LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block);
25232623
2524 LLVMPositionBuilderAtEnd(g->builder, err_block);2624 LLVMPositionBuilderAtEnd(g->builder, err_block);
2525 gen_debug_safety_crash(g, PanicMsgIdUnwrapErrFail);2625 gen_debug_safety_crash_for_err(g, err_val);
25262626
2527 LLVMPositionBuilderAtEnd(g->builder, ok_block);2627 LLVMPositionBuilderAtEnd(g->builder, ok_block);
2528 }2628 }
...@@ -3384,7 +3484,7 @@ static LLVMValueRef gen_test_fn_val(CodeGen *g, FnTableEntry *fn_entry) {...@@ -3384,7 +3484,7 @@ static LLVMValueRef gen_test_fn_val(CodeGen *g, FnTableEntry *fn_entry) {
3384}3484}
33853485
3386static void generate_error_name_table(CodeGen *g) {3486static void generate_error_name_table(CodeGen *g) {
3387 if (!g->generate_error_name_table || g->error_decls.length == 1) {3487 if (g->err_name_table != nullptr || !g->generate_error_name_table || g->error_decls.length == 1) {
3388 return;3488 return;
3389 }3489 }
33903490
...@@ -3400,6 +3500,8 @@ static void generate_error_name_table(CodeGen *g) {...@@ -3400,6 +3500,8 @@ static void generate_error_name_table(CodeGen *g) {
3400 assert(error_decl_node->type == NodeTypeErrorValueDecl);3500 assert(error_decl_node->type == NodeTypeErrorValueDecl);
3401 Buf *name = error_decl_node->data.error_value_decl.name;3501 Buf *name = error_decl_node->data.error_value_decl.name;
34023502
3503 g->largest_err_name_len = max(g->largest_err_name_len, buf_len(name));
3504
3403 LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true);3505 LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true);
3404 LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), "");3506 LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), "");
3405 LLVMSetInitializer(str_global, str_init);3507 LLVMSetInitializer(str_global, str_init);
...@@ -3417,7 +3519,7 @@ static void generate_error_name_table(CodeGen *g) {...@@ -3417,7 +3519,7 @@ static void generate_error_name_table(CodeGen *g) {
3417 LLVMValueRef err_name_table_init = LLVMConstArray(str_type->type_ref, values, (unsigned)g->error_decls.length);3519 LLVMValueRef err_name_table_init = LLVMConstArray(str_type->type_ref, values, (unsigned)g->error_decls.length);
34183520
3419 g->err_name_table = LLVMAddGlobal(g->module, LLVMTypeOf(err_name_table_init),3521 g->err_name_table = LLVMAddGlobal(g->module, LLVMTypeOf(err_name_table_init),
3420 buf_ptr(get_mangled_name(g, buf_create_from_str("err_name_table"), false)));3522 buf_ptr(get_mangled_name(g, buf_create_from_str("__zig_err_name_table"), false)));
3421 LLVMSetInitializer(g->err_name_table, err_name_table_init);3523 LLVMSetInitializer(g->err_name_table, err_name_table_init);
3422 LLVMSetLinkage(g->err_name_table, LLVMPrivateLinkage);3524 LLVMSetLinkage(g->err_name_table, LLVMPrivateLinkage);
3423 LLVMSetGlobalConstant(g->err_name_table, true);3525 LLVMSetGlobalConstant(g->err_name_table, true);
src/main.cpp-2
...@@ -248,8 +248,6 @@ int main(int argc, char **argv) {...@@ -248,8 +248,6 @@ int main(int argc, char **argv) {
248 fprintf(stderr, " %s", args.at(i));248 fprintf(stderr, " %s", args.at(i));
249 }249 }
250 fprintf(stderr, "\n");250 fprintf(stderr, "\n");
251 } else {
252 os_delete_file(buf_create_from_str("./build"));
253 }251 }
254 return (term.how == TerminationIdClean) ? term.code : -1;252 return (term.how == TerminationIdClean) ? term.code : -1;
255 }253 }
std/build.zig+42-39
...@@ -395,6 +395,33 @@ pub const Builder = struct {...@@ -395,6 +395,33 @@ pub const Builder = struct {
395395
396 return self.invalid_user_input;396 return self.invalid_user_input;
397 }397 }
398
399 fn spawnChild(self: &Builder, exe_path: []const u8, args: []const []const u8) {
400 if (self.verbose) {
401 %%io.stderr.printf("{}", exe_path);
402 for (args) |arg| {
403 %%io.stderr.printf(" {}", arg);
404 }
405 %%io.stderr.printf("\n");
406 }
407
408 var child = os.ChildProcess.spawn(exe_path, args, &self.env_map,
409 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, self.allocator)
410 %% |err| debug.panic("Unable to spawn {}: {}\n", exe_path, @errorName(err));
411
412 const term = %%child.wait();
413 switch (term) {
414 Term.Clean => |code| {
415 if (code != 0) {
416 debug.panic("Process {} exited with error code {}\n", exe_path, code);
417 }
418 },
419 else => {
420 debug.panic("Process {} terminated unexpectedly\n", exe_path);
421 },
422 };
423
424 }
398};425};
399426
400const Version = struct {427const Version = struct {
...@@ -568,14 +595,7 @@ const Exe = struct {...@@ -568,14 +595,7 @@ const Exe = struct {
568 %return zig_args.append(lib_path);595 %return zig_args.append(lib_path);
569 }596 }
570597
571 if (builder.verbose) {598 builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());
572 printInvocation(builder.zig_exe, zig_args);
573 }
574 // TODO issue #301
575 var child = os.ChildProcess.spawn(builder.zig_exe, zig_args.toSliceConst(), &builder.env_map,
576 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator)
577 %% |err| debug.panic("Unable to spawn zig compiler: {}\n", @errorName(err));
578 %return waitForCleanExit(&child);
579 }599 }
580};600};
581601
...@@ -700,14 +720,7 @@ const CLibrary = struct {...@@ -700,14 +720,7 @@ const CLibrary = struct {
700 %%cc_args.append(dir);720 %%cc_args.append(dir);
701 }721 }
702722
703 if (builder.verbose) {723 builder.spawnChild(cc, cc_args.toSliceConst());
704 printInvocation(cc, cc_args);
705 }
706
707 var child = os.ChildProcess.spawn(cc, cc_args.toSliceConst(), &builder.env_map,
708 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator)
709 %% |err| debug.panic("Unable to spawn compiler: {}\n", @errorName(err));
710 %return waitForCleanExit(&child);
711724
712 %%self.object_files.append(o_file);725 %%self.object_files.append(o_file);
713 }726 }
...@@ -732,14 +745,18 @@ const CLibrary = struct {...@@ -732,14 +745,18 @@ const CLibrary = struct {
732 %%cc_args.append(object_file);745 %%cc_args.append(object_file);
733 }746 }
734747
735 if (builder.verbose) {748 builder.spawnChild(cc, cc_args.toSliceConst());
736 printInvocation(cc, cc_args);
737 }
738749
739 var child = os.ChildProcess.spawn(cc, cc_args.toSliceConst(), &builder.env_map,750 // sym link for libfoo.so.1 to libfoo.so.1.2.3
740 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator)751 const major_only = %%fmt.allocPrint(builder.allocator, "lib{}.so.{d}", self.name, self.version.major);
741 %% |err| debug.panic("Unable to spawn compiler: {}\n", @errorName(err));752 defer builder.allocator.free(major_only);
742 %return waitForCleanExit(&child);753 _ = os.deleteFile(builder.allocator, major_only);
754 %%os.symLink(builder.allocator, self.out_filename, major_only);
755 // sym link for libfoo.so to libfoo.so.1
756 const name_only = %%fmt.allocPrint(builder.allocator, "lib{}.so", self.name);
757 defer builder.allocator.free(name_only);
758 _ = os.deleteFile(builder.allocator, name_only);
759 %%os.symLink(builder.allocator, major_only, name_only);
743 }760 }
744 }761 }
745762
...@@ -848,14 +865,7 @@ const CExecutable = struct {...@@ -848,14 +865,7 @@ const CExecutable = struct {
848 %%cc_args.append(dir);865 %%cc_args.append(dir);
849 }866 }
850867
851 if (builder.verbose) {868 builder.spawnChild(cc, cc_args.toSliceConst());
852 printInvocation(cc, cc_args);
853 }
854
855 var child = os.ChildProcess.spawn(cc, cc_args.toSliceConst(), &builder.env_map,
856 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator)
857 %% |err| debug.panic("Unable to spawn compiler: {}\n", @errorName(err));
858 %return waitForCleanExit(&child);
859869
860 %%self.object_files.append(o_file);870 %%self.object_files.append(o_file);
861 }871 }
...@@ -879,14 +889,7 @@ const CExecutable = struct {...@@ -879,14 +889,7 @@ const CExecutable = struct {
879 %%cc_args.append(full_path_lib);889 %%cc_args.append(full_path_lib);
880 }890 }
881891
882 if (builder.verbose) {892 builder.spawnChild(cc, cc_args.toSliceConst());
883 printInvocation(cc, cc_args);
884 }
885
886 var child = os.ChildProcess.spawn(cc, cc_args.toSliceConst(), &builder.env_map,
887 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator)
888 %% |err| debug.panic("Unable to spawn compiler: {}\n", @errorName(err));
889 %return waitForCleanExit(&child);
890 }893 }
891894
892 pub fn setTarget(self: &CExecutable, target_arch: Arch, target_os: Os, target_environ: Environ) {895 pub fn setTarget(self: &CExecutable, target_arch: Arch, target_os: Os, target_environ: Environ) {
std/os/child_process.zig+4-4
...@@ -142,7 +142,7 @@ pub const ChildProcess = struct {...@@ -142,7 +142,7 @@ pub const ChildProcess = struct {
142 const pid_err = posix.getErrno(pid);142 const pid_err = posix.getErrno(pid);
143 if (pid_err > 0) {143 if (pid_err > 0) {
144 return switch (pid_err) {144 return switch (pid_err) {
145 errno.EAGAIN, errno.ENOMEM, errno.ENOSYS => error.SysResources,145 errno.EAGAIN, errno.ENOMEM, errno.ENOSYS => error.SystemResources,
146 else => error.Unexpected,146 else => error.Unexpected,
147 };147 };
148 }148 }
...@@ -210,7 +210,7 @@ fn makePipe() -> %[2]i32 {...@@ -210,7 +210,7 @@ fn makePipe() -> %[2]i32 {
210 const err = posix.getErrno(posix.pipe(&fds));210 const err = posix.getErrno(posix.pipe(&fds));
211 if (err > 0) {211 if (err > 0) {
212 return switch (err) {212 return switch (err) {
213 errno.EMFILE, errno.ENFILE => error.SysResources,213 errno.EMFILE, errno.ENFILE => error.SystemResources,
214 else => error.Unexpected,214 else => error.Unexpected,
215 }215 }
216 }216 }
...@@ -242,7 +242,7 @@ fn writeIntFd(fd: i32, value: ErrInt) -> %void {...@@ -242,7 +242,7 @@ fn writeIntFd(fd: i32, value: ErrInt) -> %void {
242 switch (err) {242 switch (err) {
243 errno.EINTR => continue,243 errno.EINTR => continue,
244 errno.EINVAL => unreachable,244 errno.EINVAL => unreachable,
245 else => return error.SysResources,245 else => return error.SystemResources,
246 }246 }
247 }247 }
248 index += amt_written;248 index += amt_written;
...@@ -260,7 +260,7 @@ fn readIntFd(fd: i32) -> %ErrInt {...@@ -260,7 +260,7 @@ fn readIntFd(fd: i32) -> %ErrInt {
260 switch (err) {260 switch (err) {
261 errno.EINTR => continue,261 errno.EINTR => continue,
262 errno.EINVAL => unreachable,262 errno.EINVAL => unreachable,
263 else => return error.SysResources,263 else => return error.SystemResources,
264 }264 }
265 }265 }
266 index += amt_written;266 index += amt_written;
std/os/index.zig+63-4
...@@ -25,13 +25,16 @@ const BufMap = @import("../buf_map.zig").BufMap;...@@ -25,13 +25,16 @@ const BufMap = @import("../buf_map.zig").BufMap;
25const cstr = @import("../cstr.zig");25const cstr = @import("../cstr.zig");
2626
27error Unexpected;27error Unexpected;
28error SysResources;28error SystemResources;
29error AccessDenied;29error AccessDenied;
30error InvalidExe;30error InvalidExe;
31error FileSystem;31error FileSystem;
32error IsDir;32error IsDir;
33error FileNotFound;33error FileNotFound;
34error FileBusy;34error FileBusy;
35error LinkPathAlreadyExists;
36error SymLinkLoop;
37error ReadOnlyFileSystem;
3538
36/// Fills `buf` with random bytes. If linking against libc, this calls the39/// Fills `buf` with random bytes. If linking against libc, this calls the
37/// appropriate OS-specific library call. Otherwise it uses the zig standard40/// appropriate OS-specific library call. Otherwise it uses the zig standard
...@@ -174,7 +177,7 @@ pub fn posixOpen(path: []const u8, flags: usize, perm: usize, allocator: ?&Alloc...@@ -174,7 +177,7 @@ pub fn posixOpen(path: []const u8, flags: usize, perm: usize, allocator: ?&Alloc
174 errno.ENFILE => error.SystemFdQuotaExceeded,177 errno.ENFILE => error.SystemFdQuotaExceeded,
175 errno.ENODEV => error.NoDevice,178 errno.ENODEV => error.NoDevice,
176 errno.ENOENT => error.PathNotFound,179 errno.ENOENT => error.PathNotFound,
177 errno.ENOMEM => error.NoMem,180 errno.ENOMEM => error.SystemResources,
178 errno.ENOSPC => error.NoSpaceLeft,181 errno.ENOSPC => error.NoSpaceLeft,
179 errno.ENOTDIR => error.NotDir,182 errno.ENOTDIR => error.NotDir,
180 errno.EPERM => error.BadPerm,183 errno.EPERM => error.BadPerm,
...@@ -191,7 +194,7 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) -> %void {...@@ -191,7 +194,7 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) -> %void {
191 if (err > 0) {194 if (err > 0) {
192 return switch (err) {195 return switch (err) {
193 errno.EBUSY, errno.EINTR => continue,196 errno.EBUSY, errno.EINTR => continue,
194 errno.EMFILE => error.SysResources,197 errno.EMFILE => error.SystemResources,
195 errno.EINVAL => unreachable,198 errno.EINVAL => unreachable,
196 else => error.Unexpected,199 else => error.Unexpected,
197 };200 };
...@@ -305,7 +308,7 @@ fn posixExecveErrnoToErr(err: usize) -> error {...@@ -305,7 +308,7 @@ fn posixExecveErrnoToErr(err: usize) -> error {
305 assert(err > 0);308 assert(err > 0);
306 return switch (err) {309 return switch (err) {
307 errno.EFAULT => unreachable,310 errno.EFAULT => unreachable,
308 errno.E2BIG, errno.EMFILE, errno.ENAMETOOLONG, errno.ENFILE, errno.ENOMEM => error.SysResources,311 errno.E2BIG, errno.EMFILE, errno.ENAMETOOLONG, errno.ENFILE, errno.ENOMEM => error.SystemResources,
309 errno.EACCES, errno.EPERM => error.AccessDenied,312 errno.EACCES, errno.EPERM => error.AccessDenied,
310 errno.EINVAL, errno.ENOEXEC => error.InvalidExe,313 errno.EINVAL, errno.ENOEXEC => error.InvalidExe,
311 errno.EIO, errno.ELOOP => error.FileSystem,314 errno.EIO, errno.ELOOP => error.FileSystem,
...@@ -381,3 +384,59 @@ pub fn getCwd(allocator: &Allocator) -> %[]u8 {...@@ -381,3 +384,59 @@ pub fn getCwd(allocator: &Allocator) -> %[]u8 {
381 return buf;384 return buf;
382 }385 }
383}386}
387
388pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) -> %void {
389 const full_buf = %return allocator.alloc(u8, existing_path.len + new_path.len + 2);
390 defer allocator.free(full_buf);
391
392 const existing_buf = full_buf;
393 mem.copy(u8, existing_buf, existing_path);
394 existing_buf[existing_path.len] = 0;
395
396 const new_buf = full_buf[existing_path.len + 1...];
397 mem.copy(u8, new_buf, new_path);
398 new_buf[new_path.len] = 0;
399
400 const err = posix.getErrno(posix.symlink(existing_buf.ptr, new_buf.ptr));
401 if (err > 0) {
402 return switch (err) {
403 errno.EFAULT, errno.EINVAL => unreachable,
404 errno.EACCES, errno.EPERM => error.AccessDenied,
405 errno.EDQUOT => error.DiskQuota,
406 errno.EEXIST => error.LinkPathAlreadyExists,
407 errno.EIO => error.FileSystem,
408 errno.ELOOP => error.SymLinkLoop,
409 errno.ENAMETOOLONG => error.NameTooLong,
410 errno.ENOENT, errno.ENOTDIR => error.FileNotFound,
411 errno.ENOMEM => error.SystemResources,
412 errno.ENOSPC => error.NoSpaceLeft,
413 errno.EROFS => error.ReadOnlyFileSystem,
414 else => error.Unexpected,
415 };
416 }
417}
418
419pub fn deleteFile(allocator: &Allocator, path: []const u8) -> %void {
420 const buf = %return allocator.alloc(u8, path.len + 1);
421 defer allocator.free(buf);
422
423 mem.copy(u8, buf, path);
424 buf[path.len] = 0;
425
426 const err = posix.getErrno(posix.unlink(buf.ptr));
427 if (err > 0) {
428 return switch (err) {
429 errno.EACCES, errno.EPERM => error.AccessDenied,
430 errno.EBUSY => error.FileBusy,
431 errno.EFAULT, errno.EINVAL => unreachable,
432 errno.EIO => error.FileSystem,
433 errno.EISDIR => error.IsDir,
434 errno.ELOOP => error.SymLinkLoop,
435 errno.ENAMETOOLONG => error.NameTooLong,
436 errno.ENOENT, errno.ENOTDIR => error.FileNotFound,
437 errno.ENOMEM => error.SystemResources,
438 errno.EROFS => error.ReadOnlyFileSystem,
439 else => error.Unexpected,
440 };
441 }
442}
std/os/linux.zig+8
...@@ -287,6 +287,10 @@ pub fn read(fd: i32, buf: &u8, count: usize) -> usize {...@@ -287,6 +287,10 @@ pub fn read(fd: i32, buf: &u8, count: usize) -> usize {
287 arch.syscall3(arch.SYS_read, usize(fd), usize(buf), count)287 arch.syscall3(arch.SYS_read, usize(fd), usize(buf), count)
288}288}
289289
290pub fn symlink(existing: &const u8, new: &const u8) -> usize {
291 arch.syscall2(arch.SYS_symlink, usize(existing), usize(new))
292}
293
290pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) -> usize {294pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) -> usize {
291 arch.syscall4(arch.SYS_pread, usize(fd), usize(buf), count, offset)295 arch.syscall4(arch.SYS_pread, usize(fd), usize(buf), count, offset)
292}296}
...@@ -340,6 +344,10 @@ pub fn kill(pid: i32, sig: i32) -> usize {...@@ -340,6 +344,10 @@ pub fn kill(pid: i32, sig: i32) -> usize {
340 arch.syscall2(arch.SYS_kill, usize(pid), usize(sig))344 arch.syscall2(arch.SYS_kill, usize(pid), usize(sig))
341}345}
342346
347pub fn unlink(path: &const u8) -> usize {
348 arch.syscall1(arch.SYS_unlink, usize(path))
349}
350
343pub fn waitpid(pid: i32, status: &i32, options: i32) -> usize {351pub fn waitpid(pid: i32, status: &i32, options: i32) -> usize {
344 arch.syscall4(arch.SYS_wait4, usize(pid), usize(status), usize(options), 0)352 arch.syscall4(arch.SYS_wait4, usize(pid), usize(status), usize(options), 0)
345}353}