aboutsummaryrefslogtreecommitdiff
path: root/std
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2019-03-10 13:48:06 -0400
committerAndrew Kelley <andrew@ziglang.org>2019-03-10 13:48:06 -0400
commit3cdd2c0bddebf82a3ec7b187014acf2e7507a79c (patch)
tree4f38ce2307e32b518c8c65b12a186d054876f8dc /std
parent0714e19598e91f457d3d0119856fd7a24dd4f150 (diff)
parent0a8a7a57e7a6b4b5a0d1523bde57b2a4b93fa50a (diff)
downloadzig-3cdd2c0bddebf82a3ec7b187014acf2e7507a79c.tar.gz
zig-3cdd2c0bddebf82a3ec7b187014acf2e7507a79c.zip
Merge remote-tracking branch 'origin/master' into llvm8
Diffstat (limited to 'std')
-rw-r--r--std/build.zig488
-rw-r--r--std/event/future.zig2
-rw-r--r--std/event/loop.zig4
-rw-r--r--std/event/rwlock.zig2
-rw-r--r--std/os.zig34
-rw-r--r--std/os/child_process.zig2
-rw-r--r--std/os/windows/util.zig8
-rw-r--r--std/priority_queue.zig80
-rw-r--r--std/special/builtin.zig2
-rw-r--r--std/special/compiler_rt.zig1
-rw-r--r--std/special/compiler_rt/popcountdi2.zig24
-rw-r--r--std/special/compiler_rt/popcountdi2_test.zig27
-rw-r--r--std/special/init-exe/build.zig4
13 files changed, 443 insertions, 235 deletions
diff --git a/std/build.zig b/std/build.zig
index 2316a87b31..e7d73b37c0 100644
--- a/std/build.zig
+++ b/std/build.zig
@@ -183,9 +183,20 @@ pub const Builder = struct {
return obj_step;
}
- /// ::argv is copied.
- pub fn addCommand(self: *Builder, cwd: ?[]const u8, env_map: *const BufMap, argv: []const []const u8) *CommandStep {
- return CommandStep.create(self, cwd, env_map, argv);
+ /// Initializes a RunStep with argv, which must at least have the path to the
+ /// executable. More command line arguments can be added with `addArg`,
+ /// `addArgs`, and `addArtifactArg`.
+ /// Be careful using this function, as it introduces a system dependency.
+ /// To run an executable built with zig build, see `LibExeObjStep.run`.
+ pub fn addSystemCommand(self: *Builder, argv: []const []const u8) *RunStep {
+ assert(argv.len >= 1);
+ const run_step = RunStep.create(self, self.fmt("run {}", argv[0]));
+ run_step.addArgs(argv);
+ return run_step;
+ }
+
+ fn dupe(self: *Builder, bytes: []const u8) []u8 {
+ return mem.dupe(self.allocator, u8, bytes) catch unreachable;
}
pub fn addWriteFile(self: *Builder, file_path: []const u8, data: []const u8) *WriteFileStep {
@@ -702,25 +713,42 @@ pub const Builder = struct {
}
pub fn exec(self: *Builder, argv: []const []const u8) ![]u8 {
+ assert(argv.len != 0);
+
const max_output_size = 100 * 1024;
- const result = try os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size);
- switch (result.term) {
+ const child = try os.ChildProcess.init(argv, self.allocator);
+ defer child.deinit();
+
+ child.stdin_behavior = os.ChildProcess.StdIo.Ignore;
+ child.stdout_behavior = os.ChildProcess.StdIo.Pipe;
+ child.stderr_behavior = os.ChildProcess.StdIo.Inherit;
+
+ try child.spawn();
+
+ var stdout = std.Buffer.initNull(self.allocator);
+ defer std.Buffer.deinit(&stdout);
+
+ var stdout_file_in_stream = child.stdout.?.inStream();
+ try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size);
+
+ const term = child.wait() catch |err| std.debug.panic("unable to spawn {}: {}", argv[0], err);
+ switch (term) {
os.ChildProcess.Term.Exited => |code| {
if (code != 0) {
warn("The following command exited with error code {}:\n", code);
printCmd(null, argv);
- warn("stderr:{}\n", result.stderr);
- std.debug.panic("command failed");
+ std.debug.panic("exec failed");
}
- return result.stdout;
+ return stdout.toOwnedSlice();
},
else => {
warn("The following command terminated unexpectedly:\n");
printCmd(null, argv);
- warn("stderr:{}\n", result.stderr);
- std.debug.panic("command failed");
+ std.debug.panic("exec failed");
},
}
+
+ return stdout.toOwnedSlice();
}
pub fn addSearchPrefix(self: *Builder, search_prefix: []const u8) void {
@@ -837,26 +865,20 @@ pub const LibExeObjStep = struct {
builder: *Builder,
name: []const u8,
target: Target,
- link_libs: BufSet,
linker_script: ?[]const u8,
out_filename: []const u8,
- output_path: ?[]const u8,
- output_lib_path: ?[]const u8,
static: bool,
version: Version,
- object_files: ArrayList([]const u8),
build_mode: builtin.Mode,
kind: Kind,
major_only_filename: []const u8,
name_only_filename: []const u8,
strip: bool,
- full_path_libs: ArrayList([]const u8),
- need_flat_namespace_hack: bool,
- include_dirs: ArrayList([]const u8),
lib_paths: ArrayList([]const u8),
frameworks: BufSet,
verbose_link: bool,
verbose_cc: bool,
+ disable_gen_h: bool,
c_std: Builder.CStd,
override_std_dir: ?[]const u8,
main_pkg_path: ?[]const u8,
@@ -865,17 +887,31 @@ pub const LibExeObjStep = struct {
filter: ?[]const u8,
root_src: ?[]const u8,
- output_h_path: ?[]const u8,
out_h_filename: []const u8,
out_lib_filename: []const u8,
- assembly_files: ArrayList([]const u8),
packages: ArrayList(Pkg),
build_options_contents: std.Buffer,
system_linker_hack: bool,
- c_source_files: ArrayList(*CSourceFile),
object_src: []const u8,
+ link_objects: ArrayList(LinkObject),
+ include_dirs: ArrayList(IncludeDir),
+ output_dir: ?[]const u8,
+
+ const LinkObject = union(enum) {
+ StaticPath: []const u8,
+ OtherStep: *LibExeObjStep,
+ SystemLib: []const u8,
+ AssemblyFile: []const u8,
+ CSourceFile: *CSourceFile,
+ };
+
+ const IncludeDir = union(enum) {
+ RawPath: []const u8,
+ OtherStep: *LibExeObjStep,
+ };
+
const Kind = enum {
Exe,
Lib,
@@ -926,25 +962,17 @@ pub const LibExeObjStep = struct {
.name = name,
.target = Target.Native,
.linker_script = null,
- .link_libs = BufSet.init(builder.allocator),
.frameworks = BufSet.init(builder.allocator),
.step = Step.init(name, builder.allocator, make),
- .output_path = null,
- .output_lib_path = null,
- .output_h_path = null,
.version = ver,
.out_filename = undefined,
.out_h_filename = builder.fmt("{}.h", name),
.out_lib_filename = undefined,
.major_only_filename = undefined,
.name_only_filename = undefined,
- .object_files = ArrayList([]const u8).init(builder.allocator),
- .assembly_files = ArrayList([]const u8).init(builder.allocator),
.packages = ArrayList(Pkg).init(builder.allocator),
- .full_path_libs = ArrayList([]const u8).init(builder.allocator),
- .need_flat_namespace_hack = false,
- .c_source_files = ArrayList(*CSourceFile).init(builder.allocator),
- .include_dirs = ArrayList([]const u8).init(builder.allocator),
+ .include_dirs = ArrayList(IncludeDir).init(builder.allocator),
+ .link_objects = ArrayList(LinkObject).init(builder.allocator),
.lib_paths = ArrayList([]const u8).init(builder.allocator),
.object_src = undefined,
.build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable,
@@ -955,6 +983,8 @@ pub const LibExeObjStep = struct {
.exec_cmd_args = null,
.name_prefix = "",
.filter = null,
+ .disable_gen_h = false,
+ .output_dir = null,
};
self.computeOutFileNames();
return self;
@@ -1022,7 +1052,20 @@ pub const LibExeObjStep = struct {
self.computeOutFileNames();
}
- // TODO respect this in the C args
+ pub fn setOutputDir(self: *LibExeObjStep, dir: []const u8) void {
+ self.output_dir = self.builder.dupe(dir);
+ }
+
+ /// Creates a `RunStep` with an executable built with `addExecutable`.
+ /// Add command line arguments with `addArg`.
+ pub fn run(exe: *LibExeObjStep) *RunStep {
+ assert(exe.kind == Kind.Exe);
+ assert(exe.target == Target.Native);
+ const run_step = RunStep.create(exe.builder, exe.builder.fmt("run {}", exe.step.name));
+ run_step.addArtifactArg(exe);
+ return run_step;
+ }
+
pub fn setLinkerScriptPath(self: *LibExeObjStep, path: []const u8) void {
self.linker_script = path;
}
@@ -1032,37 +1075,28 @@ pub const LibExeObjStep = struct {
self.frameworks.put(framework_name) catch unreachable;
}
- pub fn linkLibrary(self: *LibExeObjStep, lib: *LibExeObjStep) void {
- assert(self.kind != Kind.Obj);
- assert(lib.kind == Kind.Lib);
-
- self.step.dependOn(&lib.step);
-
- if (lib.static or self.target.isWindows()) {
- self.object_files.append(lib.getOutputLibPath()) catch unreachable;
- } else {
- self.full_path_libs.append(lib.getOutputPath()) catch unreachable;
- }
-
- if (lib.link_libs.exists("c")) {
- self.link_libs.put("c") catch unreachable;
+ /// Returns whether the library, executable, or object depends on a particular system library.
+ pub fn dependsOnSystemLibrary(self: LibExeObjStep, name: []const u8) bool {
+ for (self.link_objects.toSliceConst()) |link_object| {
+ switch (link_object) {
+ LinkObject.SystemLib => |n| if (mem.eql(u8, n, name)) return true,
+ else => continue,
+ }
}
+ return false;
+ }
- // TODO should be some kind of isolated directory that only has this header in it
- self.include_dirs.append(self.builder.cache_root) catch unreachable;
- self.need_flat_namespace_hack = true;
+ pub fn linkLibrary(self: *LibExeObjStep, lib: *LibExeObjStep) void {
+ assert(lib.kind == Kind.Lib);
+ self.linkLibraryOrObject(lib);
+ }
- // inherit the object's frameworks
- if (self.target.isDarwin() and lib.static) {
- var it = lib.frameworks.iterator();
- while (it.next()) |entry| {
- self.frameworks.put(entry.key) catch unreachable;
- }
- }
+ pub fn isDynamicLibrary(self: *LibExeObjStep) bool {
+ return self.kind == Kind.Lib and !self.static;
}
pub fn linkSystemLibrary(self: *LibExeObjStep, name: []const u8) void {
- self.link_libs.put(name) catch unreachable;
+ self.link_objects.append(LinkObject{ .SystemLib = self.builder.dupe(name) }) catch unreachable;
}
pub fn setNamePrefix(self: *LibExeObjStep, text: []const u8) void {
@@ -1077,11 +1111,15 @@ pub const LibExeObjStep = struct {
pub fn addCSourceFile(self: *LibExeObjStep, file: []const u8, args: []const []const u8) void {
const c_source_file = self.builder.allocator.create(CSourceFile) catch unreachable;
+ const args_copy = self.builder.allocator.alloc([]u8, args.len) catch unreachable;
+ for (args) |arg, i| {
+ args_copy[i] = self.builder.dupe(arg);
+ }
c_source_file.* = CSourceFile{
- .source_path = file,
- .args = args,
+ .source_path = self.builder.dupe(file),
+ .args = args_copy,
};
- self.c_source_files.append(c_source_file) catch unreachable;
+ self.link_objects.append(LinkObject{ .CSourceFile = c_source_file }) catch unreachable;
}
pub fn setVerboseLink(self: *LibExeObjStep, value: bool) void {
@@ -1104,78 +1142,48 @@ pub const LibExeObjStep = struct {
self.main_pkg_path = dir_path;
}
- pub fn setOutputPath(self: *LibExeObjStep, file_path: []const u8) void {
- self.output_path = file_path;
-
- // catch a common mistake
- if (mem.eql(u8, self.builder.pathFromRoot(file_path), self.builder.pathFromRoot("."))) {
- debug.panic("setOutputPath wants a file path, not a directory\n");
- }
- }
-
+ /// Unless setOutputDir was called, this function must be called only in
+ /// the make step, from a step that has declared a dependency on this one.
+ /// To run an executable built with zig build, use `run`, or create an install step and invoke it.
pub fn getOutputPath(self: *LibExeObjStep) []const u8 {
- return if (self.output_path) |output_path| output_path else os.path.join(
+ return os.path.join(
self.builder.allocator,
- [][]const u8{ self.builder.cache_root, self.out_filename },
+ [][]const u8{ self.output_dir.?, self.out_filename },
) catch unreachable;
}
- pub fn setOutputLibPath(self: *LibExeObjStep, file_path: []const u8) void {
- assert(self.kind == Kind.Lib);
- if (self.static)
- return self.setOutputPath(file_path);
-
- self.output_lib_path = file_path;
- }
-
+ /// Unless setOutputDir was called, this function must be called only in
+ /// the make step, from a step that has declared a dependency on this one.
pub fn getOutputLibPath(self: *LibExeObjStep) []const u8 {
assert(self.kind == Kind.Lib);
- return if (self.output_lib_path) |output_lib_path| output_lib_path else os.path.join(
+ return os.path.join(
self.builder.allocator,
- [][]const u8{ self.builder.cache_root, self.out_lib_filename },
+ [][]const u8{ self.output_dir.?, self.out_lib_filename },
) catch unreachable;
}
- pub fn setOutputHPath(self: *LibExeObjStep, file_path: []const u8) void {
- self.output_h_path = file_path;
-
- // catch a common mistake
- if (mem.eql(u8, self.builder.pathFromRoot(file_path), self.builder.pathFromRoot("."))) {
- debug.panic("setOutputHPath wants a file path, not a directory\n");
- }
- }
-
+ /// Unless setOutputDir was called, this function must be called only in
+ /// the make step, from a step that has declared a dependency on this one.
pub fn getOutputHPath(self: *LibExeObjStep) []const u8 {
- return if (self.output_h_path) |output_h_path| output_h_path else os.path.join(
+ assert(self.kind != Kind.Exe);
+ assert(!self.disable_gen_h);
+ return os.path.join(
self.builder.allocator,
- [][]const u8{ self.builder.cache_root, self.out_h_filename },
+ [][]const u8{ self.output_dir.?, self.out_h_filename },
) catch unreachable;
}
pub fn addAssemblyFile(self: *LibExeObjStep, path: []const u8) void {
- self.assembly_files.append(path) catch unreachable;
+ self.link_objects.append(LinkObject{ .AssemblyFile = self.builder.dupe(path) }) catch unreachable;
}
pub fn addObjectFile(self: *LibExeObjStep, path: []const u8) void {
- assert(self.kind != Kind.Obj);
-
- self.object_files.append(path) catch unreachable;
+ self.link_objects.append(LinkObject{ .StaticPath = self.builder.dupe(path) }) catch unreachable;
}
pub fn addObject(self: *LibExeObjStep, obj: *LibExeObjStep) void {
assert(obj.kind == Kind.Obj);
- assert(self.kind != Kind.Obj);
-
- self.step.dependOn(&obj.step);
-
- self.object_files.append(obj.getOutputPath()) catch unreachable;
-
- // TODO should be some kind of isolated directory that only has this header in it
- self.include_dirs.append(self.builder.cache_root) catch unreachable;
-
- if (obj.link_libs.exists("c")) {
- self.link_libs.put("c") catch unreachable;
- }
+ self.linkLibraryOrObject(obj);
}
pub fn addBuildOption(self: *LibExeObjStep, comptime T: type, name: []const u8, value: T) void {
@@ -1184,7 +1192,7 @@ pub const LibExeObjStep = struct {
}
pub fn addIncludeDir(self: *LibExeObjStep, path: []const u8) void {
- self.include_dirs.append(path) catch unreachable;
+ self.include_dirs.append(IncludeDir{ .RawPath = self.builder.dupe(path) }) catch unreachable;
}
pub fn addLibPath(self: *LibExeObjStep, path: []const u8) void {
@@ -1207,13 +1215,30 @@ pub const LibExeObjStep = struct {
self.system_linker_hack = true;
}
+ fn linkLibraryOrObject(self: *LibExeObjStep, other: *LibExeObjStep) void {
+ self.step.dependOn(&other.step);
+ self.link_objects.append(LinkObject{ .OtherStep = other }) catch unreachable;
+ self.include_dirs.append(IncludeDir{ .OtherStep = other }) catch unreachable;
+
+ // Inherit dependency on libc
+ if (other.dependsOnSystemLibrary("c")) {
+ self.linkSystemLibrary("c");
+ }
+
+ // Inherit dependencies on darwin frameworks
+ if (self.target.isDarwin() and !other.isDynamicLibrary()) {
+ var it = other.frameworks.iterator();
+ while (it.next()) |entry| {
+ self.frameworks.put(entry.key) catch unreachable;
+ }
+ }
+ }
+
fn make(step: *Step) !void {
const self = @fieldParentPtr(LibExeObjStep, "step", step);
const builder = self.builder;
- if (self.root_src == null and self.object_files.len == 0 and
- self.assembly_files.len == 0 and self.c_source_files.len == 0)
- {
+ if (self.root_src == null and self.link_objects.len == 0) {
warn("{}: linker needs 1 or more objects to link\n", self.step.name);
return error.NeedAnObject;
}
@@ -1235,12 +1260,52 @@ pub const LibExeObjStep = struct {
zig_args.append(builder.pathFromRoot(root_src)) catch unreachable;
}
- for (self.c_source_files.toSliceConst()) |c_source_file| {
- try zig_args.append("--c-source");
- for (c_source_file.args) |arg| {
- try zig_args.append(arg);
+ for (self.link_objects.toSlice()) |link_object| {
+ switch (link_object) {
+ LinkObject.StaticPath => |static_path| {
+ try zig_args.append("--object");
+ try zig_args.append(builder.pathFromRoot(static_path));
+ },
+
+ LinkObject.OtherStep => |other| switch (other.kind) {
+ LibExeObjStep.Kind.Exe => unreachable,
+ LibExeObjStep.Kind.Test => unreachable,
+ LibExeObjStep.Kind.Obj => {
+ try zig_args.append("--object");
+ try zig_args.append(other.getOutputPath());
+ },
+ LibExeObjStep.Kind.Lib => {
+ if (other.static or self.target.isWindows()) {
+ try zig_args.append("--object");
+ try zig_args.append(other.getOutputLibPath());
+ } else {
+ const full_path_lib = other.getOutputPath();
+ try zig_args.append("--library");
+ try zig_args.append(full_path_lib);
+
+ if (os.path.dirname(full_path_lib)) |dirname| {
+ try zig_args.append("-rpath");
+ try zig_args.append(dirname);
+ }
+ }
+ },
+ },
+ LinkObject.SystemLib => |name| {
+ try zig_args.append("--library");
+ try zig_args.append(name);
+ },
+ LinkObject.AssemblyFile => |asm_file| {
+ try zig_args.append("--assembly");
+ try zig_args.append(builder.pathFromRoot(asm_file));
+ },
+ LinkObject.CSourceFile => |c_source_file| {
+ try zig_args.append("--c-source");
+ for (c_source_file.args) |arg| {
+ try zig_args.append(arg);
+ }
+ try zig_args.append(self.builder.pathFromRoot(c_source_file.source_path));
+ },
}
- try zig_args.append(self.builder.pathFromRoot(c_source_file.source_path));
}
if (self.build_options_contents.len() > 0) {
@@ -1265,16 +1330,6 @@ pub const LibExeObjStep = struct {
try zig_args.append(self.name_prefix);
}
- for (self.object_files.toSliceConst()) |object_file| {
- zig_args.append("--object") catch unreachable;
- zig_args.append(builder.pathFromRoot(object_file)) catch unreachable;
- }
-
- for (self.assembly_files.toSliceConst()) |asm_file| {
- zig_args.append("--assembly") catch unreachable;
- zig_args.append(builder.pathFromRoot(asm_file)) catch unreachable;
- }
-
if (builder.verbose_tokenize) zig_args.append("--verbose-tokenize") catch unreachable;
if (builder.verbose_ast) zig_args.append("--verbose-ast") catch unreachable;
if (builder.verbose_cimport) zig_args.append("--verbose-cimport") catch unreachable;
@@ -1294,24 +1349,8 @@ pub const LibExeObjStep = struct {
builtin.Mode.ReleaseSmall => zig_args.append("--release-small") catch unreachable,
}
- zig_args.append("--cache-dir") catch unreachable;
- zig_args.append(builder.pathFromRoot(builder.cache_root)) catch unreachable;
-
- const output_path = builder.pathFromRoot(self.getOutputPath());
- zig_args.append("--output") catch unreachable;
- zig_args.append(output_path) catch unreachable;
-
- if (self.kind == Kind.Lib and !self.static) {
- const output_lib_path = builder.pathFromRoot(self.getOutputLibPath());
- zig_args.append("--output-lib") catch unreachable;
- zig_args.append(output_lib_path) catch unreachable;
- }
-
- if (self.kind != Kind.Exe and self.root_src != null) {
- const output_h_path = self.getOutputHPath();
- zig_args.append("--output-h") catch unreachable;
- zig_args.append(builder.pathFromRoot(output_h_path)) catch unreachable;
- }
+ try zig_args.append("--cache-dir");
+ try zig_args.append(builder.pathFromRoot(builder.cache_root));
zig_args.append("--name") catch unreachable;
zig_args.append(self.name) catch unreachable;
@@ -1351,15 +1390,6 @@ pub const LibExeObjStep = struct {
zig_args.append(linker_script) catch unreachable;
}
- {
- var it = self.link_libs.iterator();
- while (true) {
- const entry = it.next() orelse break;
- zig_args.append("--library") catch unreachable;
- zig_args.append(entry.key) catch unreachable;
- }
- }
-
if (self.exec_cmd_args) |exec_cmd_args| {
for (exec_cmd_args) |cmd_arg| {
if (cmd_arg) |arg| {
@@ -1377,9 +1407,18 @@ pub const LibExeObjStep = struct {
zig_args.append("--pkg-end") catch unreachable;
}
- for (self.include_dirs.toSliceConst()) |include_path| {
- zig_args.append("-isystem") catch unreachable;
- zig_args.append(self.builder.pathFromRoot(include_path)) catch unreachable;
+ for (self.include_dirs.toSliceConst()) |include_dir| {
+ switch (include_dir) {
+ IncludeDir.RawPath => |include_path| {
+ try zig_args.append("-isystem");
+ try zig_args.append(self.builder.pathFromRoot(include_path));
+ },
+ IncludeDir.OtherStep => |other| {
+ const h_path = other.getOutputHPath();
+ try zig_args.append("-isystem");
+ try zig_args.append(os.path.dirname(h_path).?);
+ },
+ }
}
for (builder.include_paths.toSliceConst()) |include_path| {
@@ -1402,17 +1441,6 @@ pub const LibExeObjStep = struct {
zig_args.append(lib_path) catch unreachable;
}
- for (self.full_path_libs.toSliceConst()) |full_path_lib| {
- try zig_args.append("--library");
- try zig_args.append(builder.pathFromRoot(full_path_lib));
-
- const full_path_lib_abs = builder.pathFromRoot(full_path_lib);
- if (os.path.dirname(full_path_lib_abs)) |dirname| {
- try zig_args.append("-rpath");
- try zig_args.append(dirname);
- }
- }
-
if (self.target.isDarwin()) {
var it = self.frameworks.iterator();
while (it.next()) |entry| {
@@ -1435,42 +1463,132 @@ pub const LibExeObjStep = struct {
try zig_args.append(builder.pathFromRoot(dir));
}
- try builder.spawnChild(zig_args.toSliceConst());
+ if (self.output_dir) |output_dir| {
+ try zig_args.append("--output-dir");
+ try zig_args.append(output_dir);
+
+ try builder.spawnChild(zig_args.toSliceConst());
+ } else if (self.kind == Kind.Test) {
+ try builder.spawnChild(zig_args.toSliceConst());
+ } else {
+ try zig_args.append("--cache");
+ try zig_args.append("on");
+
+ const output_path_nl = try builder.exec(zig_args.toSliceConst());
+ const output_path = mem.trimRight(u8, output_path_nl, "\r\n");
+ self.output_dir = os.path.dirname(output_path).?;
+ }
if (self.kind == Kind.Lib and !self.static and self.target.wantSharedLibSymLinks()) {
- try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, self.name_only_filename);
+ try doAtomicSymLinks(builder.allocator, self.getOutputPath(), self.major_only_filename, self.name_only_filename);
}
}
};
-pub const CommandStep = struct {
+pub const RunStep = struct {
step: Step,
builder: *Builder,
- argv: [][]const u8,
+
+ /// See also addArg and addArgs to modifying this directly
+ argv: ArrayList(Arg),
+
+ /// Set this to modify the current working directory
cwd: ?[]const u8,
- env_map: *const BufMap,
- /// ::argv is copied.
- pub fn create(builder: *Builder, cwd: ?[]const u8, env_map: *const BufMap, argv: []const []const u8) *CommandStep {
- const self = builder.allocator.create(CommandStep) catch unreachable;
- self.* = CommandStep{
+ /// Override this field to modify the environment, or use setEnvironmentVariable
+ env_map: ?*BufMap,
+
+ pub const Arg = union(enum) {
+ Artifact: *LibExeObjStep,
+ Bytes: []u8,
+ };
+
+ pub fn create(builder: *Builder, name: []const u8) *RunStep {
+ const self = builder.allocator.create(RunStep) catch unreachable;
+ self.* = RunStep{
.builder = builder,
- .step = Step.init(argv[0], builder.allocator, make),
- .argv = builder.allocator.alloc([]u8, argv.len) catch unreachable,
- .cwd = cwd,
- .env_map = env_map,
+ .step = Step.init(name, builder.allocator, make),
+ .argv = ArrayList(Arg).init(builder.allocator),
+ .cwd = null,
+ .env_map = null,
};
-
- mem.copy([]const u8, self.argv, argv);
- self.step.name = self.argv[0];
return self;
}
+ pub fn addArtifactArg(self: *RunStep, artifact: *LibExeObjStep) void {
+ self.argv.append(Arg{ .Artifact = artifact }) catch unreachable;
+ self.step.dependOn(&artifact.step);
+ }
+
+ pub fn addArg(self: *RunStep, arg: []const u8) void {
+ self.argv.append(Arg{ .Bytes = self.builder.dupe(arg) }) catch unreachable;
+ }
+
+ pub fn addArgs(self: *RunStep, args: []const []const u8) void {
+ for (args) |arg| {
+ self.addArg(arg);
+ }
+ }
+
+ pub fn addPathDir(self: *RunStep, search_path: []const u8) void {
+ const PATH = if (builtin.os == builtin.Os.windows) "Path" else "PATH";
+ const env_map = self.getEnvMap();
+ const prev_path = env_map.get(PATH) orelse {
+ env_map.set(PATH, search_path) catch unreachable;
+ return;
+ };
+ const new_path = self.builder.fmt("{}" ++ [1]u8{os.path.delimiter} ++ "{}", prev_path, search_path);
+ env_map.set(PATH, new_path) catch unreachable;
+ }
+
+ pub fn getEnvMap(self: *RunStep) *BufMap {
+ return self.env_map orelse {
+ const env_map = self.builder.allocator.create(BufMap) catch unreachable;
+ env_map.* = os.getEnvMap(self.builder.allocator) catch unreachable;
+ self.env_map = env_map;
+ return env_map;
+ };
+ }
+
+ pub fn setEnvironmentVariable(self: *RunStep, key: []const u8, value: []const u8) void {
+ const env_map = self.getEnvMap();
+ env_map.set(key, value) catch unreachable;
+ }
+
fn make(step: *Step) !void {
- const self = @fieldParentPtr(CommandStep, "step", step);
+ const self = @fieldParentPtr(RunStep, "step", step);
const cwd = if (self.cwd) |cwd| self.builder.pathFromRoot(cwd) else self.builder.build_root;
- return self.builder.spawnChildEnvMap(cwd, self.env_map, self.argv);
+
+ var argv = ArrayList([]const u8).init(self.builder.allocator);
+ for (self.argv.toSlice()) |arg| {
+ switch (arg) {
+ Arg.Bytes => |bytes| try argv.append(bytes),
+ Arg.Artifact => |artifact| {
+ if (artifact.target.isWindows()) {
+ // On Windows we don't have rpaths so we have to add .dll search paths to PATH
+ self.addPathForDynLibs(artifact);
+ }
+ try argv.append(artifact.getOutputPath());
+ },
+ }
+ }
+
+ return self.builder.spawnChildEnvMap(cwd, self.env_map orelse self.builder.env_map, argv.toSliceConst());
+ }
+
+ fn addPathForDynLibs(self: *RunStep, artifact: *LibExeObjStep) void {
+ for (artifact.link_objects.toSliceConst()) |link_object| {
+ switch (link_object) {
+ LibExeObjStep.LinkObject.OtherStep => |other| {
+ if (other.target.isWindows() and other.isDynamicLibrary()) {
+ self.addPathDir(os.path.dirname(other.getOutputPath()).?);
+ self.addPathForDynLibs(other);
+ }
+ },
+ else => {},
+ }
+ }
}
};
diff --git a/std/event/future.zig b/std/event/future.zig
index 0e1b928898..e288e1ba5a 100644
--- a/std/event/future.zig
+++ b/std/event/future.zig
@@ -86,7 +86,7 @@ pub fn Future(comptime T: type) type {
test "std.event.Future" {
// https://github.com/ziglang/zig/issues/1908
- if (builtin.single_threaded) return error.SkipZigTest;
+ if (builtin.single_threaded or builtin.os != builtin.Os.linux) return error.SkipZigTest;
var da = std.heap.DirectAllocator.init();
defer da.deinit();
diff --git a/std/event/loop.zig b/std/event/loop.zig
index a327d03792..d2804eeb27 100644
--- a/std/event/loop.zig
+++ b/std/event/loop.zig
@@ -864,7 +864,7 @@ pub const Loop = struct {
test "std.event.Loop - basic" {
// https://github.com/ziglang/zig/issues/1908
- if (builtin.single_threaded) return error.SkipZigTest;
+ if (builtin.single_threaded or builtin.os != builtin.Os.linux) return error.SkipZigTest;
var da = std.heap.DirectAllocator.init();
defer da.deinit();
@@ -880,7 +880,7 @@ test "std.event.Loop - basic" {
test "std.event.Loop - call" {
// https://github.com/ziglang/zig/issues/1908
- if (builtin.single_threaded) return error.SkipZigTest;
+ if (builtin.single_threaded or builtin.os != builtin.Os.linux) return error.SkipZigTest;
var da = std.heap.DirectAllocator.init();
defer da.deinit();
diff --git a/std/event/rwlock.zig b/std/event/rwlock.zig
index 25b0f0e74b..76b364fedc 100644
--- a/std/event/rwlock.zig
+++ b/std/event/rwlock.zig
@@ -213,7 +213,7 @@ pub const RwLock = struct {
test "std.event.RwLock" {
// https://github.com/ziglang/zig/issues/1908
- if (builtin.single_threaded) return error.SkipZigTest;
+ if (builtin.single_threaded or builtin.os != builtin.Os.linux) return error.SkipZigTest;
var da = std.heap.DirectAllocator.init();
defer da.deinit();
diff --git a/std/os.zig b/std/os.zig
index c686c2a054..96745f15c7 100644
--- a/std/os.zig
+++ b/std/os.zig
@@ -1825,26 +1825,20 @@ pub const Dir = struct {
}
};
-pub fn changeCurDir(allocator: *Allocator, dir_path: []const u8) !void {
- const path_buf = try allocator.alloc(u8, dir_path.len + 1);
- defer allocator.free(path_buf);
-
- mem.copy(u8, path_buf, dir_path);
- path_buf[dir_path.len] = 0;
-
- const err = posix.getErrno(posix.chdir(path_buf.ptr));
- if (err > 0) {
- return switch (err) {
- posix.EACCES => error.AccessDenied,
- posix.EFAULT => unreachable,
- posix.EIO => error.FileSystem,
- posix.ELOOP => error.SymLinkLoop,
- posix.ENAMETOOLONG => error.NameTooLong,
- posix.ENOENT => error.FileNotFound,
- posix.ENOMEM => error.SystemResources,
- posix.ENOTDIR => error.NotDir,
- else => unexpectedErrorPosix(err),
- };
+pub fn changeCurDir(dir_path: []const u8) !void {
+ const dir_path_c = try toPosixPath(dir_path);
+ const err = posix.getErrno(posix.chdir(&dir_path_c));
+ switch (err) {
+ 0 => return,
+ posix.EACCES => return error.AccessDenied,
+ posix.EFAULT => unreachable,
+ posix.EIO => return error.FileSystem,
+ posix.ELOOP => return error.SymLinkLoop,
+ posix.ENAMETOOLONG => return error.NameTooLong,
+ posix.ENOENT => return error.FileNotFound,
+ posix.ENOMEM => return error.SystemResources,
+ posix.ENOTDIR => return error.NotDir,
+ else => return unexpectedErrorPosix(err),
}
}
diff --git a/std/os/child_process.zig b/std/os/child_process.zig
index 653c776239..38b3c8af80 100644
--- a/std/os/child_process.zig
+++ b/std/os/child_process.zig
@@ -404,7 +404,7 @@ pub const ChildProcess = struct {
}
if (self.cwd) |cwd| {
- os.changeCurDir(self.allocator, cwd) catch |err| forkChildErrReport(err_pipe[1], err);
+ os.changeCurDir(cwd) catch |err| forkChildErrReport(err_pipe[1], err);
}
if (self.gid) |gid| {
diff --git a/std/os/windows/util.zig b/std/os/windows/util.zig
index 0952343051..24039967a1 100644
--- a/std/os/windows/util.zig
+++ b/std/os/windows/util.zig
@@ -167,7 +167,7 @@ pub fn windowsOpen(
pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) ![]u16 {
// count bytes needed
const max_chars_needed = x: {
- var max_chars_needed: usize = 1; // 1 for the final null byte
+ var max_chars_needed: usize = 4; // 4 for the final 4 null bytes
var it = env_map.iterator();
while (it.next()) |pair| {
// +1 for '='
@@ -191,6 +191,12 @@ pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap)
}
result[i] = 0;
i += 1;
+ result[i] = 0;
+ i += 1;
+ result[i] = 0;
+ i += 1;
+ result[i] = 0;
+ i += 1;
return allocator.shrink(u16, result, i);
}
diff --git a/std/priority_queue.zig b/std/priority_queue.zig
index d2c493af3e..0469e26743 100644
--- a/std/priority_queue.zig
+++ b/std/priority_queue.zig
@@ -28,7 +28,10 @@ pub fn PriorityQueue(comptime T: type) type {
pub fn add(self: *Self, elem: T) !void {
try ensureCapacity(self, self.len + 1);
+ addUnchecked(self, elem);
+ }
+ fn addUnchecked(self: *Self, elem: T) void {
self.items[self.len] = elem;
var child_index = self.len;
while (child_index > 0) {
@@ -45,6 +48,13 @@ pub fn PriorityQueue(comptime T: type) type {
self.len += 1;
}
+ pub fn addSlice(self: *Self, items: []const T) !void {
+ try self.ensureCapacity(self.len + items.len);
+ for (items) |e| {
+ self.addUnchecked(e);
+ }
+ }
+
pub fn peek(self: *Self) ?T {
return if (self.len > 0) self.items[0] else null;
}
@@ -58,7 +68,7 @@ pub fn PriorityQueue(comptime T: type) type {
const last = self.items[self.len - 1];
self.items[0] = last;
self.len -= 1;
- siftDown(self);
+ siftDown(self, 0);
return first;
}
@@ -70,8 +80,8 @@ pub fn PriorityQueue(comptime T: type) type {
return self.items.len;
}
- fn siftDown(self: *Self) void {
- var index: usize = 0;
+ fn siftDown(self: *Self, start_index: usize) void {
+ var index = start_index;
const half = self.len >> 1;
while (true) {
var left_index = (index << 1) + 1;
@@ -106,6 +116,24 @@ pub fn PriorityQueue(comptime T: type) type {
}
}
+ /// PriorityQueue takes ownership of the passed in slice. The slice must have been
+ /// allocated with `allocator`.
+ /// Deinitialize with `deinit`.
+ pub fn fromOwnedSlice(allocator: *Allocator, compareFn: fn (a: T, b: T) bool, items: []T) Self {
+ var queue = Self{
+ .items = items,
+ .len = items.len,
+ .allocator = allocator,
+ .compareFn = compareFn,
+ };
+ const half = (queue.len >> 1) - 1;
+ var i: usize = 0;
+ while (i <= half) : (i += 1) {
+ queue.siftDown(half - i);
+ }
+ return queue;
+ }
+
pub fn ensureCapacity(self: *Self, new_capacity: usize) !void {
var better_capacity = self.capacity();
if (better_capacity >= new_capacity) return;
@@ -252,24 +280,34 @@ test "std.PriorityQueue: sift up with odd indices" {
try queue.add(e);
}
- expectEqual(u32(1), queue.remove());
- expectEqual(u32(2), queue.remove());
- expectEqual(u32(5), queue.remove());
- expectEqual(u32(6), queue.remove());
- expectEqual(u32(7), queue.remove());
- expectEqual(u32(7), queue.remove());
- expectEqual(u32(11), queue.remove());
- expectEqual(u32(12), queue.remove());
- expectEqual(u32(13), queue.remove());
- expectEqual(u32(14), queue.remove());
- expectEqual(u32(15), queue.remove());
- expectEqual(u32(15), queue.remove());
- expectEqual(u32(16), queue.remove());
- expectEqual(u32(21), queue.remove());
- expectEqual(u32(22), queue.remove());
- expectEqual(u32(24), queue.remove());
- expectEqual(u32(24), queue.remove());
- expectEqual(u32(25), queue.remove());
+ const sorted_items = []u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 };
+ for (sorted_items) |e| {
+ expectEqual(e, queue.remove());
+ }
+}
+
+test "std.PriorityQueue: addSlice" {
+ var queue = PQ.init(debug.global_allocator, lessThan);
+ defer queue.deinit();
+ const items = []u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };
+ try queue.addSlice(items[0..]);
+
+ const sorted_items = []u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 };
+ for (sorted_items) |e| {
+ expectEqual(e, queue.remove());
+ }
+}
+
+test "std.PriorityQueue: fromOwnedSlice" {
+ const items = []u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };
+ const heap_items = try std.mem.dupe(debug.global_allocator, u32, items[0..]);
+ var queue = PQ.fromOwnedSlice(debug.global_allocator, lessThan, heap_items[0..]);
+ defer queue.deinit();
+
+ const sorted_items = []u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 };
+ for (sorted_items) |e| {
+ expectEqual(e, queue.remove());
+ }
}
test "std.PriorityQueue: add and remove max heap" {
diff --git a/std/special/builtin.zig b/std/special/builtin.zig
index 38c1493ba2..868b880dcf 100644
--- a/std/special/builtin.zig
+++ b/std/special/builtin.zig
@@ -101,7 +101,7 @@ nakedcc fn clone() void {
\\1: ret
\\
);
- } else if (builtin.arch == builtin.Arch.aarch64v8) {
+ } else if (builtin.arch == builtin.Arch.aarch64) {
// __clone(func, stack, flags, arg, ptid, tls, ctid)
// x0, x1, w2, x3, x4, x5, x6
diff --git a/std/special/compiler_rt.zig b/std/special/compiler_rt.zig
index 6521dc1aaf..d0f29a68dc 100644
--- a/std/special/compiler_rt.zig
+++ b/std/special/compiler_rt.zig
@@ -67,6 +67,7 @@ comptime {
@export("__fixtfti", @import("compiler_rt/fixtfti.zig").__fixtfti, linkage);
@export("__udivmoddi4", @import("compiler_rt/udivmoddi4.zig").__udivmoddi4, linkage);
+ @export("__popcountdi2", @import("compiler_rt/popcountdi2.zig").__popcountdi2, linkage);
@export("__udivsi3", __udivsi3, linkage);
@export("__udivdi3", __udivdi3, linkage);
diff --git a/std/special/compiler_rt/popcountdi2.zig b/std/special/compiler_rt/popcountdi2.zig
new file mode 100644
index 0000000000..ea36b0ec44
--- /dev/null
+++ b/std/special/compiler_rt/popcountdi2.zig
@@ -0,0 +1,24 @@
+const builtin = @import("builtin");
+const compiler_rt = @import("../compiler_rt.zig");
+
+// ported from llvm compiler-rt 8.0.0rc3 95e1c294cb0415a377a7b1d6c7c7d4f89e1c04e4
+pub extern fn __popcountdi2(a: i64) i32 {
+ var x2 = @bitCast(u64, a);
+ x2 = x2 - ((x2 >> 1) & 0x5555555555555555);
+ // Every 2 bits holds the sum of every pair of bits (32)
+ x2 = ((x2 >> 2) & 0x3333333333333333) + (x2 & 0x3333333333333333);
+ // Every 4 bits holds the sum of every 4-set of bits (3 significant bits) (16)
+ x2 = (x2 + (x2 >> 4)) & 0x0F0F0F0F0F0F0F0F;
+ // Every 8 bits holds the sum of every 8-set of bits (4 significant bits) (8)
+ var x: u32 = @truncate(u32, x2 + (x2 >> 32));
+ // The lower 32 bits hold four 16 bit sums (5 significant bits).
+ // Upper 32 bits are garbage */
+ x = x + (x >> 16);
+ // The lower 16 bits hold two 32 bit sums (6 significant bits).
+ // Upper 16 bits are garbage */
+ return @bitCast(i32, (x + (x >> 8)) & 0x0000007F); // (7 significant bits)
+}
+
+test "import popcountdi2" {
+ _ = @import("popcountdi2_test.zig");
+}
diff --git a/std/special/compiler_rt/popcountdi2_test.zig b/std/special/compiler_rt/popcountdi2_test.zig
new file mode 100644
index 0000000000..bedcbcd1de
--- /dev/null
+++ b/std/special/compiler_rt/popcountdi2_test.zig
@@ -0,0 +1,27 @@
+const __popcountdi2 = @import("popcountdi2.zig").__popcountdi2;
+const testing = @import("std").testing;
+
+fn naive_popcount(a_param: i64) i32 {
+ var a = a_param;
+ var r: i32 = 0;
+ while (a != 0) : (a = @bitCast(i64, @bitCast(u64, a) >> 1)) {
+ r += @intCast(i32, a & 1);
+ }
+ return r;
+}
+
+fn test__popcountdi2(a: i64) void {
+ const x = __popcountdi2(a);
+ const expected = naive_popcount(a);
+ testing.expect(expected == x);
+}
+
+test "popcountdi2" {
+ test__popcountdi2(0);
+ test__popcountdi2(1);
+ test__popcountdi2(2);
+ test__popcountdi2(@bitCast(i64, u64(0xFFFFFFFFFFFFFFFD)));
+ test__popcountdi2(@bitCast(i64, u64(0xFFFFFFFFFFFFFFFE)));
+ test__popcountdi2(@bitCast(i64, u64(0xFFFFFFFFFFFFFFFF)));
+ // TODO some fuzz testing
+}
diff --git a/std/special/init-exe/build.zig b/std/special/init-exe/build.zig
index 21a2600562..1ee3289643 100644
--- a/std/special/init-exe/build.zig
+++ b/std/special/init-exe/build.zig
@@ -5,10 +5,10 @@ pub fn build(b: *Builder) void {
const exe = b.addExecutable("$", "src/main.zig");
exe.setBuildMode(mode);
+ const run_cmd = exe.run();
+
const run_step = b.step("run", "Run the app");
- const run_cmd = b.addCommand(".", b.env_map, [][]const u8{exe.getOutputPath()});
run_step.dependOn(&run_cmd.step);
- run_cmd.step.dependOn(&exe.step);
b.default_step.dependOn(&exe.step);
b.installArtifact(exe);