authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-17 06:45:44-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-17 06:47:20-04:00
log05b3082121e225ec2dfc9a062c765b4b60befaef
tree166aedf2cbfd92e847e16d27a5c847757b66e704
parente4ec2d10c67542589e10e1eaf569157284171159

zig build system: progress toward install and uninstall

also: * add std.os.path.join * add std.os.deleteFile

5 files changed, 196 insertions(+), 47 deletions(-)

CMakeLists.txt+1
......@@ -233,6 +233,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/os/index.zig" DESTINATION "${ZIG_STD_DEST
233233install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux.zig" DESTINATION "${ZIG_STD_DEST}/os")
234234install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux_i386.zig" DESTINATION "${ZIG_STD_DEST}/os")
235235install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux_x86_64.zig" DESTINATION "${ZIG_STD_DEST}/os")
236install(FILES "${CMAKE_SOURCE_DIR}/std/os/path.zig" DESTINATION "${ZIG_STD_DEST}/os")
236237install(FILES "${CMAKE_SOURCE_DIR}/std/os/windows.zig" DESTINATION "${ZIG_STD_DEST}/os")
237238install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}")
238239install(FILES "${CMAKE_SOURCE_DIR}/std/rand_test.zig" DESTINATION "${ZIG_STD_DEST}")
std/build.zig+139-36
......@@ -19,6 +19,8 @@ error DependencyLoopDetected;
1919error NoCompilerFound;
2020
2121pub const Builder = struct {
22 uninstall_tls: TopLevelStep,
23 have_uninstall_step: bool,
2224 allocator: &Allocator,
2325 lib_paths: List([]const u8),
2426 include_paths: List([]const u8),
......@@ -33,7 +35,9 @@ pub const Builder = struct {
3335 env_map: BufMap,
3436 top_level_steps: List(&TopLevelStep),
3537 prefix: []const u8,
38 lib_dir: []const u8,
3639 out_dir: []u8,
40 installed_files: List([]const u8),
3741
3842 const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8);
3943 const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8);
......@@ -85,7 +89,14 @@ pub const Builder = struct {
8589 .default_step = undefined,
8690 .env_map = %%os.getEnvMap(allocator),
8791 .prefix = undefined,
92 .lib_dir = undefined,
8893 .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,
89100 };
90101 self.processNixOSEnvVars();
91102 self.default_step = self.step("default", "Build the project");
......@@ -102,12 +113,8 @@ pub const Builder = struct {
102113 }
103114
104115 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");
111118 }
112119
113120 pub fn addExecutable(self: &Builder, name: []const u8, root_src: []const u8) -> &Exe {
......@@ -180,6 +187,27 @@ pub const Builder = struct {
180187 }
181188 }
182189
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
183211 fn makeOneStep(self: &Builder, s: &Step) -> %void {
184212 if (s.loop_flag) {
185213 %%io.stderr.printf("Dependency loop detected:\n {}\n", s.name);
......@@ -426,6 +454,34 @@ pub const Builder = struct {
426454 };
427455
428456 }
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 }
429485};
430486
431487const Version = struct {
......@@ -616,6 +672,8 @@ const CLibrary = struct {
616672 target: Target,
617673 builder: &Builder,
618674 include_dirs: List([]const u8),
675 major_only_filename: []const u8,
676 name_only_filename: []const u8,
619677
620678 pub fn initShared(builder: &Builder, name: []const u8, version: &const Version) -> CLibrary {
621679 return init(builder, name, version, false);
......@@ -639,6 +697,8 @@ const CLibrary = struct {
639697 .link_libs = BufSet.init(builder.allocator),
640698 .include_dirs = List([]const u8).init(builder.allocator),
641699 .out_filename = undefined,
700 .major_only_filename = undefined,
701 .name_only_filename = undefined,
642702 };
643703 clib.computeOutFileName();
644704 return clib;
......@@ -650,6 +710,10 @@ const CLibrary = struct {
650710 } else {
651711 self.out_filename = %%fmt.allocPrint(self.builder.allocator, "lib{}.so.{d}.{d}.{d}",
652712 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);
653717 }
654718 }
655719
......@@ -752,15 +816,11 @@ const CLibrary = struct {
752816 builder.spawnChild(cc, cc_args.toSliceConst());
753817
754818 // 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);
759821 // 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);
764824 }
765825 }
766826
......@@ -938,6 +998,71 @@ const CommandStep = struct {
938998 }
939999};
9401000
1001const 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
1040const 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
9411066const Step = struct {
9421067 name: []const u8,
9431068 makeFn: fn(self: &Step) -> %void,
......@@ -972,25 +1097,3 @@ const Step = struct {
9721097
9731098 fn makeNoOp(self: &Step) -> %void {}
9741099};
975
976fn 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
984fn 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}
std/os/index.zig+30-11
......@@ -10,6 +10,7 @@ pub const posix = switch(@compileVar("os")) {
1010
1111pub const max_noalloc_path_len = 1024;
1212pub const ChildProcess = @import("child_process.zig").ChildProcess;
13pub const path = @import("path.zig");
1314
1415const debug = @import("../debug.zig");
1516const assert = debug.assert;
......@@ -24,6 +25,8 @@ const Allocator = mem.Allocator;
2425const BufMap = @import("../buf_map.zig").BufMap;
2526const cstr = @import("../cstr.zig");
2627
28const io = @import("../io.zig");
29
2730error Unexpected;
2831error SystemResources;
2932error AccessDenied;
......@@ -134,21 +137,21 @@ pub fn posixWrite(fd: i32, bytes: []const u8) -> %void {
134137}
135138
136139
137/// ::path may need to be copied in memory to add a null terminating byte. In this case
140/// ::file_path may need to be copied in memory to add a null terminating byte. In this case
138141/// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed
139142/// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned.
140143/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
141144/// Calls POSIX open, keeps trying if it gets interrupted, and translates
142145/// the return value into zig errors.
143pub fn posixOpen(path: []const u8, flags: usize, perm: usize, allocator: ?&Allocator) -> %i32 {
146pub fn posixOpen(file_path: []const u8, flags: usize, perm: usize, allocator: ?&Allocator) -> %i32 {
144147 var stack_buf: [max_noalloc_path_len]u8 = undefined;
145148 var path0: []u8 = undefined;
146149 var need_free = false;
147150
148 if (path.len < stack_buf.len) {
149 path0 = stack_buf[0...path.len + 1];
151 if (file_path.len < stack_buf.len) {
152 path0 = stack_buf[0...file_path.len + 1];
150153 } else if (const a ?= allocator) {
151 path0 = %return a.alloc(u8, path.len + 1);
154 path0 = %return a.alloc(u8, file_path.len + 1);
152155 need_free = true;
153156 } else {
154157 return error.NameTooLong;
......@@ -156,8 +159,8 @@ pub fn posixOpen(path: []const u8, flags: usize, perm: usize, allocator: ?&Alloc
156159 defer if (need_free) {
157160 (??allocator).free(path0);
158161 };
159 mem.copy(u8, path0, path);
160 path0[path.len] = 0;
162 mem.copy(u8, path0, file_path);
163 path0[file_path.len] = 0;
161164
162165 while (true) {
163166 const result = posix.open(path0.ptr, flags, perm);
......@@ -416,12 +419,12 @@ pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []con
416419 }
417420}
418421
419pub fn deleteFile(allocator: &Allocator, path: []const u8) -> %void {
420 const buf = %return allocator.alloc(u8, path.len + 1);
422pub fn deleteFile(allocator: &Allocator, file_path: []const u8) -> %void {
423 const buf = %return allocator.alloc(u8, file_path.len + 1);
421424 defer allocator.free(buf);
422425
423 mem.copy(u8, buf, path);
424 buf[path.len] = 0;
426 mem.copy(u8, buf, file_path);
427 buf[file_path.len] = 0;
425428
426429 const err = posix.getErrno(posix.unlink(buf.ptr));
427430 if (err > 0) {
......@@ -440,3 +443,19 @@ pub fn deleteFile(allocator: &Allocator, path: []const u8) -> %void {
440443 };
441444 }
442445}
446
447pub fn copyFile(allocator: &Allocator, source_path: []const u8, dest_path: []const u8) -> %void {
448 var in_stream = %return io.InStream.open(source_path, allocator);
449 defer in_stream.close();
450 var out_stream = %return io.OutStream.open(dest_path, allocator);
451 defer out_stream.close();
452
453 const buf = out_stream.buffer[0...];
454 while (true) {
455 const amt = %return in_stream.read(buf);
456 out_stream.index = amt;
457 %return out_stream.flush();
458 if (amt != out_stream.buffer.len)
459 return;
460 }
461}
std/os/path.zig created+25
......@@ -0,0 +1,25 @@
1const debug = @import("../debug.zig");
2const assert = debug.assert;
3const mem = @import("../mem.zig");
4const Allocator = mem.Allocator;
5
6/// Allocates memory for the result, which must be freed by the caller.
7pub fn join(allocator: &Allocator, dirname: []const u8, basename: []const u8) -> %[]const u8 {
8 const buf = %return allocator.alloc(u8, dirname.len + basename.len + 1);
9 %defer allocator.free(buf);
10
11 mem.copy(u8, buf, dirname);
12 if (dirname[dirname.len - 1] == '/') {
13 mem.copy(u8, buf[dirname.len...], basename);
14 return buf[0...buf.len - 1];
15 } else {
16 buf[dirname.len] = '/';
17 mem.copy(u8, buf[dirname.len + 1 ...], basename);
18 return buf;
19 }
20}
21
22test "os.path.join" {
23 assert(mem.eql(u8, %%join(&debug.global_allocator, "/a/b", "c"), "/a/b/c"));
24 assert(mem.eql(u8, %%join(&debug.global_allocator, "/a/b/", "c"), "/a/b/c"));
25}
std/special/build_runner.zig+1
......@@ -80,6 +80,7 @@ fn usage(builder: &Builder, maybe_zig_exe: ?[]const u8, already_ran_build: bool,
8080
8181 // run the build script to collect the options
8282 if (!already_ran_build) {
83 builder.setInstallPrefix(null);
8384 root.build(builder);
8485 }
8586