| ... | ... | @@ -10,6 +10,7 @@ const StdIo = os.ChildProcess.StdIo; |
| 10 | 10 | const Term = os.ChildProcess.Term; |
| 11 | 11 | const BufSet = @import("buf_set.zig").BufSet; |
| 12 | 12 | const BufMap = @import("buf_map.zig").BufMap; |
| 13 | const fmt = @import("fmt.zig"); |
| 13 | 14 | |
| 14 | 15 | error ExtraArg; |
| 15 | 16 | error UncleanExit; |
| ... | ... | @@ -32,7 +33,7 @@ pub const Builder = struct { |
| 32 | 33 | env_map: BufMap, |
| 33 | 34 | top_level_steps: List(&TopLevelStep), |
| 34 | 35 | prefix: []const u8, |
| 35 | | out_dir: []const u8, |
| 36 | out_dir: []u8, |
| 36 | 37 | |
| 37 | 38 | const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8); |
| 38 | 39 | const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8); |
| ... | ... | @@ -84,7 +85,7 @@ pub const Builder = struct { |
| 84 | 85 | .default_step = undefined, |
| 85 | 86 | .env_map = %%os.getEnvMap(allocator), |
| 86 | 87 | .prefix = undefined, |
| 87 | | .out_dir = ".", // TODO organize |
| 88 | .out_dir = %%os.getCwd(allocator), |
| 88 | 89 | }; |
| 89 | 90 | self.processNixOSEnvVars(); |
| 90 | 91 | self.default_step = self.step("default", "Build the project"); |
| ... | ... | @@ -92,6 +93,7 @@ pub const Builder = struct { |
| 92 | 93 | } |
| 93 | 94 | |
| 94 | 95 | pub fn deinit(self: &Builder) { |
| 96 | self.allocator.free(self.out_dir); |
| 95 | 97 | self.lib_paths.deinit(); |
| 96 | 98 | self.include_paths.deinit(); |
| 97 | 99 | self.rpaths.deinit(); |
| ... | ... | @@ -410,6 +412,17 @@ const CrossTarget = struct { |
| 410 | 412 | const Target = enum { |
| 411 | 413 | Native, |
| 412 | 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 | 428 | const LinkerScript = enum { |
| ... | ... | @@ -562,28 +575,23 @@ const Exe = struct { |
| 562 | 575 | var child = os.ChildProcess.spawn(builder.zig_exe, zig_args.toSliceConst(), &builder.env_map, |
| 563 | 576 | StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator) |
| 564 | 577 | %% |err| debug.panic("Unable to spawn zig compiler: {}\n", @errorName(err)); |
| 565 | | const term = %%child.wait(); |
| 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 | | }; |
| 578 | %return waitForCleanExit(&child); |
| 576 | 579 | } |
| 577 | 580 | }; |
| 578 | 581 | |
| 579 | 582 | const CLibrary = struct { |
| 580 | 583 | step: Step, |
| 581 | 584 | name: []const u8, |
| 585 | out_filename: []const u8, |
| 582 | 586 | static: bool, |
| 583 | 587 | version: Version, |
| 584 | 588 | cflags: List([]const u8), |
| 585 | 589 | source_files: List([]const u8), |
| 590 | object_files: List([]const u8), |
| 586 | 591 | link_libs: BufSet, |
| 592 | target: Target, |
| 593 | builder: &Builder, |
| 594 | include_dirs: List([]const u8), |
| 587 | 595 | |
| 588 | 596 | pub fn initShared(builder: &Builder, name: []const u8, version: &const Version) -> CLibrary { |
| 589 | 597 | return init(builder, name, version, false); |
| ... | ... | @@ -594,14 +602,30 @@ const CLibrary = struct { |
| 594 | 602 | } |
| 595 | 603 | |
| 596 | 604 | fn init(builder: &Builder, name: []const u8, version: &const Version, static: bool) -> CLibrary { |
| 597 | | CLibrary { |
| 605 | var clib = CLibrary { |
| 606 | .builder = builder, |
| 598 | 607 | .name = name, |
| 599 | 608 | .version = *version, |
| 600 | 609 | .static = static, |
| 610 | .target = Target.Native, |
| 601 | 611 | .cflags = List([]const u8).init(builder.allocator), |
| 602 | 612 | .source_files = List([]const u8).init(builder.allocator), |
| 613 | .object_files = List([]const u8).init(builder.allocator), |
| 603 | 614 | .step = Step.init(name, builder.allocator, make), |
| 604 | 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 | 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 | 653 | pub fn addCompileFlagsForRelease(self: &CLibrary, release: bool) { |
| 622 | 654 | if (release) { |
| 623 | 655 | %%self.cflags.append("-g"); |
| ... | ... | @@ -637,29 +669,115 @@ const CLibrary = struct { |
| 637 | 669 | // TODO issue #320 |
| 638 | 670 | //const self = @fieldParentPtr(CLibrary, "step", step); |
| 639 | 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") ?? { |
| 642 | | %%io.stderr.printf("Unable to find C compiler\n"); |
| 643 | | return error.NoCompilerFound; |
| 688 | // TODO don't dump the .o file in the same place as the source file |
| 689 | const o_file = %%fmt.allocPrint(builder.allocator, "{}{}", source_file, self.target.oFileExt()); |
| 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 | 757 | const CExecutable = struct { |
| 650 | 758 | step: Step, |
| 759 | builder: &Builder, |
| 651 | 760 | name: []const u8, |
| 652 | 761 | cflags: List([]const u8), |
| 653 | 762 | source_files: List([]const u8), |
| 763 | object_files: List([]const u8), |
| 764 | full_path_libs: List([]const u8), |
| 654 | 765 | link_libs: BufSet, |
| 766 | target: Target, |
| 767 | include_dirs: List([]const u8), |
| 655 | 768 | |
| 656 | 769 | pub fn init(builder: &Builder, name: []const u8) -> CExecutable { |
| 657 | 770 | CExecutable { |
| 771 | .builder = builder, |
| 658 | 772 | .name = name, |
| 773 | .target = Target.Native, |
| 659 | 774 | .cflags = List([]const u8).init(builder.allocator), |
| 660 | 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 | 778 | .step = Step.init(name, builder.allocator, make), |
| 662 | 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 | 787 | |
| 670 | 788 | pub fn linkCLibrary(self: &CExecutable, clib: &CLibrary) { |
| 671 | 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 | 793 | pub fn addSourceFile(self: &CExecutable, file: []const u8) { |
| 676 | 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 | 805 | pub fn addCompileFlagsForRelease(self: &CExecutable, release: bool) { |
| 680 | 806 | if (release) { |
| 681 | 807 | %%self.cflags.append("-g"); |
| ... | ... | @@ -695,8 +821,82 @@ const CExecutable = struct { |
| 695 | 821 | // TODO issue #320 |
| 696 | 822 | //const self = @fieldParentPtr(CExecutable, "step", step); |
| 697 | 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 | 970 | } |
| 771 | 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 | } |