| ... | @@ -10,6 +10,7 @@ const StdIo = os.ChildProcess.StdIo; | ... | @@ -10,6 +10,7 @@ const StdIo = os.ChildProcess.StdIo; |
| 10 | const Term = os.ChildProcess.Term; | 10 | const Term = os.ChildProcess.Term; |
| 11 | const BufSet = @import("buf_set.zig").BufSet; | 11 | const BufSet = @import("buf_set.zig").BufSet; |
| 12 | const BufMap = @import("buf_map.zig").BufMap; | 12 | const BufMap = @import("buf_map.zig").BufMap; |
| | 13 | const fmt = @import("fmt.zig"); |
| 13 | | 14 | |
| 14 | error ExtraArg; | 15 | error ExtraArg; |
| 15 | error UncleanExit; | 16 | error UncleanExit; |
| ... | @@ -32,7 +33,7 @@ pub const Builder = struct { | ... | @@ -32,7 +33,7 @@ pub const Builder = struct { |
| 32 | env_map: BufMap, | 33 | env_map: BufMap, |
| 33 | top_level_steps: List(&TopLevelStep), | 34 | top_level_steps: List(&TopLevelStep), |
| 34 | prefix: []const u8, | 35 | prefix: []const u8, |
| 35 | out_dir: []const u8, | 36 | out_dir: []u8, |
| 36 | | 37 | |
| 37 | const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8); | 38 | const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8); |
| 38 | const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8); | 39 | const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8); |
| ... | @@ -84,7 +85,7 @@ pub const Builder = struct { | ... | @@ -84,7 +85,7 @@ pub const Builder = struct { |
| 84 | .default_step = undefined, | 85 | .default_step = undefined, |
| 85 | .env_map = %%os.getEnvMap(allocator), | 86 | .env_map = %%os.getEnvMap(allocator), |
| 86 | .prefix = undefined, | 87 | .prefix = undefined, |
| 87 | .out_dir = ".", // TODO organize | 88 | .out_dir = %%os.getCwd(allocator), |
| 88 | }; | 89 | }; |
| 89 | self.processNixOSEnvVars(); | 90 | self.processNixOSEnvVars(); |
| 90 | self.default_step = self.step("default", "Build the project"); | 91 | self.default_step = self.step("default", "Build the project"); |
| ... | @@ -92,6 +93,7 @@ pub const Builder = struct { | ... | @@ -92,6 +93,7 @@ pub const Builder = struct { |
| 92 | } | 93 | } |
| 93 | | 94 | |
| 94 | pub fn deinit(self: &Builder) { | 95 | pub fn deinit(self: &Builder) { |
| | 96 | self.allocator.free(self.out_dir); |
| 95 | self.lib_paths.deinit(); | 97 | self.lib_paths.deinit(); |
| 96 | self.include_paths.deinit(); | 98 | self.include_paths.deinit(); |
| 97 | self.rpaths.deinit(); | 99 | self.rpaths.deinit(); |
| ... | @@ -410,6 +412,17 @@ const CrossTarget = struct { | ... | @@ -410,6 +412,17 @@ const CrossTarget = struct { |
| 410 | const Target = enum { | 412 | const Target = enum { |
| 411 | Native, | 413 | Native, |
| 412 | Cross: CrossTarget, | 414 | Cross: CrossTarget, |
| | 415 | |
| | 416 | pub fn oFileExt(self: &const Target) -> []const u8 { |
| | 417 | const environ = switch (*self) { |
| | 418 | Target.Native => @compileVar("environ"), |
| | 419 | Target.Cross => |t| t.environ, |
| | 420 | }; |
| | 421 | return switch (environ) { |
| | 422 | Environ.msvc => ".obj", |
| | 423 | else => ".o", |
| | 424 | }; |
| | 425 | } |
| 413 | }; | 426 | }; |
| 414 | | 427 | |
| 415 | const LinkerScript = enum { | 428 | const LinkerScript = enum { |
| ... | @@ -562,28 +575,23 @@ const Exe = struct { | ... | @@ -562,28 +575,23 @@ const Exe = struct { |
| 562 | var child = os.ChildProcess.spawn(builder.zig_exe, zig_args.toSliceConst(), &builder.env_map, | 575 | var child = os.ChildProcess.spawn(builder.zig_exe, zig_args.toSliceConst(), &builder.env_map, |
| 563 | StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator) | 576 | StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator) |
| 564 | %% |err| debug.panic("Unable to spawn zig compiler: {}\n", @errorName(err)); | 577 | %% |err| debug.panic("Unable to spawn zig compiler: {}\n", @errorName(err)); |
| 565 | const term = %%child.wait(); | 578 | %return waitForCleanExit(&child); |
| 566 | switch (term) { | | |
| 567 | Term.Clean => |code| { | | |
| 568 | if (code != 0) { | | |
| 569 | return error.UncleanExit; | | |
| 570 | } | | |
| 571 | }, | | |
| 572 | else => { | | |
| 573 | return error.UncleanExit; | | |
| 574 | }, | | |
| 575 | }; | | |
| 576 | } | 579 | } |
| 577 | }; | 580 | }; |
| 578 | | 581 | |
| 579 | const CLibrary = struct { | 582 | const CLibrary = struct { |
| 580 | step: Step, | 583 | step: Step, |
| 581 | name: []const u8, | 584 | name: []const u8, |
| | 585 | out_filename: []const u8, |
| 582 | static: bool, | 586 | static: bool, |
| 583 | version: Version, | 587 | version: Version, |
| 584 | cflags: List([]const u8), | 588 | cflags: List([]const u8), |
| 585 | source_files: List([]const u8), | 589 | source_files: List([]const u8), |
| | 590 | object_files: List([]const u8), |
| 586 | link_libs: BufSet, | 591 | link_libs: BufSet, |
| | 592 | target: Target, |
| | 593 | builder: &Builder, |
| | 594 | include_dirs: List([]const u8), |
| 587 | | 595 | |
| 588 | pub fn initShared(builder: &Builder, name: []const u8, version: &const Version) -> CLibrary { | 596 | pub fn initShared(builder: &Builder, name: []const u8, version: &const Version) -> CLibrary { |
| 589 | return init(builder, name, version, false); | 597 | return init(builder, name, version, false); |
| ... | @@ -594,14 +602,30 @@ const CLibrary = struct { | ... | @@ -594,14 +602,30 @@ const CLibrary = struct { |
| 594 | } | 602 | } |
| 595 | | 603 | |
| 596 | fn init(builder: &Builder, name: []const u8, version: &const Version, static: bool) -> CLibrary { | 604 | fn init(builder: &Builder, name: []const u8, version: &const Version, static: bool) -> CLibrary { |
| 597 | CLibrary { | 605 | var clib = CLibrary { |
| | 606 | .builder = builder, |
| 598 | .name = name, | 607 | .name = name, |
| 599 | .version = *version, | 608 | .version = *version, |
| 600 | .static = static, | 609 | .static = static, |
| | 610 | .target = Target.Native, |
| 601 | .cflags = List([]const u8).init(builder.allocator), | 611 | .cflags = List([]const u8).init(builder.allocator), |
| 602 | .source_files = List([]const u8).init(builder.allocator), | 612 | .source_files = List([]const u8).init(builder.allocator), |
| | 613 | .object_files = List([]const u8).init(builder.allocator), |
| 603 | .step = Step.init(name, builder.allocator, make), | 614 | .step = Step.init(name, builder.allocator, make), |
| 604 | .link_libs = BufSet.init(builder.allocator), | 615 | .link_libs = BufSet.init(builder.allocator), |
| | 616 | .include_dirs = List([]const u8).init(builder.allocator), |
| | 617 | .out_filename = undefined, |
| | 618 | }; |
| | 619 | clib.computeOutFileName(); |
| | 620 | return clib; |
| | 621 | } |
| | 622 | |
| | 623 | fn computeOutFileName(self: &CLibrary) { |
| | 624 | if (self.static) { |
| | 625 | self.out_filename = %%fmt.allocPrint(self.builder.allocator, "lib{}.a", self.name); |
| | 626 | } else { |
| | 627 | self.out_filename = %%fmt.allocPrint(self.builder.allocator, "lib{}.so.{d}.{d}.{d}", |
| | 628 | self.name, self.version.major, self.version.minor, self.version.patch); |
| 605 | } | 629 | } |
| 606 | } | 630 | } |
| 607 | | 631 | |
| ... | @@ -618,6 +642,14 @@ const CLibrary = struct { | ... | @@ -618,6 +642,14 @@ const CLibrary = struct { |
| 618 | %%self.source_files.append(file); | 642 | %%self.source_files.append(file); |
| 619 | } | 643 | } |
| 620 | | 644 | |
| | 645 | pub fn addObjectFile(self: &CLibrary, file: []const u8) { |
| | 646 | %%self.object_files.append(file); |
| | 647 | } |
| | 648 | |
| | 649 | pub fn addIncludeDir(self: &CLibrary, path: []const u8) { |
| | 650 | %%self.include_dirs.append(path); |
| | 651 | } |
| | 652 | |
| 621 | pub fn addCompileFlagsForRelease(self: &CLibrary, release: bool) { | 653 | pub fn addCompileFlagsForRelease(self: &CLibrary, release: bool) { |
| 622 | if (release) { | 654 | if (release) { |
| 623 | %%self.cflags.append("-g"); | 655 | %%self.cflags.append("-g"); |
| ... | @@ -637,29 +669,115 @@ const CLibrary = struct { | ... | @@ -637,29 +669,115 @@ const CLibrary = struct { |
| 637 | // TODO issue #320 | 669 | // TODO issue #320 |
| 638 | //const self = @fieldParentPtr(CLibrary, "step", step); | 670 | //const self = @fieldParentPtr(CLibrary, "step", step); |
| 639 | const self = @ptrcast(&CLibrary, step); | 671 | const self = @ptrcast(&CLibrary, step); |
| | 672 | const cc = os.getEnv("CC") ?? "cc"; |
| | 673 | const builder = self.builder; |
| | 674 | |
| | 675 | var cc_args = List([]const u8).init(builder.allocator); |
| | 676 | defer cc_args.deinit(); |
| | 677 | |
| | 678 | for (self.source_files.toSliceConst()) |source_file| { |
| | 679 | %%cc_args.resize(0); |
| | 680 | |
| | 681 | if (!self.static) { |
| | 682 | %%cc_args.append("-fPIC"); |
| | 683 | } |
| | 684 | |
| | 685 | %%cc_args.append("-c"); |
| | 686 | %%cc_args.append(source_file); |
| 640 | | 687 | |
| 641 | const cc = os.getEnv("CC") ?? { | 688 | // TODO don't dump the .o file in the same place as the source file |
| 642 | %%io.stderr.printf("Unable to find C compiler\n"); | 689 | const o_file = %%fmt.allocPrint(builder.allocator, "{}{}", source_file, self.target.oFileExt()); |
| 643 | return error.NoCompilerFound; | 690 | defer builder.allocator.free(o_file); |
| | 691 | %%cc_args.append("-o"); |
| | 692 | %%cc_args.append(o_file); |
| | 693 | |
| | 694 | for (self.cflags.toSliceConst()) |cflag| { |
| | 695 | %%cc_args.append(cflag); |
| | 696 | } |
| | 697 | |
| | 698 | for (self.include_dirs.toSliceConst()) |dir| { |
| | 699 | %%cc_args.append("-I"); |
| | 700 | %%cc_args.append(dir); |
| | 701 | } |
| | 702 | |
| | 703 | if (builder.verbose) { |
| | 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); |
| | 711 | |
| | 712 | %%self.object_files.append(o_file); |
| | 713 | } |
| | 714 | |
| | 715 | if (self.static) { |
| | 716 | debug.panic("TODO static library"); |
| | 717 | } else { |
| | 718 | %%cc_args.resize(0); |
| | 719 | |
| | 720 | %%cc_args.append("-fPIC"); |
| | 721 | %%cc_args.append("-shared"); |
| | 722 | |
| | 723 | const soname_arg = %%fmt.allocPrint(builder.allocator, "-Wl,-soname,lib{}.so.{d}", |
| | 724 | self.name, self.version.major); |
| | 725 | defer builder.allocator.free(soname_arg); |
| | 726 | %%cc_args.append(soname_arg); |
| | 727 | |
| | 728 | %%cc_args.append("-o"); |
| | 729 | %%cc_args.append(self.out_filename); |
| | 730 | |
| | 731 | for (self.object_files.toSliceConst()) |object_file| { |
| | 732 | %%cc_args.append(object_file); |
| | 733 | } |
| | 734 | |
| | 735 | if (builder.verbose) { |
| | 736 | printInvocation(cc, cc_args); |
| | 737 | } |
| | 738 | |
| | 739 | var child = os.ChildProcess.spawn(cc, cc_args.toSliceConst(), &builder.env_map, |
| | 740 | StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator) |
| | 741 | %% |err| debug.panic("Unable to spawn compiler: {}\n", @errorName(err)); |
| | 742 | %return waitForCleanExit(&child); |
| | 743 | } |
| | 744 | } |
| | 745 | |
| | 746 | pub fn setTarget(self: &CLibrary, target_arch: Arch, target_os: Os, target_environ: Environ) { |
| | 747 | self.target = Target.Cross { |
| | 748 | CrossTarget { |
| | 749 | .arch = target_arch, |
| | 750 | .os = target_os, |
| | 751 | .environ = target_environ, |
| | 752 | } |
| 644 | }; | 753 | }; |
| 645 | %%io.stderr.printf("TODO: build c library\n"); | | |
| 646 | } | 754 | } |
| 647 | }; | 755 | }; |
| 648 | | 756 | |
| 649 | const CExecutable = struct { | 757 | const CExecutable = struct { |
| 650 | step: Step, | 758 | step: Step, |
| | 759 | builder: &Builder, |
| 651 | name: []const u8, | 760 | name: []const u8, |
| 652 | cflags: List([]const u8), | 761 | cflags: List([]const u8), |
| 653 | source_files: List([]const u8), | 762 | source_files: List([]const u8), |
| | 763 | object_files: List([]const u8), |
| | 764 | full_path_libs: List([]const u8), |
| 654 | link_libs: BufSet, | 765 | link_libs: BufSet, |
| | 766 | target: Target, |
| | 767 | include_dirs: List([]const u8), |
| 655 | | 768 | |
| 656 | pub fn init(builder: &Builder, name: []const u8) -> CExecutable { | 769 | pub fn init(builder: &Builder, name: []const u8) -> CExecutable { |
| 657 | CExecutable { | 770 | CExecutable { |
| | 771 | .builder = builder, |
| 658 | .name = name, | 772 | .name = name, |
| | 773 | .target = Target.Native, |
| 659 | .cflags = List([]const u8).init(builder.allocator), | 774 | .cflags = List([]const u8).init(builder.allocator), |
| 660 | .source_files = List([]const u8).init(builder.allocator), | 775 | .source_files = List([]const u8).init(builder.allocator), |
| | 776 | .object_files = List([]const u8).init(builder.allocator), |
| | 777 | .full_path_libs = List([]const u8).init(builder.allocator), |
| 661 | .step = Step.init(name, builder.allocator, make), | 778 | .step = Step.init(name, builder.allocator, make), |
| 662 | .link_libs = BufSet.init(builder.allocator), | 779 | .link_libs = BufSet.init(builder.allocator), |
| | 780 | .include_dirs = List([]const u8).init(builder.allocator), |
| 663 | } | 781 | } |
| 664 | } | 782 | } |
| 665 | | 783 | |
| ... | @@ -669,13 +787,21 @@ const CExecutable = struct { | ... | @@ -669,13 +787,21 @@ const CExecutable = struct { |
| 669 | | 787 | |
| 670 | pub fn linkCLibrary(self: &CExecutable, clib: &CLibrary) { | 788 | pub fn linkCLibrary(self: &CExecutable, clib: &CLibrary) { |
| 671 | self.step.dependOn(&clib.step); | 789 | self.step.dependOn(&clib.step); |
| 672 | %%self.link_libs.put(clib.name); | 790 | %%self.full_path_libs.append(clib.out_filename); |
| 673 | } | 791 | } |
| 674 | | 792 | |
| 675 | pub fn addSourceFile(self: &CExecutable, file: []const u8) { | 793 | pub fn addSourceFile(self: &CExecutable, file: []const u8) { |
| 676 | %%self.source_files.append(file); | 794 | %%self.source_files.append(file); |
| 677 | } | 795 | } |
| 678 | | 796 | |
| | 797 | pub fn addObjectFile(self: &CExecutable, file: []const u8) { |
| | 798 | %%self.object_files.append(file); |
| | 799 | } |
| | 800 | |
| | 801 | pub fn addIncludeDir(self: &CExecutable, path: []const u8) { |
| | 802 | %%self.include_dirs.append(path); |
| | 803 | } |
| | 804 | |
| 679 | pub fn addCompileFlagsForRelease(self: &CExecutable, release: bool) { | 805 | pub fn addCompileFlagsForRelease(self: &CExecutable, release: bool) { |
| 680 | if (release) { | 806 | if (release) { |
| 681 | %%self.cflags.append("-g"); | 807 | %%self.cflags.append("-g"); |
| ... | @@ -695,8 +821,82 @@ const CExecutable = struct { | ... | @@ -695,8 +821,82 @@ const CExecutable = struct { |
| 695 | // TODO issue #320 | 821 | // TODO issue #320 |
| 696 | //const self = @fieldParentPtr(CExecutable, "step", step); | 822 | //const self = @fieldParentPtr(CExecutable, "step", step); |
| 697 | const self = @ptrcast(&CExecutable, step); | 823 | const self = @ptrcast(&CExecutable, step); |
| | 824 | const cc = os.getEnv("CC") ?? "cc"; |
| | 825 | const builder = self.builder; |
| | 826 | |
| | 827 | var cc_args = List([]const u8).init(builder.allocator); |
| | 828 | defer cc_args.deinit(); |
| | 829 | |
| | 830 | for (self.source_files.toSliceConst()) |source_file| { |
| | 831 | %%cc_args.resize(0); |
| | 832 | |
| | 833 | %%cc_args.append("-c"); |
| | 834 | %%cc_args.append(source_file); |
| | 835 | |
| | 836 | // TODO don't dump the .o file in the same place as the source file |
| | 837 | const o_file = %%fmt.allocPrint(builder.allocator, "{}{}", source_file, self.target.oFileExt()); |
| | 838 | defer builder.allocator.free(o_file); |
| | 839 | %%cc_args.append("-o"); |
| | 840 | %%cc_args.append(o_file); |
| | 841 | |
| | 842 | for (self.cflags.toSliceConst()) |cflag| { |
| | 843 | %%cc_args.append(cflag); |
| | 844 | } |
| | 845 | |
| | 846 | for (self.include_dirs.toSliceConst()) |dir| { |
| | 847 | %%cc_args.append("-I"); |
| | 848 | %%cc_args.append(dir); |
| | 849 | } |
| | 850 | |
| | 851 | if (builder.verbose) { |
| | 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); |
| | 859 | |
| | 860 | %%self.object_files.append(o_file); |
| | 861 | } |
| | 862 | |
| | 863 | %%cc_args.resize(0); |
| 698 | | 864 | |
| 699 | %%io.stderr.printf("TODO: build c exe\n"); | 865 | for (self.object_files.toSliceConst()) |object_file| { |
| | 866 | %%cc_args.append(object_file); |
| | 867 | } |
| | 868 | |
| | 869 | %%cc_args.append("-o"); |
| | 870 | %%cc_args.append(self.name); |
| | 871 | |
| | 872 | const rpath_arg = %%fmt.allocPrint(builder.allocator, "-Wl,-rpath,{}", builder.out_dir); |
| | 873 | defer builder.allocator.free(rpath_arg); |
| | 874 | %%cc_args.append(rpath_arg); |
| | 875 | |
| | 876 | %%cc_args.append("-rdynamic"); |
| | 877 | |
| | 878 | for (self.full_path_libs.toSliceConst()) |full_path_lib| { |
| | 879 | %%cc_args.append(full_path_lib); |
| | 880 | } |
| | 881 | |
| | 882 | if (builder.verbose) { |
| | 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 | } |
| | 891 | |
| | 892 | pub fn setTarget(self: &CExecutable, target_arch: Arch, target_os: Os, target_environ: Environ) { |
| | 893 | self.target = Target.Cross { |
| | 894 | CrossTarget { |
| | 895 | .arch = target_arch, |
| | 896 | .os = target_os, |
| | 897 | .environ = target_environ, |
| | 898 | } |
| | 899 | }; |
| 700 | } | 900 | } |
| 701 | }; | 901 | }; |
| 702 | | 902 | |
| ... | @@ -770,3 +970,17 @@ fn printInvocation(exe_name: []const u8, args: &const List([]const u8)) { | ... | @@ -770,3 +970,17 @@ fn printInvocation(exe_name: []const u8, args: &const List([]const u8)) { |
| 770 | } | 970 | } |
| 771 | %%io.stderr.printf("\n"); | 971 | %%io.stderr.printf("\n"); |
| 772 | } | 972 | } |
| | 973 | |
| | 974 | fn waitForCleanExit(child: &os.ChildProcess) -> %void { |
| | 975 | const term = %%child.wait(); |
| | 976 | switch (term) { |
| | 977 | Term.Clean => |code| { |
| | 978 | if (code != 0) { |
| | 979 | return error.UncleanExit; |
| | 980 | } |
| | 981 | }, |
| | 982 | else => { |
| | 983 | return error.UncleanExit; |
| | 984 | }, |
| | 985 | }; |
| | 986 | } |