Commit 05b3082121
Changed files (5)
std
std/os/index.zig
@@ -10,6 +10,7 @@ pub const posix = switch(@compileVar("os")) {
pub const max_noalloc_path_len = 1024;
pub const ChildProcess = @import("child_process.zig").ChildProcess;
+pub const path = @import("path.zig");
const debug = @import("../debug.zig");
const assert = debug.assert;
@@ -24,6 +25,8 @@ const Allocator = mem.Allocator;
const BufMap = @import("../buf_map.zig").BufMap;
const cstr = @import("../cstr.zig");
+const io = @import("../io.zig");
+
error Unexpected;
error SystemResources;
error AccessDenied;
@@ -134,21 +137,21 @@ pub fn posixWrite(fd: i32, bytes: []const u8) -> %void {
}
-/// ::path may need to be copied in memory to add a null terminating byte. In this case
+/// ::file_path may need to be copied in memory to add a null terminating byte. In this case
/// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed
/// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned.
/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
/// Calls POSIX open, keeps trying if it gets interrupted, and translates
/// the return value into zig errors.
-pub fn posixOpen(path: []const u8, flags: usize, perm: usize, allocator: ?&Allocator) -> %i32 {
+pub fn posixOpen(file_path: []const u8, flags: usize, perm: usize, allocator: ?&Allocator) -> %i32 {
var stack_buf: [max_noalloc_path_len]u8 = undefined;
var path0: []u8 = undefined;
var need_free = false;
- if (path.len < stack_buf.len) {
- path0 = stack_buf[0...path.len + 1];
+ if (file_path.len < stack_buf.len) {
+ path0 = stack_buf[0...file_path.len + 1];
} else if (const a ?= allocator) {
- path0 = %return a.alloc(u8, path.len + 1);
+ path0 = %return a.alloc(u8, file_path.len + 1);
need_free = true;
} else {
return error.NameTooLong;
@@ -156,8 +159,8 @@ pub fn posixOpen(path: []const u8, flags: usize, perm: usize, allocator: ?&Alloc
defer if (need_free) {
(??allocator).free(path0);
};
- mem.copy(u8, path0, path);
- path0[path.len] = 0;
+ mem.copy(u8, path0, file_path);
+ path0[file_path.len] = 0;
while (true) {
const result = posix.open(path0.ptr, flags, perm);
@@ -416,12 +419,12 @@ pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []con
}
}
-pub fn deleteFile(allocator: &Allocator, path: []const u8) -> %void {
- const buf = %return allocator.alloc(u8, path.len + 1);
+pub fn deleteFile(allocator: &Allocator, file_path: []const u8) -> %void {
+ const buf = %return allocator.alloc(u8, file_path.len + 1);
defer allocator.free(buf);
- mem.copy(u8, buf, path);
- buf[path.len] = 0;
+ mem.copy(u8, buf, file_path);
+ buf[file_path.len] = 0;
const err = posix.getErrno(posix.unlink(buf.ptr));
if (err > 0) {
@@ -440,3 +443,19 @@ pub fn deleteFile(allocator: &Allocator, path: []const u8) -> %void {
};
}
}
+
+pub fn copyFile(allocator: &Allocator, source_path: []const u8, dest_path: []const u8) -> %void {
+ var in_stream = %return io.InStream.open(source_path, allocator);
+ defer in_stream.close();
+ var out_stream = %return io.OutStream.open(dest_path, allocator);
+ defer out_stream.close();
+
+ const buf = out_stream.buffer[0...];
+ while (true) {
+ const amt = %return in_stream.read(buf);
+ out_stream.index = amt;
+ %return out_stream.flush();
+ if (amt != out_stream.buffer.len)
+ return;
+ }
+}
std/os/path.zig
@@ -0,0 +1,25 @@
+const debug = @import("../debug.zig");
+const assert = debug.assert;
+const mem = @import("../mem.zig");
+const Allocator = mem.Allocator;
+
+/// Allocates memory for the result, which must be freed by the caller.
+pub fn join(allocator: &Allocator, dirname: []const u8, basename: []const u8) -> %[]const u8 {
+ const buf = %return allocator.alloc(u8, dirname.len + basename.len + 1);
+ %defer allocator.free(buf);
+
+ mem.copy(u8, buf, dirname);
+ if (dirname[dirname.len - 1] == '/') {
+ mem.copy(u8, buf[dirname.len...], basename);
+ return buf[0...buf.len - 1];
+ } else {
+ buf[dirname.len] = '/';
+ mem.copy(u8, buf[dirname.len + 1 ...], basename);
+ return buf;
+ }
+}
+
+test "os.path.join" {
+ assert(mem.eql(u8, %%join(&debug.global_allocator, "/a/b", "c"), "/a/b/c"));
+ assert(mem.eql(u8, %%join(&debug.global_allocator, "/a/b/", "c"), "/a/b/c"));
+}
std/special/build_runner.zig
@@ -80,6 +80,7 @@ fn usage(builder: &Builder, maybe_zig_exe: ?[]const u8, already_ran_build: bool,
// run the build script to collect the options
if (!already_ran_build) {
+ builder.setInstallPrefix(null);
root.build(builder);
}
std/build.zig
@@ -19,6 +19,8 @@ error DependencyLoopDetected;
error NoCompilerFound;
pub const Builder = struct {
+ uninstall_tls: TopLevelStep,
+ have_uninstall_step: bool,
allocator: &Allocator,
lib_paths: List([]const u8),
include_paths: List([]const u8),
@@ -33,7 +35,9 @@ pub const Builder = struct {
env_map: BufMap,
top_level_steps: List(&TopLevelStep),
prefix: []const u8,
+ lib_dir: []const u8,
out_dir: []u8,
+ installed_files: List([]const u8),
const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8);
const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8);
@@ -85,7 +89,14 @@ pub const Builder = struct {
.default_step = undefined,
.env_map = %%os.getEnvMap(allocator),
.prefix = undefined,
+ .lib_dir = undefined,
.out_dir = %%os.getCwd(allocator),
+ .installed_files = List([]const u8).init(allocator),
+ .uninstall_tls = TopLevelStep {
+ .step = Step.init("uninstall", allocator, makeUninstall),
+ .description = "Remove build artifacts from prefix path",
+ },
+ .have_uninstall_step = false,
};
self.processNixOSEnvVars();
self.default_step = self.step("default", "Build the project");
@@ -102,12 +113,8 @@ pub const Builder = struct {
}
pub fn setInstallPrefix(self: &Builder, maybe_prefix: ?[]const u8) {
- if (const prefix ?= maybe_prefix) {
- self.prefix = prefix;
- return;
- }
- // TODO better default
- self.prefix = "/usr/local";
+ self.prefix = maybe_prefix ?? "/usr/local"; // TODO better default
+ self.lib_dir = %%os.path.join(self.allocator, self.prefix, "lib");
}
pub fn addExecutable(self: &Builder, name: []const u8, root_src: []const u8) -> &Exe {
@@ -180,6 +187,27 @@ pub const Builder = struct {
}
}
+ pub fn getUninstallStep(self: &Builder) -> &Step {
+ if (self.have_uninstall_step)
+ return &self.uninstall_tls.step;
+
+ %%self.top_level_steps.append(&self.uninstall_tls);
+ self.have_uninstall_step = true;
+ return &self.uninstall_tls.step;
+ }
+
+ fn makeUninstall(uninstall_step: &Step) -> %void {
+ // TODO
+ // const self = @fieldParentPtr(Exe, "step", step);
+ const self = @ptrcast(&Builder, uninstall_step);
+
+ for (self.installed_files.toSliceConst()) |installed_file| {
+ _ = os.deleteFile(self.allocator, installed_file);
+ }
+
+ // TODO remove empty directories
+ }
+
fn makeOneStep(self: &Builder, s: &Step) -> %void {
if (s.loop_flag) {
%%io.stderr.printf("Dependency loop detected:\n {}\n", s.name);
@@ -426,6 +454,34 @@ pub const Builder = struct {
};
}
+
+ pub fn installCLibrary(self: &Builder, lib: &CLibrary) -> &InstallCLibraryStep {
+ const install_step = %%self.allocator.create(InstallCLibraryStep);
+ *install_step = InstallCLibraryStep.init(self, lib);
+ install_step.step.dependOn(&lib.step);
+ return install_step;
+ }
+
+ ///::dest_rel_path is relative to prefix path
+ pub fn installFile(self: &Builder, src_path: []const u8, dest_rel_path: []const u8) -> &InstallFileStep {
+ const full_dest_path = %%os.path.join(self.allocator, self.prefix, dest_rel_path);
+ self.addInstalledFile(full_dest_path);
+
+ const install_step = %%self.allocator.create(InstallFileStep);
+ *install_step = InstallFileStep.init(self, src_path, full_dest_path);
+ return install_step;
+ }
+
+ pub fn addInstalledFile(self: &Builder, full_path: []const u8) {
+ _ = self.getUninstallStep();
+ %%self.installed_files.append(full_path);
+ }
+
+ fn copyFile(self: &Builder, source_path: []const u8, dest_path: []const u8) {
+ os.copyFile(self.allocator, source_path, dest_path) %% |err| {
+ debug.panic("Unable to copy {} to {}: {}", source_path, dest_path, @errorName(err));
+ };
+ }
};
const Version = struct {
@@ -616,6 +672,8 @@ const CLibrary = struct {
target: Target,
builder: &Builder,
include_dirs: List([]const u8),
+ major_only_filename: []const u8,
+ name_only_filename: []const u8,
pub fn initShared(builder: &Builder, name: []const u8, version: &const Version) -> CLibrary {
return init(builder, name, version, false);
@@ -639,6 +697,8 @@ const CLibrary = struct {
.link_libs = BufSet.init(builder.allocator),
.include_dirs = List([]const u8).init(builder.allocator),
.out_filename = undefined,
+ .major_only_filename = undefined,
+ .name_only_filename = undefined,
};
clib.computeOutFileName();
return clib;
@@ -650,6 +710,10 @@ const CLibrary = struct {
} else {
self.out_filename = %%fmt.allocPrint(self.builder.allocator, "lib{}.so.{d}.{d}.{d}",
self.name, self.version.major, self.version.minor, self.version.patch);
+ self.major_only_filename = %%fmt.allocPrint(self.builder.allocator,
+ "lib{}.so.{d}", self.name, self.version.major);
+ self.name_only_filename = %%fmt.allocPrint(self.builder.allocator,
+ "lib{}.so", self.name);
}
}
@@ -752,15 +816,11 @@ const CLibrary = struct {
builder.spawnChild(cc, cc_args.toSliceConst());
// sym link for libfoo.so.1 to libfoo.so.1.2.3
- const major_only = %%fmt.allocPrint(builder.allocator, "lib{}.so.{d}", self.name, self.version.major);
- defer builder.allocator.free(major_only);
- _ = os.deleteFile(builder.allocator, major_only);
- %%os.symLink(builder.allocator, self.out_filename, major_only);
+ _ = os.deleteFile(builder.allocator, self.major_only_filename);
+ %%os.symLink(builder.allocator, self.out_filename, self.major_only_filename);
// sym link for libfoo.so to libfoo.so.1
- const name_only = %%fmt.allocPrint(builder.allocator, "lib{}.so", self.name);
- defer builder.allocator.free(name_only);
- _ = os.deleteFile(builder.allocator, name_only);
- %%os.symLink(builder.allocator, major_only, name_only);
+ _ = os.deleteFile(builder.allocator, self.name_only_filename);
+ %%os.symLink(builder.allocator, self.major_only_filename, self.name_only_filename);
}
}
@@ -938,6 +998,71 @@ const CommandStep = struct {
}
};
+const InstallCLibraryStep = struct {
+ step: Step,
+ builder: &Builder,
+ lib: &CLibrary,
+ dest_file: []const u8,
+
+ pub fn init(builder: &Builder, lib: &CLibrary) -> InstallCLibraryStep {
+ var self = InstallCLibraryStep {
+ .builder = builder,
+ .step = Step.init(
+ %%fmt.allocPrint(builder.allocator, "install {}", lib.step.name),
+ builder.allocator, make),
+ .lib = lib,
+ .dest_file = undefined,
+ };
+ self.dest_file = %%os.path.join(builder.allocator, builder.lib_dir, lib.out_filename);
+ builder.addInstalledFile(self.dest_file);
+ if (!self.lib.static) {
+ builder.addInstalledFile(%%os.path.join(builder.allocator, builder.lib_dir, lib.major_only_filename));
+ builder.addInstalledFile(%%os.path.join(builder.allocator, builder.lib_dir, lib.name_only_filename));
+ }
+ return self;
+ }
+
+ fn make(step: &Step) -> %void {
+ // TODO issue #320
+ //const self = @fieldParentPtr(InstallCLibraryStep, "step", step);
+ const self = @ptrcast(&InstallCLibraryStep, step);
+
+ self.builder.copyFile(self.lib.out_filename, self.dest_file);
+ if (!self.lib.static) {
+ _ = os.deleteFile(self.builder.allocator, self.lib.major_only_filename);
+ %%os.symLink(self.builder.allocator, self.lib.out_filename, self.lib.major_only_filename);
+ _ = os.deleteFile(self.builder.allocator, self.lib.name_only_filename);
+ %%os.symLink(self.builder.allocator, self.lib.major_only_filename, self.lib.name_only_filename);
+ }
+ }
+};
+
+const InstallFileStep = struct {
+ step: Step,
+ builder: &Builder,
+ src_path: []const u8,
+ dest_path: []const u8,
+
+ pub fn init(builder: &Builder, src_path: []const u8, dest_path: []const u8) -> InstallFileStep {
+ return InstallFileStep {
+ .builder = builder,
+ .step = Step.init(
+ %%fmt.allocPrint(builder.allocator, "install {}", src_path),
+ builder.allocator, make),
+ .src_path = src_path,
+ .dest_path = dest_path,
+ };
+ }
+
+ fn make(step: &Step) -> %void {
+ // TODO issue #320
+ //const self = @fieldParentPtr(InstallFileStep, "step", step);
+ const self = @ptrcast(&InstallFileStep, step);
+
+ debug.panic("TODO install file");
+ }
+};
+
const Step = struct {
name: []const u8,
makeFn: fn(self: &Step) -> %void,
@@ -972,25 +1097,3 @@ const Step = struct {
fn makeNoOp(self: &Step) -> %void {}
};
-
-fn printInvocation(exe_name: []const u8, args: &const List([]const u8)) {
- %%io.stderr.printf("{}", exe_name);
- for (args.toSliceConst()) |arg| {
- %%io.stderr.printf(" {}", arg);
- }
- %%io.stderr.printf("\n");
-}
-
-fn waitForCleanExit(child: &os.ChildProcess) -> %void {
- const term = %%child.wait();
- switch (term) {
- Term.Clean => |code| {
- if (code != 0) {
- return error.UncleanExit;
- }
- },
- else => {
- return error.UncleanExit;
- },
- };
-}
CMakeLists.txt
@@ -233,6 +233,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/os/index.zig" DESTINATION "${ZIG_STD_DEST
install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux.zig" DESTINATION "${ZIG_STD_DEST}/os")
install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux_i386.zig" DESTINATION "${ZIG_STD_DEST}/os")
install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux_x86_64.zig" DESTINATION "${ZIG_STD_DEST}/os")
+install(FILES "${CMAKE_SOURCE_DIR}/std/os/path.zig" DESTINATION "${ZIG_STD_DEST}/os")
install(FILES "${CMAKE_SOURCE_DIR}/std/os/windows.zig" DESTINATION "${ZIG_STD_DEST}/os")
install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}")
install(FILES "${CMAKE_SOURCE_DIR}/std/rand_test.zig" DESTINATION "${ZIG_STD_DEST}")