zig build system: progress toward install and uninstall
also: * add std.os.path.join * add std.os.deleteFilemaster
parent
e4ec2d10c6
commit
05b3082121
|
@ -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}")
|
||||
|
|
175
std/build.zig
175
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;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"));
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue