| ... | ... | @@ -19,6 +19,8 @@ error DependencyLoopDetected; |
| 19 | 19 | error NoCompilerFound; |
| 20 | 20 | |
| 21 | 21 | pub const Builder = struct { |
| 22 | uninstall_tls: TopLevelStep, |
| 23 | have_uninstall_step: bool, |
| 22 | 24 | allocator: &Allocator, |
| 23 | 25 | lib_paths: List([]const u8), |
| 24 | 26 | include_paths: List([]const u8), |
| ... | ... | @@ -33,7 +35,9 @@ pub const Builder = struct { |
| 33 | 35 | env_map: BufMap, |
| 34 | 36 | top_level_steps: List(&TopLevelStep), |
| 35 | 37 | prefix: []const u8, |
| 38 | lib_dir: []const u8, |
| 36 | 39 | out_dir: []u8, |
| 40 | installed_files: List([]const u8), |
| 37 | 41 | |
| 38 | 42 | const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8); |
| 39 | 43 | const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8); |
| ... | ... | @@ -85,7 +89,14 @@ pub const Builder = struct { |
| 85 | 89 | .default_step = undefined, |
| 86 | 90 | .env_map = %%os.getEnvMap(allocator), |
| 87 | 91 | .prefix = undefined, |
| 92 | .lib_dir = undefined, |
| 88 | 93 | .out_dir = %%os.getCwd(allocator), |
| 94 | .installed_files = List([]const u8).init(allocator), |
| 95 | .uninstall_tls = TopLevelStep { |
| 96 | .step = Step.init("uninstall", allocator, makeUninstall), |
| 97 | .description = "Remove build artifacts from prefix path", |
| 98 | }, |
| 99 | .have_uninstall_step = false, |
| 89 | 100 | }; |
| 90 | 101 | self.processNixOSEnvVars(); |
| 91 | 102 | self.default_step = self.step("default", "Build the project"); |
| ... | ... | @@ -102,12 +113,8 @@ pub const Builder = struct { |
| 102 | 113 | } |
| 103 | 114 | |
| 104 | 115 | pub fn setInstallPrefix(self: &Builder, maybe_prefix: ?[]const u8) { |
| 105 | | if (const prefix ?= maybe_prefix) { |
| 106 | | self.prefix = prefix; |
| 107 | | return; |
| 108 | | } |
| 109 | | // TODO better default |
| 110 | | self.prefix = "/usr/local"; |
| 116 | self.prefix = maybe_prefix ?? "/usr/local"; // TODO better default |
| 117 | self.lib_dir = %%os.path.join(self.allocator, self.prefix, "lib"); |
| 111 | 118 | } |
| 112 | 119 | |
| 113 | 120 | pub fn addExecutable(self: &Builder, name: []const u8, root_src: []const u8) -> &Exe { |
| ... | ... | @@ -180,6 +187,27 @@ pub const Builder = struct { |
| 180 | 187 | } |
| 181 | 188 | } |
| 182 | 189 | |
| 190 | pub fn getUninstallStep(self: &Builder) -> &Step { |
| 191 | if (self.have_uninstall_step) |
| 192 | return &self.uninstall_tls.step; |
| 193 | |
| 194 | %%self.top_level_steps.append(&self.uninstall_tls); |
| 195 | self.have_uninstall_step = true; |
| 196 | return &self.uninstall_tls.step; |
| 197 | } |
| 198 | |
| 199 | fn makeUninstall(uninstall_step: &Step) -> %void { |
| 200 | // TODO |
| 201 | // const self = @fieldParentPtr(Exe, "step", step); |
| 202 | const self = @ptrcast(&Builder, uninstall_step); |
| 203 | |
| 204 | for (self.installed_files.toSliceConst()) |installed_file| { |
| 205 | _ = os.deleteFile(self.allocator, installed_file); |
| 206 | } |
| 207 | |
| 208 | // TODO remove empty directories |
| 209 | } |
| 210 | |
| 183 | 211 | fn makeOneStep(self: &Builder, s: &Step) -> %void { |
| 184 | 212 | if (s.loop_flag) { |
| 185 | 213 | %%io.stderr.printf("Dependency loop detected:\n {}\n", s.name); |
| ... | ... | @@ -426,6 +454,34 @@ pub const Builder = struct { |
| 426 | 454 | }; |
| 427 | 455 | |
| 428 | 456 | } |
| 457 | |
| 458 | pub fn installCLibrary(self: &Builder, lib: &CLibrary) -> &InstallCLibraryStep { |
| 459 | const install_step = %%self.allocator.create(InstallCLibraryStep); |
| 460 | *install_step = InstallCLibraryStep.init(self, lib); |
| 461 | install_step.step.dependOn(&lib.step); |
| 462 | return install_step; |
| 463 | } |
| 464 | |
| 465 | ///::dest_rel_path is relative to prefix path |
| 466 | pub fn installFile(self: &Builder, src_path: []const u8, dest_rel_path: []const u8) -> &InstallFileStep { |
| 467 | const full_dest_path = %%os.path.join(self.allocator, self.prefix, dest_rel_path); |
| 468 | self.addInstalledFile(full_dest_path); |
| 469 | |
| 470 | const install_step = %%self.allocator.create(InstallFileStep); |
| 471 | *install_step = InstallFileStep.init(self, src_path, full_dest_path); |
| 472 | return install_step; |
| 473 | } |
| 474 | |
| 475 | pub fn addInstalledFile(self: &Builder, full_path: []const u8) { |
| 476 | _ = self.getUninstallStep(); |
| 477 | %%self.installed_files.append(full_path); |
| 478 | } |
| 479 | |
| 480 | fn copyFile(self: &Builder, source_path: []const u8, dest_path: []const u8) { |
| 481 | os.copyFile(self.allocator, source_path, dest_path) %% |err| { |
| 482 | debug.panic("Unable to copy {} to {}: {}", source_path, dest_path, @errorName(err)); |
| 483 | }; |
| 484 | } |
| 429 | 485 | }; |
| 430 | 486 | |
| 431 | 487 | const Version = struct { |
| ... | ... | @@ -616,6 +672,8 @@ const CLibrary = struct { |
| 616 | 672 | target: Target, |
| 617 | 673 | builder: &Builder, |
| 618 | 674 | include_dirs: List([]const u8), |
| 675 | major_only_filename: []const u8, |
| 676 | name_only_filename: []const u8, |
| 619 | 677 | |
| 620 | 678 | pub fn initShared(builder: &Builder, name: []const u8, version: &const Version) -> CLibrary { |
| 621 | 679 | return init(builder, name, version, false); |
| ... | ... | @@ -639,6 +697,8 @@ const CLibrary = struct { |
| 639 | 697 | .link_libs = BufSet.init(builder.allocator), |
| 640 | 698 | .include_dirs = List([]const u8).init(builder.allocator), |
| 641 | 699 | .out_filename = undefined, |
| 700 | .major_only_filename = undefined, |
| 701 | .name_only_filename = undefined, |
| 642 | 702 | }; |
| 643 | 703 | clib.computeOutFileName(); |
| 644 | 704 | return clib; |
| ... | ... | @@ -650,6 +710,10 @@ const CLibrary = struct { |
| 650 | 710 | } else { |
| 651 | 711 | self.out_filename = %%fmt.allocPrint(self.builder.allocator, "lib{}.so.{d}.{d}.{d}", |
| 652 | 712 | self.name, self.version.major, self.version.minor, self.version.patch); |
| 713 | self.major_only_filename = %%fmt.allocPrint(self.builder.allocator, |
| 714 | "lib{}.so.{d}", self.name, self.version.major); |
| 715 | self.name_only_filename = %%fmt.allocPrint(self.builder.allocator, |
| 716 | "lib{}.so", self.name); |
| 653 | 717 | } |
| 654 | 718 | } |
| 655 | 719 | |
| ... | ... | @@ -752,15 +816,11 @@ const CLibrary = struct { |
| 752 | 816 | builder.spawnChild(cc, cc_args.toSliceConst()); |
| 753 | 817 | |
| 754 | 818 | // sym link for libfoo.so.1 to libfoo.so.1.2.3 |
| 755 | | const major_only = %%fmt.allocPrint(builder.allocator, "lib{}.so.{d}", self.name, self.version.major); |
| 756 | | defer builder.allocator.free(major_only); |
| 757 | | _ = os.deleteFile(builder.allocator, major_only); |
| 758 | | %%os.symLink(builder.allocator, self.out_filename, major_only); |
| 819 | _ = os.deleteFile(builder.allocator, self.major_only_filename); |
| 820 | %%os.symLink(builder.allocator, self.out_filename, self.major_only_filename); |
| 759 | 821 | // sym link for libfoo.so to libfoo.so.1 |
| 760 | | const name_only = %%fmt.allocPrint(builder.allocator, "lib{}.so", self.name); |
| 761 | | defer builder.allocator.free(name_only); |
| 762 | | _ = os.deleteFile(builder.allocator, name_only); |
| 763 | | %%os.symLink(builder.allocator, major_only, name_only); |
| 822 | _ = os.deleteFile(builder.allocator, self.name_only_filename); |
| 823 | %%os.symLink(builder.allocator, self.major_only_filename, self.name_only_filename); |
| 764 | 824 | } |
| 765 | 825 | } |
| 766 | 826 | |
| ... | ... | @@ -938,6 +998,71 @@ const CommandStep = struct { |
| 938 | 998 | } |
| 939 | 999 | }; |
| 940 | 1000 | |
| 1001 | const InstallCLibraryStep = struct { |
| 1002 | step: Step, |
| 1003 | builder: &Builder, |
| 1004 | lib: &CLibrary, |
| 1005 | dest_file: []const u8, |
| 1006 | |
| 1007 | pub fn init(builder: &Builder, lib: &CLibrary) -> InstallCLibraryStep { |
| 1008 | var self = InstallCLibraryStep { |
| 1009 | .builder = builder, |
| 1010 | .step = Step.init( |
| 1011 | %%fmt.allocPrint(builder.allocator, "install {}", lib.step.name), |
| 1012 | builder.allocator, make), |
| 1013 | .lib = lib, |
| 1014 | .dest_file = undefined, |
| 1015 | }; |
| 1016 | self.dest_file = %%os.path.join(builder.allocator, builder.lib_dir, lib.out_filename); |
| 1017 | builder.addInstalledFile(self.dest_file); |
| 1018 | if (!self.lib.static) { |
| 1019 | builder.addInstalledFile(%%os.path.join(builder.allocator, builder.lib_dir, lib.major_only_filename)); |
| 1020 | builder.addInstalledFile(%%os.path.join(builder.allocator, builder.lib_dir, lib.name_only_filename)); |
| 1021 | } |
| 1022 | return self; |
| 1023 | } |
| 1024 | |
| 1025 | fn make(step: &Step) -> %void { |
| 1026 | // TODO issue #320 |
| 1027 | //const self = @fieldParentPtr(InstallCLibraryStep, "step", step); |
| 1028 | const self = @ptrcast(&InstallCLibraryStep, step); |
| 1029 | |
| 1030 | self.builder.copyFile(self.lib.out_filename, self.dest_file); |
| 1031 | if (!self.lib.static) { |
| 1032 | _ = os.deleteFile(self.builder.allocator, self.lib.major_only_filename); |
| 1033 | %%os.symLink(self.builder.allocator, self.lib.out_filename, self.lib.major_only_filename); |
| 1034 | _ = os.deleteFile(self.builder.allocator, self.lib.name_only_filename); |
| 1035 | %%os.symLink(self.builder.allocator, self.lib.major_only_filename, self.lib.name_only_filename); |
| 1036 | } |
| 1037 | } |
| 1038 | }; |
| 1039 | |
| 1040 | const InstallFileStep = struct { |
| 1041 | step: Step, |
| 1042 | builder: &Builder, |
| 1043 | src_path: []const u8, |
| 1044 | dest_path: []const u8, |
| 1045 | |
| 1046 | pub fn init(builder: &Builder, src_path: []const u8, dest_path: []const u8) -> InstallFileStep { |
| 1047 | return InstallFileStep { |
| 1048 | .builder = builder, |
| 1049 | .step = Step.init( |
| 1050 | %%fmt.allocPrint(builder.allocator, "install {}", src_path), |
| 1051 | builder.allocator, make), |
| 1052 | .src_path = src_path, |
| 1053 | .dest_path = dest_path, |
| 1054 | }; |
| 1055 | } |
| 1056 | |
| 1057 | fn make(step: &Step) -> %void { |
| 1058 | // TODO issue #320 |
| 1059 | //const self = @fieldParentPtr(InstallFileStep, "step", step); |
| 1060 | const self = @ptrcast(&InstallFileStep, step); |
| 1061 | |
| 1062 | debug.panic("TODO install file"); |
| 1063 | } |
| 1064 | }; |
| 1065 | |
| 941 | 1066 | const Step = struct { |
| 942 | 1067 | name: []const u8, |
| 943 | 1068 | makeFn: fn(self: &Step) -> %void, |
| ... | ... | @@ -972,25 +1097,3 @@ const Step = struct { |
| 972 | 1097 | |
| 973 | 1098 | fn makeNoOp(self: &Step) -> %void {} |
| 974 | 1099 | }; |
| 975 | | |
| 976 | | fn printInvocation(exe_name: []const u8, args: &const List([]const u8)) { |
| 977 | | %%io.stderr.printf("{}", exe_name); |
| 978 | | for (args.toSliceConst()) |arg| { |
| 979 | | %%io.stderr.printf(" {}", arg); |
| 980 | | } |
| 981 | | %%io.stderr.printf("\n"); |
| 982 | | } |
| 983 | | |
| 984 | | fn waitForCleanExit(child: &os.ChildProcess) -> %void { |
| 985 | | const term = %%child.wait(); |
| 986 | | switch (term) { |
| 987 | | Term.Clean => |code| { |
| 988 | | if (code != 0) { |
| 989 | | return error.UncleanExit; |
| 990 | | } |
| 991 | | }, |
| 992 | | else => { |
| 993 | | return error.UncleanExit; |
| 994 | | }, |
| 995 | | }; |
| 996 | | } |