| ... | @@ -19,6 +19,8 @@ error DependencyLoopDetected; | ... | @@ -19,6 +19,8 @@ error DependencyLoopDetected; |
| 19 | error NoCompilerFound; | 19 | error NoCompilerFound; |
| 20 | | 20 | |
| 21 | pub const Builder = struct { | 21 | pub const Builder = struct { |
| | 22 | uninstall_tls: TopLevelStep, |
| | 23 | have_uninstall_step: bool, |
| 22 | allocator: &Allocator, | 24 | allocator: &Allocator, |
| 23 | lib_paths: List([]const u8), | 25 | lib_paths: List([]const u8), |
| 24 | include_paths: List([]const u8), | 26 | include_paths: List([]const u8), |
| ... | @@ -33,7 +35,9 @@ pub const Builder = struct { | ... | @@ -33,7 +35,9 @@ pub const Builder = struct { |
| 33 | env_map: BufMap, | 35 | env_map: BufMap, |
| 34 | top_level_steps: List(&TopLevelStep), | 36 | top_level_steps: List(&TopLevelStep), |
| 35 | prefix: []const u8, | 37 | prefix: []const u8, |
| | 38 | lib_dir: []const u8, |
| 36 | out_dir: []u8, | 39 | out_dir: []u8, |
| | 40 | installed_files: List([]const u8), |
| 37 | | 41 | |
| 38 | const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8); | 42 | const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8); |
| 39 | const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8); | 43 | const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8); |
| ... | @@ -85,7 +89,14 @@ pub const Builder = struct { | ... | @@ -85,7 +89,14 @@ pub const Builder = struct { |
| 85 | .default_step = undefined, | 89 | .default_step = undefined, |
| 86 | .env_map = %%os.getEnvMap(allocator), | 90 | .env_map = %%os.getEnvMap(allocator), |
| 87 | .prefix = undefined, | 91 | .prefix = undefined, |
| | 92 | .lib_dir = undefined, |
| 88 | .out_dir = %%os.getCwd(allocator), | 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 | self.processNixOSEnvVars(); | 101 | self.processNixOSEnvVars(); |
| 91 | self.default_step = self.step("default", "Build the project"); | 102 | self.default_step = self.step("default", "Build the project"); |
| ... | @@ -102,12 +113,8 @@ pub const Builder = struct { | ... | @@ -102,12 +113,8 @@ pub const Builder = struct { |
| 102 | } | 113 | } |
| 103 | | 114 | |
| 104 | pub fn setInstallPrefix(self: &Builder, maybe_prefix: ?[]const u8) { | 115 | pub fn setInstallPrefix(self: &Builder, maybe_prefix: ?[]const u8) { |
| 105 | if (const prefix ?= maybe_prefix) { | 116 | self.prefix = maybe_prefix ?? "/usr/local"; // TODO better default |
| 106 | self.prefix = prefix; | 117 | self.lib_dir = %%os.path.join(self.allocator, self.prefix, "lib"); |
| 107 | return; | | |
| 108 | } | | |
| 109 | // TODO better default | | |
| 110 | self.prefix = "/usr/local"; | | |
| 111 | } | 118 | } |
| 112 | | 119 | |
| 113 | pub fn addExecutable(self: &Builder, name: []const u8, root_src: []const u8) -> &Exe { | 120 | pub fn addExecutable(self: &Builder, name: []const u8, root_src: []const u8) -> &Exe { |
| ... | @@ -180,6 +187,27 @@ pub const Builder = struct { | ... | @@ -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 | fn makeOneStep(self: &Builder, s: &Step) -> %void { | 211 | fn makeOneStep(self: &Builder, s: &Step) -> %void { |
| 184 | if (s.loop_flag) { | 212 | if (s.loop_flag) { |
| 185 | %%io.stderr.printf("Dependency loop detected:\n {}\n", s.name); | 213 | %%io.stderr.printf("Dependency loop detected:\n {}\n", s.name); |
| ... | @@ -426,6 +454,34 @@ pub const Builder = struct { | ... | @@ -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 | const Version = struct { | 487 | const Version = struct { |
| ... | @@ -616,6 +672,8 @@ const CLibrary = struct { | ... | @@ -616,6 +672,8 @@ const CLibrary = struct { |
| 616 | target: Target, | 672 | target: Target, |
| 617 | builder: &Builder, | 673 | builder: &Builder, |
| 618 | include_dirs: List([]const u8), | 674 | include_dirs: List([]const u8), |
| | 675 | major_only_filename: []const u8, |
| | 676 | name_only_filename: []const u8, |
| 619 | | 677 | |
| 620 | pub fn initShared(builder: &Builder, name: []const u8, version: &const Version) -> CLibrary { | 678 | pub fn initShared(builder: &Builder, name: []const u8, version: &const Version) -> CLibrary { |
| 621 | return init(builder, name, version, false); | 679 | return init(builder, name, version, false); |
| ... | @@ -639,6 +697,8 @@ const CLibrary = struct { | ... | @@ -639,6 +697,8 @@ const CLibrary = struct { |
| 639 | .link_libs = BufSet.init(builder.allocator), | 697 | .link_libs = BufSet.init(builder.allocator), |
| 640 | .include_dirs = List([]const u8).init(builder.allocator), | 698 | .include_dirs = List([]const u8).init(builder.allocator), |
| 641 | .out_filename = undefined, | 699 | .out_filename = undefined, |
| | 700 | .major_only_filename = undefined, |
| | 701 | .name_only_filename = undefined, |
| 642 | }; | 702 | }; |
| 643 | clib.computeOutFileName(); | 703 | clib.computeOutFileName(); |
| 644 | return clib; | 704 | return clib; |
| ... | @@ -650,6 +710,10 @@ const CLibrary = struct { | ... | @@ -650,6 +710,10 @@ const CLibrary = struct { |
| 650 | } else { | 710 | } else { |
| 651 | self.out_filename = %%fmt.allocPrint(self.builder.allocator, "lib{}.so.{d}.{d}.{d}", | 711 | self.out_filename = %%fmt.allocPrint(self.builder.allocator, "lib{}.so.{d}.{d}.{d}", |
| 652 | self.name, self.version.major, self.version.minor, self.version.patch); | 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,15 +816,11 @@ const CLibrary = struct { |
| 752 | builder.spawnChild(cc, cc_args.toSliceConst()); | 816 | builder.spawnChild(cc, cc_args.toSliceConst()); |
| 753 | | 817 | |
| 754 | // sym link for libfoo.so.1 to libfoo.so.1.2.3 | 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); | 819 | _ = os.deleteFile(builder.allocator, self.major_only_filename); |
| 756 | defer builder.allocator.free(major_only); | 820 | %%os.symLink(builder.allocator, self.out_filename, self.major_only_filename); |
| 757 | _ = os.deleteFile(builder.allocator, major_only); | | |
| 758 | %%os.symLink(builder.allocator, self.out_filename, major_only); | | |
| 759 | // sym link for libfoo.so to libfoo.so.1 | 821 | // sym link for libfoo.so to libfoo.so.1 |
| 760 | const name_only = %%fmt.allocPrint(builder.allocator, "lib{}.so", self.name); | 822 | _ = os.deleteFile(builder.allocator, self.name_only_filename); |
| 761 | defer builder.allocator.free(name_only); | 823 | %%os.symLink(builder.allocator, self.major_only_filename, self.name_only_filename); |
| 762 | _ = os.deleteFile(builder.allocator, name_only); | | |
| 763 | %%os.symLink(builder.allocator, major_only, name_only); | | |
| 764 | } | 824 | } |
| 765 | } | 825 | } |
| 766 | | 826 | |
| ... | @@ -938,6 +998,71 @@ const CommandStep = struct { | ... | @@ -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 | const Step = struct { | 1066 | const Step = struct { |
| 942 | name: []const u8, | 1067 | name: []const u8, |
| 943 | makeFn: fn(self: &Step) -> %void, | 1068 | makeFn: fn(self: &Step) -> %void, |
| ... | @@ -972,25 +1097,3 @@ const Step = struct { | ... | @@ -972,25 +1097,3 @@ const Step = struct { |
| 972 | | 1097 | |
| 973 | fn makeNoOp(self: &Step) -> %void {} | 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 | } | | |