Merge remote-tracking branch 'origin/master' into llvm8
commit
a94304d3e4
|
@ -596,6 +596,7 @@ set(ZIG_STD_FILES
|
|||
"os/windows/ntdll.zig"
|
||||
"os/windows/ole32.zig"
|
||||
"os/windows/shell32.zig"
|
||||
"os/windows/tls.zig"
|
||||
"os/windows/util.zig"
|
||||
"os/zen.zig"
|
||||
"pdb.zig"
|
||||
|
|
35
build.zig
35
build.zig
|
@ -16,7 +16,10 @@ pub fn build(b: *Builder) !void {
|
|||
var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
|
||||
|
||||
const rel_zig_exe = try os.path.relative(b.allocator, b.build_root, b.zig_exe);
|
||||
const langref_out_path = os.path.join(b.allocator, b.cache_root, "langref.html") catch unreachable;
|
||||
const langref_out_path = os.path.join(
|
||||
b.allocator,
|
||||
[][]const u8{ b.cache_root, "langref.html" },
|
||||
) catch unreachable;
|
||||
var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8{
|
||||
docgen_exe.getOutputPath(),
|
||||
rel_zig_exe,
|
||||
|
@ -125,13 +128,19 @@ fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void {
|
|||
for (dep.libdirs.toSliceConst()) |lib_dir| {
|
||||
lib_exe_obj.addLibPath(lib_dir);
|
||||
}
|
||||
const lib_dir = os.path.join(b.allocator, dep.prefix, "lib") catch unreachable;
|
||||
const lib_dir = os.path.join(
|
||||
b.allocator,
|
||||
[][]const u8{ dep.prefix, "lib" },
|
||||
) catch unreachable;
|
||||
for (dep.system_libs.toSliceConst()) |lib| {
|
||||
const static_bare_name = if (mem.eql(u8, lib, "curses"))
|
||||
([]const u8)("libncurses.a")
|
||||
else
|
||||
b.fmt("lib{}.a", lib);
|
||||
const static_lib_name = os.path.join(b.allocator, lib_dir, static_bare_name) catch unreachable;
|
||||
const static_lib_name = os.path.join(
|
||||
b.allocator,
|
||||
[][]const u8{ lib_dir, static_bare_name },
|
||||
) catch unreachable;
|
||||
const have_static = fileExists(static_lib_name) catch unreachable;
|
||||
if (have_static) {
|
||||
lib_exe_obj.addObjectFile(static_lib_name);
|
||||
|
@ -159,7 +168,11 @@ fn fileExists(filename: []const u8) !bool {
|
|||
|
||||
fn addCppLib(b: *Builder, lib_exe_obj: var, cmake_binary_dir: []const u8, lib_name: []const u8) void {
|
||||
const lib_prefix = if (lib_exe_obj.target.isWindows()) "" else "lib";
|
||||
lib_exe_obj.addObjectFile(os.path.join(b.allocator, cmake_binary_dir, "zig_cpp", b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt())) catch unreachable);
|
||||
lib_exe_obj.addObjectFile(os.path.join(b.allocator, [][]const u8{
|
||||
cmake_binary_dir,
|
||||
"zig_cpp",
|
||||
b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt()),
|
||||
}) catch unreachable);
|
||||
}
|
||||
|
||||
const LibraryDep = struct {
|
||||
|
@ -235,8 +248,11 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {
|
|||
pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void {
|
||||
var it = mem.tokenize(stdlib_files, ";");
|
||||
while (it.next()) |stdlib_file| {
|
||||
const src_path = os.path.join(b.allocator, "std", stdlib_file) catch unreachable;
|
||||
const dest_path = os.path.join(b.allocator, "lib", "zig", "std", stdlib_file) catch unreachable;
|
||||
const src_path = os.path.join(b.allocator, [][]const u8{ "std", stdlib_file }) catch unreachable;
|
||||
const dest_path = os.path.join(
|
||||
b.allocator,
|
||||
[][]const u8{ "lib", "zig", "std", stdlib_file },
|
||||
) catch unreachable;
|
||||
b.installFile(src_path, dest_path);
|
||||
}
|
||||
}
|
||||
|
@ -244,8 +260,11 @@ pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void {
|
|||
pub fn installCHeaders(b: *Builder, c_header_files: []const u8) void {
|
||||
var it = mem.tokenize(c_header_files, ";");
|
||||
while (it.next()) |c_header_file| {
|
||||
const src_path = os.path.join(b.allocator, "c_headers", c_header_file) catch unreachable;
|
||||
const dest_path = os.path.join(b.allocator, "lib", "zig", "include", c_header_file) catch unreachable;
|
||||
const src_path = os.path.join(b.allocator, [][]const u8{ "c_headers", c_header_file }) catch unreachable;
|
||||
const dest_path = os.path.join(
|
||||
b.allocator,
|
||||
[][]const u8{ "lib", "zig", "include", c_header_file },
|
||||
) catch unreachable;
|
||||
b.installFile(src_path, dest_path);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -990,13 +990,19 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
|||
try tokenizeAndPrint(tokenizer, out, code.source_token);
|
||||
try out.write("</pre>");
|
||||
const name_plus_ext = try std.fmt.allocPrint(allocator, "{}.zig", code.name);
|
||||
const tmp_source_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_ext);
|
||||
const tmp_source_file_name = try os.path.join(
|
||||
allocator,
|
||||
[][]const u8{ tmp_dir_name, name_plus_ext },
|
||||
);
|
||||
try io.writeFile(tmp_source_file_name, trimmed_raw_source);
|
||||
|
||||
switch (code.id) {
|
||||
Code.Id.Exe => |expected_outcome| {
|
||||
const name_plus_bin_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, exe_ext);
|
||||
const tmp_bin_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_bin_ext);
|
||||
const tmp_bin_file_name = try os.path.join(
|
||||
allocator,
|
||||
[][]const u8{ tmp_dir_name, name_plus_bin_ext },
|
||||
);
|
||||
var build_args = std.ArrayList([]const u8).init(allocator);
|
||||
defer build_args.deinit();
|
||||
try build_args.appendSlice([][]const u8{
|
||||
|
@ -1024,7 +1030,10 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
|||
}
|
||||
for (code.link_objects) |link_object| {
|
||||
const name_with_ext = try std.fmt.allocPrint(allocator, "{}{}", link_object, obj_ext);
|
||||
const full_path_object = try os.path.join(allocator, tmp_dir_name, name_with_ext);
|
||||
const full_path_object = try os.path.join(
|
||||
allocator,
|
||||
[][]const u8{ tmp_dir_name, name_with_ext },
|
||||
);
|
||||
try build_args.append("--object");
|
||||
try build_args.append(full_path_object);
|
||||
try out.print(" --object {}", name_with_ext);
|
||||
|
@ -1216,12 +1225,18 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
|||
},
|
||||
Code.Id.Obj => |maybe_error_match| {
|
||||
const name_plus_obj_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, obj_ext);
|
||||
const tmp_obj_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_obj_ext);
|
||||
const tmp_obj_file_name = try os.path.join(
|
||||
allocator,
|
||||
[][]const u8{ tmp_dir_name, name_plus_obj_ext },
|
||||
);
|
||||
var build_args = std.ArrayList([]const u8).init(allocator);
|
||||
defer build_args.deinit();
|
||||
|
||||
const name_plus_h_ext = try std.fmt.allocPrint(allocator, "{}.h", code.name);
|
||||
const output_h_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_h_ext);
|
||||
const output_h_file_name = try os.path.join(
|
||||
allocator,
|
||||
[][]const u8{ tmp_dir_name, name_plus_h_ext },
|
||||
);
|
||||
|
||||
try build_args.appendSlice([][]const u8{
|
||||
zig_exe,
|
||||
|
|
|
@ -3192,7 +3192,16 @@ fn foo() void { }
|
|||
{#code_end#}
|
||||
{#header_open|Pass-by-value Parameters#}
|
||||
<p>
|
||||
In Zig, structs, unions, and enums with payloads can be passed directly to a function:
|
||||
Primitive types such as {#link|Integers#} and {#link|Floats#} passed as parameters
|
||||
are copied, and then the copy is available in the function body. This is called "passing by value".
|
||||
Copying a primitive type is essentially free and typically involves nothing more than
|
||||
setting a register.
|
||||
</p>
|
||||
<p>
|
||||
Structs, unions, and arrays can sometimes be more efficiently passed as a reference, since a copy
|
||||
could be arbitrarily expensive depending on the size. When these types are passed
|
||||
as parameters, Zig may choose to copy and pass by value, or pass by reference, whichever way
|
||||
Zig decides will be faster. This is made possible, in part, by the fact that parameters are immutable.
|
||||
</p>
|
||||
{#code_begin|test#}
|
||||
const Point = struct {
|
||||
|
@ -3201,20 +3210,20 @@ const Point = struct {
|
|||
};
|
||||
|
||||
fn foo(point: Point) i32 {
|
||||
// Here, `point` could be a reference, or a copy. The function body
|
||||
// can ignore the difference and treat it as a value. Be very careful
|
||||
// taking the address of the parameter - it should be treated as if
|
||||
// the address will become invalid when the function returns.
|
||||
return point.x + point.y;
|
||||
}
|
||||
|
||||
const assert = @import("std").debug.assert;
|
||||
|
||||
test "pass aggregate type by non-copy value to function" {
|
||||
test "pass struct to function" {
|
||||
assert(foo(Point{ .x = 1, .y = 2 }) == 3);
|
||||
}
|
||||
{#code_end#}
|
||||
<p>
|
||||
In this case, the value may be passed by reference, or by value, whichever way
|
||||
Zig decides will be faster.
|
||||
</p>
|
||||
<p>
|
||||
For extern functions, Zig follows the C ABI for passing structs and unions by value.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
# How to Add Support For More Targets
|
||||
|
||||
Create bootstrap code in std/bootstrap.zig and add conditional compilation
|
||||
logic. This code is responsible for the real executable entry point, calling
|
||||
main() and making the exit syscall when main returns.
|
||||
|
||||
How to pass a byvalue struct parameter in the C calling convention is
|
||||
target-specific. Add logic for how to do function prototypes and function calls
|
||||
for the target when an exported or external function has a byvalue struct.
|
||||
|
||||
Write the target-specific code in the standard library.
|
||||
|
||||
Update the C integer types to be the correct size for the target.
|
||||
|
||||
Make sure that `c_longdouble` codegens the correct floating point value.
|
|
@ -487,7 +487,7 @@ pub const Compilation = struct {
|
|||
comp.name = try Buffer.init(comp.arena(), name);
|
||||
comp.llvm_triple = try target.getTriple(comp.arena());
|
||||
comp.llvm_target = try Target.llvmTargetFromTriple(comp.llvm_triple);
|
||||
comp.zig_std_dir = try std.os.path.join(comp.arena(), zig_lib_dir, "std");
|
||||
comp.zig_std_dir = try std.os.path.join(comp.arena(), [][]const u8{ zig_lib_dir, "std" });
|
||||
|
||||
const opt_level = switch (build_mode) {
|
||||
builtin.Mode.Debug => llvm.CodeGenLevelNone,
|
||||
|
@ -1198,7 +1198,7 @@ pub const Compilation = struct {
|
|||
const file_name = try std.fmt.allocPrint(self.gpa(), "{}{}", file_prefix[0..], suffix);
|
||||
defer self.gpa().free(file_name);
|
||||
|
||||
const full_path = try os.path.join(self.gpa(), tmp_dir, file_name[0..]);
|
||||
const full_path = try os.path.join(self.gpa(), [][]const u8{ tmp_dir, file_name[0..] });
|
||||
errdefer self.gpa().free(full_path);
|
||||
|
||||
return Buffer.fromOwnedSlice(self.gpa(), full_path);
|
||||
|
@ -1219,7 +1219,7 @@ pub const Compilation = struct {
|
|||
const zig_dir_path = try getZigDir(self.gpa());
|
||||
defer self.gpa().free(zig_dir_path);
|
||||
|
||||
const tmp_dir = try os.path.join(self.arena(), zig_dir_path, comp_dir_name[0..]);
|
||||
const tmp_dir = try os.path.join(self.arena(), [][]const u8{ zig_dir_path, comp_dir_name[0..] });
|
||||
try os.makePath(self.gpa(), tmp_dir);
|
||||
return tmp_dir;
|
||||
}
|
||||
|
|
|
@ -8,10 +8,10 @@ const warn = std.debug.warn;
|
|||
|
||||
/// Caller must free result
|
||||
pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 {
|
||||
const test_zig_dir = try os.path.join(allocator, test_path, "lib", "zig");
|
||||
const test_zig_dir = try os.path.join(allocator, [][]const u8{ test_path, "lib", "zig" });
|
||||
errdefer allocator.free(test_zig_dir);
|
||||
|
||||
const test_index_file = try os.path.join(allocator, test_zig_dir, "std", "index.zig");
|
||||
const test_index_file = try os.path.join(allocator, [][]const u8{ test_zig_dir, "std", "index.zig" });
|
||||
defer allocator.free(test_index_file);
|
||||
|
||||
var file = try os.File.openRead(test_index_file);
|
||||
|
|
|
@ -230,7 +230,7 @@ pub const LibCInstallation = struct {
|
|||
while (path_i < search_paths.len) : (path_i += 1) {
|
||||
const search_path_untrimmed = search_paths.at(search_paths.len - path_i - 1);
|
||||
const search_path = std.mem.trimLeft(u8, search_path_untrimmed, " ");
|
||||
const stdlib_path = try std.os.path.join(loop.allocator, search_path, "stdlib.h");
|
||||
const stdlib_path = try std.os.path.join(loop.allocator, [][]const u8{ search_path, "stdlib.h" });
|
||||
defer loop.allocator.free(stdlib_path);
|
||||
|
||||
if (try fileExists(stdlib_path)) {
|
||||
|
@ -254,7 +254,10 @@ pub const LibCInstallation = struct {
|
|||
const stream = &std.io.BufferOutStream.init(&result_buf).stream;
|
||||
try stream.print("{}\\Include\\{}\\ucrt", search.path, search.version);
|
||||
|
||||
const stdlib_path = try std.os.path.join(loop.allocator, result_buf.toSliceConst(), "stdlib.h");
|
||||
const stdlib_path = try std.os.path.join(
|
||||
loop.allocator,
|
||||
[][]const u8{ result_buf.toSliceConst(), "stdlib.h" },
|
||||
);
|
||||
defer loop.allocator.free(stdlib_path);
|
||||
|
||||
if (try fileExists(stdlib_path)) {
|
||||
|
@ -283,7 +286,10 @@ pub const LibCInstallation = struct {
|
|||
builtin.Arch.aarch64v8 => try stream.write("arm"),
|
||||
else => return error.UnsupportedArchitecture,
|
||||
}
|
||||
const ucrt_lib_path = try std.os.path.join(loop.allocator, result_buf.toSliceConst(), "ucrt.lib");
|
||||
const ucrt_lib_path = try std.os.path.join(
|
||||
loop.allocator,
|
||||
[][]const u8{ result_buf.toSliceConst(), "ucrt.lib" },
|
||||
);
|
||||
defer loop.allocator.free(ucrt_lib_path);
|
||||
if (try fileExists(ucrt_lib_path)) {
|
||||
self.lib_dir = result_buf.toOwnedSlice();
|
||||
|
@ -358,7 +364,10 @@ pub const LibCInstallation = struct {
|
|||
builtin.Arch.aarch64v8 => try stream.write("arm\\"),
|
||||
else => return error.UnsupportedArchitecture,
|
||||
}
|
||||
const kernel32_path = try std.os.path.join(loop.allocator, result_buf.toSliceConst(), "kernel32.lib");
|
||||
const kernel32_path = try std.os.path.join(
|
||||
loop.allocator,
|
||||
[][]const u8{ result_buf.toSliceConst(), "kernel32.lib" },
|
||||
);
|
||||
defer loop.allocator.free(kernel32_path);
|
||||
if (try fileExists(kernel32_path)) {
|
||||
self.kernel32_lib_dir = result_buf.toOwnedSlice();
|
||||
|
|
|
@ -315,7 +315,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
|
|||
}
|
||||
|
||||
fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void {
|
||||
const full_path = try std.os.path.join(&ctx.arena.allocator, dirname, basename);
|
||||
const full_path = try std.os.path.join(&ctx.arena.allocator, [][]const u8{ dirname, basename });
|
||||
const full_path_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, full_path);
|
||||
try ctx.args.append(full_path_with_null.ptr);
|
||||
}
|
||||
|
|
|
@ -757,7 +757,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro
|
|||
var group = event.Group(FmtError!void).init(fmt.loop);
|
||||
while (try dir.next()) |entry| {
|
||||
if (entry.kind == std.os.Dir.Entry.Kind.Directory or mem.endsWith(u8, entry.name, ".zig")) {
|
||||
const full_path = try os.path.join(fmt.loop.allocator, file_path, entry.name);
|
||||
const full_path = try os.path.join(fmt.loop.allocator, [][]const u8{ file_path, entry.name });
|
||||
try group.call(fmtPath, fmt, full_path, check_mode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ pub const TestContext = struct {
|
|||
) !void {
|
||||
var file_index_buf: [20]u8 = undefined;
|
||||
const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.incr());
|
||||
const file1_path = try std.os.path.join(allocator, tmp_dir_name, file_index, file1);
|
||||
const file1_path = try std.os.path.join(allocator, [][]const u8{ tmp_dir_name, file_index, file1 });
|
||||
|
||||
if (std.os.path.dirname(file1_path)) |dirname| {
|
||||
try std.os.makePath(allocator, dirname);
|
||||
|
@ -120,7 +120,7 @@ pub const TestContext = struct {
|
|||
) !void {
|
||||
var file_index_buf: [20]u8 = undefined;
|
||||
const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.incr());
|
||||
const file1_path = try std.os.path.join(allocator, tmp_dir_name, file_index, file1);
|
||||
const file1_path = try std.os.path.join(allocator, [][]const u8{ tmp_dir_name, file_index, file1 });
|
||||
|
||||
const output_file = try std.fmt.allocPrint(allocator, "{}-out{}", file1_path, Target(Target.Native).exeFileExt());
|
||||
if (std.os.path.dirname(file1_path)) |dirname| {
|
||||
|
|
|
@ -544,12 +544,7 @@ struct AstNodeDefer {
|
|||
};
|
||||
|
||||
struct AstNodeVariableDeclaration {
|
||||
VisibMod visib_mod;
|
||||
Buf *symbol;
|
||||
bool is_const;
|
||||
bool is_comptime;
|
||||
bool is_export;
|
||||
bool is_extern;
|
||||
// one or both of type and expr will be non null
|
||||
AstNode *type;
|
||||
AstNode *expr;
|
||||
|
@ -559,6 +554,13 @@ struct AstNodeVariableDeclaration {
|
|||
AstNode *align_expr;
|
||||
// populated if the "section(S)" is present
|
||||
AstNode *section_expr;
|
||||
Token *threadlocal_tok;
|
||||
|
||||
VisibMod visib_mod;
|
||||
bool is_const;
|
||||
bool is_comptime;
|
||||
bool is_export;
|
||||
bool is_extern;
|
||||
};
|
||||
|
||||
struct AstNodeTestDecl {
|
||||
|
@ -1873,6 +1875,7 @@ struct ZigVar {
|
|||
bool shadowable;
|
||||
bool src_is_const;
|
||||
bool gen_is_const;
|
||||
bool is_thread_local;
|
||||
};
|
||||
|
||||
struct ErrorTableEntry {
|
||||
|
|
|
@ -28,28 +28,10 @@ static Error ATTRIBUTE_MUST_USE resolve_enum_zero_bits(CodeGen *g, ZigType *enum
|
|||
static Error ATTRIBUTE_MUST_USE resolve_union_zero_bits(CodeGen *g, ZigType *union_type);
|
||||
static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry);
|
||||
|
||||
ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
|
||||
if (node->owner->c_import_node != nullptr) {
|
||||
// if this happens, then translate_c generated code that
|
||||
// failed semantic analysis, which isn't supposed to happen
|
||||
ErrorMsg *err = add_node_error(g, node->owner->c_import_node,
|
||||
buf_sprintf("compiler bug: @cImport generated invalid zig code"));
|
||||
|
||||
add_error_note(g, err, node, msg);
|
||||
|
||||
g->errors.append(err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column,
|
||||
node->owner->source_code, node->owner->line_offsets, msg);
|
||||
|
||||
g->errors.append(err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg) {
|
||||
if (node->owner->c_import_node != nullptr) {
|
||||
static ErrorMsg *add_error_note_token(CodeGen *g, ErrorMsg *parent_msg, ImportTableEntry *owner, Token *token,
|
||||
Buf *msg)
|
||||
{
|
||||
if (owner->c_import_node != nullptr) {
|
||||
// if this happens, then translate_c generated code that
|
||||
// failed semantic analysis, which isn't supposed to happen
|
||||
|
||||
|
@ -64,13 +46,46 @@ ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *m
|
|||
return note;
|
||||
}
|
||||
|
||||
ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column,
|
||||
node->owner->source_code, node->owner->line_offsets, msg);
|
||||
ErrorMsg *err = err_msg_create_with_line(owner->path, token->start_line, token->start_column,
|
||||
owner->source_code, owner->line_offsets, msg);
|
||||
|
||||
err_msg_add_note(parent_msg, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ErrorMsg *add_token_error(CodeGen *g, ImportTableEntry *owner, Token *token, Buf *msg) {
|
||||
if (owner->c_import_node != nullptr) {
|
||||
// if this happens, then translate_c generated code that
|
||||
// failed semantic analysis, which isn't supposed to happen
|
||||
ErrorMsg *err = add_node_error(g, owner->c_import_node,
|
||||
buf_sprintf("compiler bug: @cImport generated invalid zig code"));
|
||||
|
||||
add_error_note_token(g, err, owner, token, msg);
|
||||
|
||||
g->errors.append(err);
|
||||
return err;
|
||||
}
|
||||
ErrorMsg *err = err_msg_create_with_line(owner->path, token->start_line, token->start_column,
|
||||
owner->source_code, owner->line_offsets, msg);
|
||||
|
||||
g->errors.append(err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
|
||||
Token fake_token;
|
||||
fake_token.start_line = node->line;
|
||||
fake_token.start_column = node->column;
|
||||
return add_token_error(g, node->owner, &fake_token, msg);
|
||||
}
|
||||
|
||||
ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg) {
|
||||
Token fake_token;
|
||||
fake_token.start_line = node->line;
|
||||
fake_token.start_column = node->column;
|
||||
return add_error_note_token(g, parent_msg, node->owner, &fake_token, msg);
|
||||
}
|
||||
|
||||
ZigType *new_type_table_entry(ZigTypeId id) {
|
||||
ZigType *entry = allocate<ZigType>(1);
|
||||
entry->id = id;
|
||||
|
@ -3668,6 +3683,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
|
|||
bool is_const = var_decl->is_const;
|
||||
bool is_extern = var_decl->is_extern;
|
||||
bool is_export = var_decl->is_export;
|
||||
bool is_thread_local = var_decl->threadlocal_tok != nullptr;
|
||||
|
||||
ZigType *explicit_type = nullptr;
|
||||
if (var_decl->type) {
|
||||
|
@ -3727,6 +3743,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
|
|||
tld_var->var = add_variable(g, source_node, tld_var->base.parent_scope, var_decl->symbol,
|
||||
is_const, init_val, &tld_var->base, type);
|
||||
tld_var->var->linkage = linkage;
|
||||
tld_var->var->is_thread_local = is_thread_local;
|
||||
|
||||
if (implicit_type != nullptr && type_is_invalid(implicit_type)) {
|
||||
tld_var->var->var_type = g->builtin_types.entry_invalid;
|
||||
|
@ -3747,6 +3764,10 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
|
|||
}
|
||||
}
|
||||
|
||||
if (is_thread_local && is_const) {
|
||||
add_node_error(g, source_node, buf_sprintf("threadlocal variable cannot be constant"));
|
||||
}
|
||||
|
||||
g->global_vars.append(tld_var);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
void semantic_analyze(CodeGen *g);
|
||||
ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg);
|
||||
ErrorMsg *add_token_error(CodeGen *g, ImportTableEntry *owner, Token *token, Buf *msg);
|
||||
ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg);
|
||||
ZigType *new_type_table_entry(ZigTypeId id);
|
||||
ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const);
|
||||
|
|
|
@ -132,6 +132,10 @@ static const char *const_or_var_string(bool is_const) {
|
|||
return is_const ? "const" : "var";
|
||||
}
|
||||
|
||||
static const char *thread_local_string(Token *tok) {
|
||||
return (tok == nullptr) ? "" : "threadlocal ";
|
||||
}
|
||||
|
||||
const char *container_string(ContainerKind kind) {
|
||||
switch (kind) {
|
||||
case ContainerKindEnum: return "enum";
|
||||
|
@ -554,8 +558,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
|||
{
|
||||
const char *pub_str = visib_mod_string(node->data.variable_declaration.visib_mod);
|
||||
const char *extern_str = extern_string(node->data.variable_declaration.is_extern);
|
||||
const char *thread_local_str = thread_local_string(node->data.variable_declaration.threadlocal_tok);
|
||||
const char *const_or_var = const_or_var_string(node->data.variable_declaration.is_const);
|
||||
fprintf(ar->f, "%s%s%s ", pub_str, extern_str, const_or_var);
|
||||
fprintf(ar->f, "%s%s%s%s ", pub_str, extern_str, thread_local_str, const_or_var);
|
||||
print_symbol(ar, node->data.variable_declaration.symbol);
|
||||
|
||||
if (node->data.variable_declaration.type) {
|
||||
|
|
157
src/codegen.cpp
157
src/codegen.cpp
|
@ -88,7 +88,7 @@ static const char *symbols_that_llvm_depends_on[] = {
|
|||
};
|
||||
|
||||
CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode,
|
||||
Buf *zig_lib_dir)
|
||||
Buf *zig_lib_dir, Buf *override_std_dir)
|
||||
{
|
||||
CodeGen *g = allocate<CodeGen>(1);
|
||||
|
||||
|
@ -96,8 +96,12 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
|
|||
|
||||
g->zig_lib_dir = zig_lib_dir;
|
||||
|
||||
g->zig_std_dir = buf_alloc();
|
||||
os_path_join(zig_lib_dir, buf_create_from_str("std"), g->zig_std_dir);
|
||||
if (override_std_dir == nullptr) {
|
||||
g->zig_std_dir = buf_alloc();
|
||||
os_path_join(zig_lib_dir, buf_create_from_str("std"), g->zig_std_dir);
|
||||
} else {
|
||||
g->zig_std_dir = override_std_dir;
|
||||
}
|
||||
|
||||
g->zig_c_headers_dir = buf_alloc();
|
||||
os_path_join(zig_lib_dir, buf_create_from_str("include"), g->zig_c_headers_dir);
|
||||
|
@ -2582,6 +2586,8 @@ static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast
|
|||
|
||||
}
|
||||
|
||||
typedef LLVMValueRef (*BuildBinOpFunc)(LLVMBuilderRef, LLVMValueRef, LLVMValueRef, const char *);
|
||||
|
||||
static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
|
||||
IrInstructionBinOp *bin_op_instruction)
|
||||
{
|
||||
|
@ -2640,50 +2646,71 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
|
|||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
case IrBinOpMult:
|
||||
case IrBinOpMultWrap:
|
||||
case IrBinOpAdd:
|
||||
case IrBinOpAddWrap:
|
||||
case IrBinOpSub:
|
||||
case IrBinOpSubWrap: {
|
||||
// These are lookup table using the AddSubMul enum as the lookup.
|
||||
// If AddSubMul ever changes, then these tables will be out of
|
||||
// date.
|
||||
static const BuildBinOpFunc float_op[3] = { LLVMBuildFAdd, LLVMBuildFSub, LLVMBuildFMul };
|
||||
static const BuildBinOpFunc wrap_op[3] = { LLVMBuildAdd, LLVMBuildSub, LLVMBuildMul };
|
||||
static const BuildBinOpFunc signed_op[3] = { LLVMBuildNSWAdd, LLVMBuildNSWSub, LLVMBuildNSWMul };
|
||||
static const BuildBinOpFunc unsigned_op[3] = { LLVMBuildNUWAdd, LLVMBuildNUWSub, LLVMBuildNUWMul };
|
||||
|
||||
bool is_vector = type_entry->id == ZigTypeIdVector;
|
||||
bool is_wrapping = (op_id == IrBinOpSubWrap || op_id == IrBinOpAddWrap || op_id == IrBinOpMultWrap);
|
||||
AddSubMul add_sub_mul =
|
||||
op_id == IrBinOpAdd || op_id == IrBinOpAddWrap ? AddSubMulAdd :
|
||||
op_id == IrBinOpSub || op_id == IrBinOpSubWrap ? AddSubMulSub :
|
||||
AddSubMulMul;
|
||||
|
||||
// The code that is generated for vectors and scalars are the same,
|
||||
// so we can just set type_entry to the vectors elem_type an avoid
|
||||
// a lot of repeated code.
|
||||
if (is_vector)
|
||||
type_entry = type_entry->data.vector.elem_type;
|
||||
|
||||
if (type_entry->id == ZigTypeIdPointer) {
|
||||
assert(type_entry->data.pointer.ptr_len == PtrLenUnknown);
|
||||
LLVMValueRef subscript_value;
|
||||
if (is_vector)
|
||||
zig_panic("TODO: Implement vector operations on pointers.");
|
||||
|
||||
switch (add_sub_mul) {
|
||||
case AddSubMulAdd:
|
||||
subscript_value = op2_value;
|
||||
break;
|
||||
case AddSubMulSub:
|
||||
subscript_value = LLVMBuildNeg(g->builder, op2_value, "");
|
||||
break;
|
||||
case AddSubMulMul:
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
// TODO runtime safety
|
||||
return LLVMBuildInBoundsGEP(g->builder, op1_value, &op2_value, 1, "");
|
||||
return LLVMBuildInBoundsGEP(g->builder, op1_value, &subscript_value, 1, "");
|
||||
} else if (type_entry->id == ZigTypeIdFloat) {
|
||||
ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
|
||||
return LLVMBuildFAdd(g->builder, op1_value, op2_value, "");
|
||||
return float_op[add_sub_mul](g->builder, op1_value, op2_value, "");
|
||||
} else if (type_entry->id == ZigTypeIdInt) {
|
||||
bool is_wrapping = (op_id == IrBinOpAddWrap);
|
||||
if (is_wrapping) {
|
||||
return LLVMBuildAdd(g->builder, op1_value, op2_value, "");
|
||||
return wrap_op[add_sub_mul](g->builder, op1_value, op2_value, "");
|
||||
} else if (want_runtime_safety) {
|
||||
return gen_overflow_op(g, type_entry, AddSubMulAdd, op1_value, op2_value);
|
||||
if (is_vector)
|
||||
zig_panic("TODO: Implement runtime safety vector operations.");
|
||||
return gen_overflow_op(g, type_entry, add_sub_mul, op1_value, op2_value);
|
||||
} else if (type_entry->data.integral.is_signed) {
|
||||
return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, "");
|
||||
return signed_op[add_sub_mul](g->builder, op1_value, op2_value, "");
|
||||
} else {
|
||||
return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, "");
|
||||
}
|
||||
} else if (type_entry->id == ZigTypeIdVector) {
|
||||
ZigType *elem_type = type_entry->data.vector.elem_type;
|
||||
if (elem_type->id == ZigTypeIdFloat) {
|
||||
ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
|
||||
return LLVMBuildFAdd(g->builder, op1_value, op2_value, "");
|
||||
} else if (elem_type->id == ZigTypeIdPointer) {
|
||||
zig_panic("TODO codegen for pointers in vectors");
|
||||
} else if (elem_type->id == ZigTypeIdInt) {
|
||||
bool is_wrapping = (op_id == IrBinOpAddWrap);
|
||||
if (is_wrapping) {
|
||||
return LLVMBuildAdd(g->builder, op1_value, op2_value, "");
|
||||
} else if (want_runtime_safety) {
|
||||
zig_panic("TODO runtime safety for vector integer addition");
|
||||
} else if (elem_type->data.integral.is_signed) {
|
||||
return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, "");
|
||||
} else {
|
||||
return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, "");
|
||||
}
|
||||
} else {
|
||||
zig_unreachable();
|
||||
return unsigned_op[add_sub_mul](g->builder, op1_value, op2_value, "");
|
||||
}
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
case IrBinOpBinOr:
|
||||
return LLVMBuildOr(g->builder, op1_value, op2_value, "");
|
||||
case IrBinOpBinXor:
|
||||
|
@ -2728,49 +2755,6 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
|
|||
return ZigLLVMBuildLShrExact(g->builder, op1_value, op2_casted, "");
|
||||
}
|
||||
}
|
||||
case IrBinOpSub:
|
||||
case IrBinOpSubWrap:
|
||||
if (type_entry->id == ZigTypeIdPointer) {
|
||||
assert(type_entry->data.pointer.ptr_len == PtrLenUnknown);
|
||||
// TODO runtime safety
|
||||
LLVMValueRef subscript_value = LLVMBuildNeg(g->builder, op2_value, "");
|
||||
return LLVMBuildInBoundsGEP(g->builder, op1_value, &subscript_value, 1, "");
|
||||
} else if (type_entry->id == ZigTypeIdFloat) {
|
||||
ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
|
||||
return LLVMBuildFSub(g->builder, op1_value, op2_value, "");
|
||||
} else if (type_entry->id == ZigTypeIdInt) {
|
||||
bool is_wrapping = (op_id == IrBinOpSubWrap);
|
||||
if (is_wrapping) {
|
||||
return LLVMBuildSub(g->builder, op1_value, op2_value, "");
|
||||
} else if (want_runtime_safety) {
|
||||
return gen_overflow_op(g, type_entry, AddSubMulSub, op1_value, op2_value);
|
||||
} else if (type_entry->data.integral.is_signed) {
|
||||
return LLVMBuildNSWSub(g->builder, op1_value, op2_value, "");
|
||||
} else {
|
||||
return LLVMBuildNUWSub(g->builder, op1_value, op2_value, "");
|
||||
}
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
case IrBinOpMult:
|
||||
case IrBinOpMultWrap:
|
||||
if (type_entry->id == ZigTypeIdFloat) {
|
||||
ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
|
||||
return LLVMBuildFMul(g->builder, op1_value, op2_value, "");
|
||||
} else if (type_entry->id == ZigTypeIdInt) {
|
||||
bool is_wrapping = (op_id == IrBinOpMultWrap);
|
||||
if (is_wrapping) {
|
||||
return LLVMBuildMul(g->builder, op1_value, op2_value, "");
|
||||
} else if (want_runtime_safety) {
|
||||
return gen_overflow_op(g, type_entry, AddSubMulMul, op1_value, op2_value);
|
||||
} else if (type_entry->data.integral.is_signed) {
|
||||
return LLVMBuildNSWMul(g->builder, op1_value, op2_value, "");
|
||||
} else {
|
||||
return LLVMBuildNUWMul(g->builder, op1_value, op2_value, "");
|
||||
}
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
case IrBinOpDivUnspecified:
|
||||
return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base),
|
||||
op1_value, op2_value, type_entry, DivKindFloat);
|
||||
|
@ -6361,6 +6345,12 @@ static void validate_inline_fns(CodeGen *g) {
|
|||
report_errors_and_maybe_exit(g);
|
||||
}
|
||||
|
||||
static void set_global_tls(CodeGen *g, ZigVar *var, LLVMValueRef global_value) {
|
||||
if (var->is_thread_local && !g->is_single_threaded) {
|
||||
LLVMSetThreadLocalMode(global_value, LLVMGeneralDynamicTLSModel);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_code_gen(CodeGen *g) {
|
||||
assert(!g->errors.length);
|
||||
|
||||
|
@ -6445,6 +6435,7 @@ static void do_code_gen(CodeGen *g) {
|
|||
maybe_import_dll(g, global_value, GlobalLinkageIdStrong);
|
||||
LLVMSetAlignment(global_value, var->align_bytes);
|
||||
LLVMSetGlobalConstant(global_value, var->gen_is_const);
|
||||
set_global_tls(g, var, global_value);
|
||||
}
|
||||
} else {
|
||||
bool exported = (var->linkage == VarLinkageExport);
|
||||
|
@ -6470,6 +6461,7 @@ static void do_code_gen(CodeGen *g) {
|
|||
}
|
||||
|
||||
LLVMSetGlobalConstant(global_value, var->gen_is_const);
|
||||
set_global_tls(g, var, global_value);
|
||||
}
|
||||
|
||||
var->value_ref = global_value;
|
||||
|
@ -7520,6 +7512,7 @@ static Error define_builtin_compile_vars(CodeGen *g) {
|
|||
g->compile_var_package = new_package(buf_ptr(this_dir), builtin_zig_basename);
|
||||
g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
|
||||
g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
|
||||
g->std_package->package_table.put(buf_create_from_str("std"), g->std_package);
|
||||
g->compile_var_import = add_source_file(g, g->compile_var_package, builtin_zig_path, contents);
|
||||
scan_import(g, g->compile_var_import);
|
||||
|
||||
|
@ -7560,7 +7553,13 @@ static void init(CodeGen *g) {
|
|||
LLVMTargetRef target_ref;
|
||||
char *err_msg = nullptr;
|
||||
if (LLVMGetTargetFromTriple(buf_ptr(&g->triple_str), &target_ref, &err_msg)) {
|
||||
zig_panic("unable to create target based on: %s", buf_ptr(&g->triple_str));
|
||||
fprintf(stderr,
|
||||
"Zig is expecting LLVM to understand this target: '%s'\n"
|
||||
"However LLVM responded with: \"%s\"\n"
|
||||
"Zig is unable to continue. This is a bug in Zig:\n"
|
||||
"https://github.com/ziglang/zig/issues/438\n"
|
||||
, buf_ptr(&g->triple_str), err_msg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bool is_optimized = g->build_mode != BuildModeDebug;
|
||||
|
@ -8349,8 +8348,12 @@ static void add_cache_pkg(CodeGen *g, CacheHash *ch, PackageTableEntry *pkg) {
|
|||
if (!entry)
|
||||
break;
|
||||
|
||||
cache_buf(ch, entry->key);
|
||||
add_cache_pkg(g, ch, entry->value);
|
||||
// TODO: I think we need a more sophisticated detection of
|
||||
// packages we have already seen
|
||||
if (entry->value != pkg) {
|
||||
cache_buf(ch, entry->key);
|
||||
add_cache_pkg(g, ch, entry->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <stdio.h>
|
||||
|
||||
CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode,
|
||||
Buf *zig_lib_dir);
|
||||
Buf *zig_lib_dir, Buf *override_std_dir);
|
||||
|
||||
void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len);
|
||||
void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len);
|
||||
|
|
|
@ -5204,6 +5204,10 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
|
|||
add_node_error(irb->codegen, variable_declaration->section_expr,
|
||||
buf_sprintf("cannot set section of local variable '%s'", buf_ptr(variable_declaration->symbol)));
|
||||
}
|
||||
if (variable_declaration->threadlocal_tok != nullptr) {
|
||||
add_token_error(irb->codegen, node->owner, variable_declaration->threadlocal_tok,
|
||||
buf_sprintf("function-local variable '%s' cannot be threadlocal", buf_ptr(variable_declaration->symbol)));
|
||||
}
|
||||
|
||||
// Temporarily set the name of the IrExecutable to the VariableDeclaration
|
||||
// so that the struct or enum from the init expression inherits the name.
|
||||
|
|
|
@ -42,7 +42,7 @@ static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path)
|
|||
}
|
||||
|
||||
CodeGen *child_gen = codegen_create(full_path, child_target, child_out_type,
|
||||
parent_gen->build_mode, parent_gen->zig_lib_dir);
|
||||
parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir);
|
||||
|
||||
child_gen->out_h_path = nullptr;
|
||||
child_gen->verbose_tokenize = parent_gen->verbose_tokenize;
|
||||
|
|
12
src/main.cpp
12
src/main.cpp
|
@ -74,6 +74,7 @@ static int print_full_usage(const char *arg0) {
|
|||
" -dirafter [dir] same as -isystem but do it last\n"
|
||||
" -isystem [dir] add additional search path for other .h files\n"
|
||||
" -mllvm [arg] forward an arg to LLVM's option processing\n"
|
||||
" --override-std-dir [arg] use an alternate Zig standard library\n"
|
||||
"\n"
|
||||
"Link Options:\n"
|
||||
" --dynamic-linker [path] set the path to ld.so\n"
|
||||
|
@ -395,6 +396,7 @@ int main(int argc, char **argv) {
|
|||
bool system_linker_hack = false;
|
||||
TargetSubsystem subsystem = TargetSubsystemAuto;
|
||||
bool is_single_threaded = false;
|
||||
Buf *override_std_dir = nullptr;
|
||||
|
||||
if (argc >= 2 && strcmp(argv[1], "build") == 0) {
|
||||
Buf zig_exe_path_buf = BUF_INIT;
|
||||
|
@ -430,7 +432,8 @@ int main(int argc, char **argv) {
|
|||
Buf *build_runner_path = buf_alloc();
|
||||
os_path_join(get_zig_special_dir(), buf_create_from_str("build_runner.zig"), build_runner_path);
|
||||
|
||||
CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, get_zig_lib_dir());
|
||||
CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, get_zig_lib_dir(),
|
||||
override_std_dir);
|
||||
g->enable_time_report = timing_info;
|
||||
buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name);
|
||||
codegen_set_out_name(g, buf_create_from_str("build"));
|
||||
|
@ -645,6 +648,8 @@ int main(int argc, char **argv) {
|
|||
clang_argv.append(argv[i]);
|
||||
|
||||
llvm_argv.append(argv[i]);
|
||||
} else if (strcmp(arg, "--override-std-dir") == 0) {
|
||||
override_std_dir = buf_create_from_str(argv[i]);
|
||||
} else if (strcmp(arg, "--library-path") == 0 || strcmp(arg, "-L") == 0) {
|
||||
lib_dirs.append(argv[i]);
|
||||
} else if (strcmp(arg, "--library") == 0) {
|
||||
|
@ -819,7 +824,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
switch (cmd) {
|
||||
case CmdBuiltin: {
|
||||
CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, get_zig_lib_dir());
|
||||
CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, get_zig_lib_dir(), override_std_dir);
|
||||
g->is_single_threaded = is_single_threaded;
|
||||
Buf *builtin_source = codegen_generate_builtin_source(g);
|
||||
if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) {
|
||||
|
@ -878,7 +883,8 @@ int main(int argc, char **argv) {
|
|||
if (cmd == CmdRun && buf_out_name == nullptr) {
|
||||
buf_out_name = buf_create_from_str("run");
|
||||
}
|
||||
CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, get_zig_lib_dir());
|
||||
CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, get_zig_lib_dir(),
|
||||
override_std_dir);
|
||||
g->subsystem = subsystem;
|
||||
|
||||
if (disable_pic) {
|
||||
|
|
|
@ -844,12 +844,17 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) {
|
|||
|
||||
// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON
|
||||
static AstNode *ast_parse_var_decl(ParseContext *pc) {
|
||||
Token *first = eat_token_if(pc, TokenIdKeywordConst);
|
||||
if (first == nullptr)
|
||||
first = eat_token_if(pc, TokenIdKeywordVar);
|
||||
if (first == nullptr)
|
||||
return nullptr;
|
||||
|
||||
Token *thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal);
|
||||
Token *mut_kw = eat_token_if(pc, TokenIdKeywordConst);
|
||||
if (mut_kw == nullptr)
|
||||
mut_kw = eat_token_if(pc, TokenIdKeywordVar);
|
||||
if (mut_kw == nullptr) {
|
||||
if (thread_local_kw == nullptr) {
|
||||
return nullptr;
|
||||
} else {
|
||||
ast_invalid_token_error(pc, peek_token(pc));
|
||||
}
|
||||
}
|
||||
Token *identifier = expect_token(pc, TokenIdSymbol);
|
||||
AstNode *type_expr = nullptr;
|
||||
if (eat_token_if(pc, TokenIdColon) != nullptr)
|
||||
|
@ -863,8 +868,9 @@ static AstNode *ast_parse_var_decl(ParseContext *pc) {
|
|||
|
||||
expect_token(pc, TokenIdSemicolon);
|
||||
|
||||
AstNode *res = ast_create_node(pc, NodeTypeVariableDeclaration, first);
|
||||
res->data.variable_declaration.is_const = first->id == TokenIdKeywordConst;
|
||||
AstNode *res = ast_create_node(pc, NodeTypeVariableDeclaration, mut_kw);
|
||||
res->data.variable_declaration.threadlocal_tok = thread_local_kw;
|
||||
res->data.variable_declaration.is_const = mut_kw->id == TokenIdKeywordConst;
|
||||
res->data.variable_declaration.symbol = token_buf(identifier);
|
||||
res->data.variable_declaration.type = type_expr;
|
||||
res->data.variable_declaration.align_expr = align_expr;
|
||||
|
|
|
@ -146,6 +146,7 @@ static const struct ZigKeyword zig_keywords[] = {
|
|||
{"suspend", TokenIdKeywordSuspend},
|
||||
{"switch", TokenIdKeywordSwitch},
|
||||
{"test", TokenIdKeywordTest},
|
||||
{"threadlocal", TokenIdKeywordThreadLocal},
|
||||
{"true", TokenIdKeywordTrue},
|
||||
{"try", TokenIdKeywordTry},
|
||||
{"undefined", TokenIdKeywordUndefined},
|
||||
|
@ -1586,6 +1587,7 @@ const char * token_name(TokenId id) {
|
|||
case TokenIdKeywordStruct: return "struct";
|
||||
case TokenIdKeywordSwitch: return "switch";
|
||||
case TokenIdKeywordTest: return "test";
|
||||
case TokenIdKeywordThreadLocal: return "threadlocal";
|
||||
case TokenIdKeywordTrue: return "true";
|
||||
case TokenIdKeywordTry: return "try";
|
||||
case TokenIdKeywordUndefined: return "undefined";
|
||||
|
|
|
@ -88,6 +88,7 @@ enum TokenId {
|
|||
TokenIdKeywordSuspend,
|
||||
TokenIdKeywordSwitch,
|
||||
TokenIdKeywordTest,
|
||||
TokenIdKeywordThreadLocal,
|
||||
TokenIdKeywordTrue,
|
||||
TokenIdKeywordTry,
|
||||
TokenIdKeywordUndefined,
|
||||
|
|
|
@ -145,8 +145,8 @@ pub const Builder = struct {
|
|||
|
||||
pub fn setInstallPrefix(self: *Builder, maybe_prefix: ?[]const u8) void {
|
||||
self.prefix = maybe_prefix orelse "/usr/local"; // TODO better default
|
||||
self.lib_dir = os.path.join(self.allocator, self.prefix, "lib") catch unreachable;
|
||||
self.exe_dir = os.path.join(self.allocator, self.prefix, "bin") catch unreachable;
|
||||
self.lib_dir = os.path.join(self.allocator, [][]const u8{ self.prefix, "lib" }) catch unreachable;
|
||||
self.exe_dir = os.path.join(self.allocator, [][]const u8{ self.prefix, "bin" }) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
|
||||
|
@ -618,7 +618,10 @@ pub const Builder = struct {
|
|||
|
||||
///::dest_rel_path is relative to prefix path or it can be an absolute path
|
||||
pub fn addInstallFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep {
|
||||
const full_dest_path = os.path.resolve(self.allocator, self.prefix, dest_rel_path) catch unreachable;
|
||||
const full_dest_path = os.path.resolve(
|
||||
self.allocator,
|
||||
[][]const u8{ self.prefix, dest_rel_path },
|
||||
) catch unreachable;
|
||||
self.pushInstalledFile(full_dest_path);
|
||||
|
||||
const install_step = self.allocator.create(InstallFileStep) catch unreachable;
|
||||
|
@ -653,7 +656,7 @@ pub const Builder = struct {
|
|||
}
|
||||
|
||||
fn pathFromRoot(self: *Builder, rel_path: []const u8) []u8 {
|
||||
return os.path.resolve(self.allocator, self.build_root, rel_path) catch unreachable;
|
||||
return os.path.resolve(self.allocator, [][]const u8{ self.build_root, rel_path }) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn fmt(self: *Builder, comptime format: []const u8, args: ...) []u8 {
|
||||
|
@ -676,7 +679,7 @@ pub const Builder = struct {
|
|||
if (os.path.isAbsolute(name)) {
|
||||
return name;
|
||||
}
|
||||
const full_path = try os.path.join(self.allocator, search_prefix, "bin", self.fmt("{}{}", name, exe_extension));
|
||||
const full_path = try os.path.join(self.allocator, [][]const u8{ search_prefix, "bin", self.fmt("{}{}", name, exe_extension) });
|
||||
if (os.path.real(self.allocator, full_path)) |real_path| {
|
||||
return real_path;
|
||||
} else |_| {
|
||||
|
@ -691,7 +694,7 @@ pub const Builder = struct {
|
|||
}
|
||||
var it = mem.tokenize(PATH, []u8{os.path.delimiter});
|
||||
while (it.next()) |path| {
|
||||
const full_path = try os.path.join(self.allocator, path, self.fmt("{}{}", name, exe_extension));
|
||||
const full_path = try os.path.join(self.allocator, [][]const u8{ path, self.fmt("{}{}", name, exe_extension) });
|
||||
if (os.path.real(self.allocator, full_path)) |real_path| {
|
||||
return real_path;
|
||||
} else |_| {
|
||||
|
@ -705,7 +708,7 @@ pub const Builder = struct {
|
|||
return name;
|
||||
}
|
||||
for (paths) |path| {
|
||||
const full_path = try os.path.join(self.allocator, path, self.fmt("{}{}", name, exe_extension));
|
||||
const full_path = try os.path.join(self.allocator, [][]const u8{ path, self.fmt("{}{}", name, exe_extension) });
|
||||
if (os.path.real(self.allocator, full_path)) |real_path| {
|
||||
return real_path;
|
||||
} else |_| {
|
||||
|
@ -1113,7 +1116,10 @@ pub const LibExeObjStep = struct {
|
|||
}
|
||||
|
||||
pub fn getOutputPath(self: *LibExeObjStep) []const u8 {
|
||||
return if (self.output_path) |output_path| output_path else os.path.join(self.builder.allocator, self.builder.cache_root, self.out_filename) catch unreachable;
|
||||
return if (self.output_path) |output_path| output_path else os.path.join(
|
||||
self.builder.allocator,
|
||||
[][]const u8{ self.builder.cache_root, self.out_filename },
|
||||
) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn setOutputHPath(self: *LibExeObjStep, file_path: []const u8) void {
|
||||
|
@ -1126,7 +1132,10 @@ pub const LibExeObjStep = struct {
|
|||
}
|
||||
|
||||
pub fn getOutputHPath(self: *LibExeObjStep) []const u8 {
|
||||
return if (self.output_h_path) |output_h_path| output_h_path else os.path.join(self.builder.allocator, self.builder.cache_root, self.out_h_filename) catch unreachable;
|
||||
return if (self.output_h_path) |output_h_path| output_h_path else os.path.join(
|
||||
self.builder.allocator,
|
||||
[][]const u8{ self.builder.cache_root, self.out_h_filename },
|
||||
) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn addAssemblyFile(self: *LibExeObjStep, path: []const u8) void {
|
||||
|
@ -1226,7 +1235,10 @@ pub const LibExeObjStep = struct {
|
|||
}
|
||||
|
||||
if (self.build_options_contents.len() > 0) {
|
||||
const build_options_file = try os.path.join(builder.allocator, builder.cache_root, builder.fmt("{}_build_options.zig", self.name));
|
||||
const build_options_file = try os.path.join(
|
||||
builder.allocator,
|
||||
[][]const u8{ builder.cache_root, builder.fmt("{}_build_options.zig", self.name) },
|
||||
);
|
||||
try std.io.writeFile(build_options_file, self.build_options_contents.toSliceConst());
|
||||
try zig_args.append("--pkg-begin");
|
||||
try zig_args.append("build_options");
|
||||
|
@ -1476,7 +1488,10 @@ pub const LibExeObjStep = struct {
|
|||
cc_args.append("-c") catch unreachable;
|
||||
cc_args.append(abs_source_file) catch unreachable;
|
||||
|
||||
const cache_o_src = os.path.join(builder.allocator, builder.cache_root, source_file) catch unreachable;
|
||||
const cache_o_src = os.path.join(
|
||||
builder.allocator,
|
||||
[][]const u8{ builder.cache_root, source_file },
|
||||
) catch unreachable;
|
||||
if (os.path.dirname(cache_o_src)) |cache_o_dir| {
|
||||
try builder.makePath(cache_o_dir);
|
||||
}
|
||||
|
@ -1528,7 +1543,10 @@ pub const LibExeObjStep = struct {
|
|||
cc_args.append("-current_version") catch unreachable;
|
||||
cc_args.append(builder.fmt("{}.{}.{}", self.version.major, self.version.minor, self.version.patch)) catch unreachable;
|
||||
|
||||
const install_name = builder.pathFromRoot(os.path.join(builder.allocator, builder.cache_root, self.major_only_filename) catch unreachable);
|
||||
const install_name = builder.pathFromRoot(os.path.join(
|
||||
builder.allocator,
|
||||
[][]const u8{ builder.cache_root, self.major_only_filename },
|
||||
) catch unreachable);
|
||||
cc_args.append("-install_name") catch unreachable;
|
||||
cc_args.append(install_name) catch unreachable;
|
||||
} else {
|
||||
|
@ -1594,7 +1612,10 @@ pub const LibExeObjStep = struct {
|
|||
cc_args.append("-c") catch unreachable;
|
||||
cc_args.append(abs_source_file) catch unreachable;
|
||||
|
||||
const cache_o_src = os.path.join(builder.allocator, builder.cache_root, source_file) catch unreachable;
|
||||
const cache_o_src = os.path.join(
|
||||
builder.allocator,
|
||||
[][]const u8{ builder.cache_root, source_file },
|
||||
) catch unreachable;
|
||||
if (os.path.dirname(cache_o_src)) |cache_o_dir| {
|
||||
try builder.makePath(cache_o_dir);
|
||||
}
|
||||
|
@ -1686,6 +1707,7 @@ pub const TestStep = struct {
|
|||
no_rosegment: bool,
|
||||
output_path: ?[]const u8,
|
||||
system_linker_hack: bool,
|
||||
override_std_dir: ?[]const u8,
|
||||
|
||||
pub fn init(builder: *Builder, root_src: []const u8) TestStep {
|
||||
const step_name = builder.fmt("test {}", root_src);
|
||||
|
@ -1707,6 +1729,7 @@ pub const TestStep = struct {
|
|||
.no_rosegment = false,
|
||||
.output_path = null,
|
||||
.system_linker_hack = false,
|
||||
.override_std_dir = null,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1737,6 +1760,10 @@ pub const TestStep = struct {
|
|||
self.build_mode = mode;
|
||||
}
|
||||
|
||||
pub fn overrideStdDir(self: *TestStep, dir_path: []const u8) void {
|
||||
self.override_std_dir = dir_path;
|
||||
}
|
||||
|
||||
pub fn setOutputPath(self: *TestStep, file_path: []const u8) void {
|
||||
self.output_path = file_path;
|
||||
|
||||
|
@ -1751,7 +1778,10 @@ pub const TestStep = struct {
|
|||
return output_path;
|
||||
} else {
|
||||
const basename = self.builder.fmt("test{}", self.target.exeFileExt());
|
||||
return os.path.join(self.builder.allocator, self.builder.cache_root, basename) catch unreachable;
|
||||
return os.path.join(
|
||||
self.builder.allocator,
|
||||
[][]const u8{ self.builder.cache_root, basename },
|
||||
) catch unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1914,6 +1944,10 @@ pub const TestStep = struct {
|
|||
if (self.system_linker_hack) {
|
||||
try zig_args.append("--system-linker-hack");
|
||||
}
|
||||
if (self.override_std_dir) |dir| {
|
||||
try zig_args.append("--override-std-dir");
|
||||
try zig_args.append(builder.pathFromRoot(dir));
|
||||
}
|
||||
|
||||
try builder.spawnChild(zig_args.toSliceConst());
|
||||
}
|
||||
|
@ -1969,13 +2003,22 @@ const InstallArtifactStep = struct {
|
|||
.builder = builder,
|
||||
.step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make),
|
||||
.artifact = artifact,
|
||||
.dest_file = os.path.join(builder.allocator, dest_dir, artifact.out_filename) catch unreachable,
|
||||
.dest_file = os.path.join(
|
||||
builder.allocator,
|
||||
[][]const u8{ dest_dir, artifact.out_filename },
|
||||
) catch unreachable,
|
||||
};
|
||||
self.step.dependOn(&artifact.step);
|
||||
builder.pushInstalledFile(self.dest_file);
|
||||
if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) {
|
||||
builder.pushInstalledFile(os.path.join(builder.allocator, builder.lib_dir, artifact.major_only_filename) catch unreachable);
|
||||
builder.pushInstalledFile(os.path.join(builder.allocator, builder.lib_dir, artifact.name_only_filename) catch unreachable);
|
||||
builder.pushInstalledFile(os.path.join(
|
||||
builder.allocator,
|
||||
[][]const u8{ builder.lib_dir, artifact.major_only_filename },
|
||||
) catch unreachable);
|
||||
builder.pushInstalledFile(os.path.join(
|
||||
builder.allocator,
|
||||
[][]const u8{ builder.lib_dir, artifact.name_only_filename },
|
||||
) catch unreachable);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
@ -2131,13 +2174,19 @@ fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_maj
|
|||
const out_dir = os.path.dirname(output_path) orelse ".";
|
||||
const out_basename = os.path.basename(output_path);
|
||||
// sym link for libfoo.so.1 to libfoo.so.1.2.3
|
||||
const major_only_path = os.path.join(allocator, out_dir, filename_major_only) catch unreachable;
|
||||
const major_only_path = os.path.join(
|
||||
allocator,
|
||||
[][]const u8{ out_dir, filename_major_only },
|
||||
) catch unreachable;
|
||||
os.atomicSymLink(allocator, out_basename, major_only_path) catch |err| {
|
||||
warn("Unable to symlink {} -> {}\n", major_only_path, out_basename);
|
||||
return err;
|
||||
};
|
||||
// sym link for libfoo.so to libfoo.so.1
|
||||
const name_only_path = os.path.join(allocator, out_dir, filename_name_only) catch unreachable;
|
||||
const name_only_path = os.path.join(
|
||||
allocator,
|
||||
[][]const u8{ out_dir, filename_name_only },
|
||||
) catch unreachable;
|
||||
os.atomicSymLink(allocator, filename_major_only, name_only_path) catch |err| {
|
||||
warn("Unable to symlink {} -> {}\n", name_only_path, filename_major_only);
|
||||
return err;
|
||||
|
|
|
@ -37,7 +37,6 @@ const Module = struct {
|
|||
var stderr_file: os.File = undefined;
|
||||
var stderr_file_out_stream: os.File.OutStream = undefined;
|
||||
|
||||
/// TODO multithreaded awareness
|
||||
var stderr_stream: ?*io.OutStream(os.File.WriteError) = null;
|
||||
var stderr_mutex = std.Mutex.init();
|
||||
pub fn warn(comptime fmt: []const u8, args: ...) void {
|
||||
|
@ -775,7 +774,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
|
|||
const len = try di.coff.getPdbPath(path_buf[0..]);
|
||||
const raw_path = path_buf[0..len];
|
||||
|
||||
const path = try os.path.resolve(allocator, raw_path);
|
||||
const path = try os.path.resolve(allocator, [][]const u8{raw_path});
|
||||
|
||||
try di.pdb.openFile(di.coff, path);
|
||||
|
||||
|
@ -1353,7 +1352,7 @@ const LineNumberProgram = struct {
|
|||
return error.InvalidDebugInfo;
|
||||
} else
|
||||
self.include_dirs[file_entry.dir_index];
|
||||
const file_name = try os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name);
|
||||
const file_name = try os.path.join(self.file_entries.allocator, [][]const u8{ dir_name, file_entry.file_name });
|
||||
errdefer self.file_entries.allocator.free(file_name);
|
||||
return LineInfo{
|
||||
.line = if (self.prev_line >= 0) @intCast(usize, self.prev_line) else 0,
|
||||
|
|
|
@ -871,7 +871,7 @@ pub fn Watch(comptime V: type) type {
|
|||
}
|
||||
|
||||
async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V {
|
||||
const resolved_path = try os.path.resolve(self.channel.loop.allocator, file_path);
|
||||
const resolved_path = try os.path.resolve(self.channel.loop.allocator, [][]const u8{file_path});
|
||||
var resolved_path_consumed = false;
|
||||
defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path);
|
||||
|
||||
|
@ -1336,7 +1336,7 @@ async fn testFsWatchCantFail(loop: *Loop, result: *(anyerror!void)) void {
|
|||
}
|
||||
|
||||
async fn testFsWatch(loop: *Loop) !void {
|
||||
const file_path = try os.path.join(loop.allocator, test_tmp_dir, "file.txt");
|
||||
const file_path = try os.path.join(loop.allocator, [][]const u8{ test_tmp_dir, "file.txt" });
|
||||
defer loop.allocator.free(file_path);
|
||||
|
||||
const contents =
|
||||
|
|
|
@ -106,9 +106,7 @@ pub const DirectAllocator = struct {
|
|||
};
|
||||
const ptr = os.windows.HeapAlloc(heap_handle, 0, amt) orelse return error.OutOfMemory;
|
||||
const root_addr = @ptrToInt(ptr);
|
||||
const rem = @rem(root_addr, alignment);
|
||||
const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
|
||||
const adjusted_addr = root_addr + march_forward_bytes;
|
||||
const adjusted_addr = mem.alignForward(root_addr, alignment);
|
||||
const record_addr = adjusted_addr + n;
|
||||
@intToPtr(*align(1) usize, record_addr).* = root_addr;
|
||||
return @intToPtr([*]u8, adjusted_addr)[0..n];
|
||||
|
@ -126,8 +124,7 @@ pub const DirectAllocator = struct {
|
|||
const base_addr = @ptrToInt(old_mem.ptr);
|
||||
const old_addr_end = base_addr + old_mem.len;
|
||||
const new_addr_end = base_addr + new_size;
|
||||
const rem = @rem(new_addr_end, os.page_size);
|
||||
const new_addr_end_rounded = new_addr_end + if (rem == 0) 0 else (os.page_size - rem);
|
||||
const new_addr_end_rounded = mem.alignForward(new_addr_end, os.page_size);
|
||||
if (old_addr_end > new_addr_end_rounded) {
|
||||
_ = os.posix.munmap(new_addr_end_rounded, old_addr_end - new_addr_end_rounded);
|
||||
}
|
||||
|
|
|
@ -33,8 +33,8 @@ pub const io = @import("io.zig");
|
|||
pub const json = @import("json.zig");
|
||||
pub const macho = @import("macho.zig");
|
||||
pub const math = @import("math/index.zig");
|
||||
pub const meta = @import("meta/index.zig");
|
||||
pub const mem = @import("mem.zig");
|
||||
pub const meta = @import("meta/index.zig");
|
||||
pub const net = @import("net.zig");
|
||||
pub const os = @import("os/index.zig");
|
||||
pub const pdb = @import("pdb.zig");
|
||||
|
|
10
std/io.zig
10
std/io.zig
|
@ -912,7 +912,7 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
|
|||
}
|
||||
|
||||
/// Flush any remaining bits to the stream.
|
||||
pub fn flushBits(self: *Self) !void {
|
||||
pub fn flushBits(self: *Self) Error!void {
|
||||
if (self.bit_count == 0) return;
|
||||
try self.out_stream.writeByte(self.bit_buffer);
|
||||
self.bit_buffer = 0;
|
||||
|
@ -1079,7 +1079,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E
|
|||
}
|
||||
|
||||
//@BUG: inferred error issue. See: #1386
|
||||
fn deserializeInt(self: *Self, comptime T: type) (Stream.Error || error{EndOfStream})!T {
|
||||
fn deserializeInt(self: *Self, comptime T: type) (Error || error{EndOfStream})!T {
|
||||
comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T));
|
||||
|
||||
const u8_bit_count = 8;
|
||||
|
@ -1287,11 +1287,11 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime is_packed: bool, com
|
|||
}
|
||||
|
||||
/// Flushes any unwritten bits to the stream
|
||||
pub fn flush(self: *Self) Stream.Error!void {
|
||||
pub fn flush(self: *Self) Error!void {
|
||||
if (is_packed) return self.out_stream.flushBits();
|
||||
}
|
||||
|
||||
fn serializeInt(self: *Self, value: var) !void {
|
||||
fn serializeInt(self: *Self, value: var) Error!void {
|
||||
const T = @typeOf(value);
|
||||
comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T));
|
||||
|
||||
|
@ -1323,7 +1323,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime is_packed: bool, com
|
|||
}
|
||||
|
||||
/// Serializes the passed value into the stream
|
||||
pub fn serialize(self: *Self, value: var) !void {
|
||||
pub fn serialize(self: *Self, value: var) Error!void {
|
||||
const T = comptime @typeOf(value);
|
||||
|
||||
if (comptime trait.isIndexable(T)) {
|
||||
|
|
|
@ -357,6 +357,15 @@ fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime is_pa
|
|||
const total_packed_bytes = (total_bits / u8_bit_count) + extra_packed_byte;
|
||||
|
||||
assert(in.pos == if (is_packed) total_packed_bytes else total_bytes);
|
||||
|
||||
//Verify that empty error set works with serializer.
|
||||
//deserializer is covered by SliceInStream
|
||||
const NullError = io.NullOutStream.Error;
|
||||
var null_out = io.NullOutStream.init();
|
||||
var null_out_stream = &null_out.stream;
|
||||
var null_serializer = io.Serializer(endian, is_packed, NullError).init(null_out_stream);
|
||||
try null_serializer.serialize(data_mem[0..]);
|
||||
try null_serializer.flush();
|
||||
}
|
||||
|
||||
test "Serializer/Deserializer Int" {
|
||||
|
@ -568,4 +577,4 @@ test "Deserializer bad data" {
|
|||
try testBadData(builtin.Endian.Little, false);
|
||||
try testBadData(builtin.Endian.Big, true);
|
||||
try testBadData(builtin.Endian.Little, true);
|
||||
}
|
||||
}
|
||||
|
|
72
std/mem.zig
72
std/mem.zig
|
@ -882,42 +882,40 @@ pub const SplitIterator = struct {
|
|||
}
|
||||
};
|
||||
|
||||
/// Naively combines a series of strings with a separator.
|
||||
/// Naively combines a series of slices with a separator.
|
||||
/// Allocates memory for the result, which must be freed by the caller.
|
||||
pub fn join(allocator: *Allocator, sep: u8, strings: ...) ![]u8 {
|
||||
comptime assert(strings.len >= 1);
|
||||
var total_strings_len: usize = strings.len; // 1 sep per string
|
||||
{
|
||||
comptime var string_i = 0;
|
||||
inline while (string_i < strings.len) : (string_i += 1) {
|
||||
const arg = ([]const u8)(strings[string_i]);
|
||||
total_strings_len += arg.len;
|
||||
}
|
||||
}
|
||||
pub fn join(allocator: *Allocator, separator: []const u8, slices: []const []const u8) ![]u8 {
|
||||
if (slices.len == 0) return (([*]u8)(undefined))[0..0];
|
||||
|
||||
const buf = try allocator.alloc(u8, total_strings_len);
|
||||
const total_len = blk: {
|
||||
var sum: usize = separator.len * (slices.len - 1);
|
||||
for (slices) |slice|
|
||||
sum += slice.len;
|
||||
break :blk sum;
|
||||
};
|
||||
|
||||
const buf = try allocator.alloc(u8, total_len);
|
||||
errdefer allocator.free(buf);
|
||||
|
||||
var buf_index: usize = 0;
|
||||
comptime var string_i = 0;
|
||||
inline while (true) {
|
||||
const arg = ([]const u8)(strings[string_i]);
|
||||
string_i += 1;
|
||||
copy(u8, buf[buf_index..], arg);
|
||||
buf_index += arg.len;
|
||||
if (string_i >= strings.len) break;
|
||||
if (buf[buf_index - 1] != sep) {
|
||||
buf[buf_index] = sep;
|
||||
buf_index += 1;
|
||||
}
|
||||
copy(u8, buf, slices[0]);
|
||||
var buf_index: usize = slices[0].len;
|
||||
for (slices[1..]) |slice| {
|
||||
copy(u8, buf[buf_index..], separator);
|
||||
buf_index += separator.len;
|
||||
copy(u8, buf[buf_index..], slice);
|
||||
buf_index += slice.len;
|
||||
}
|
||||
|
||||
return allocator.shrink(u8, buf, buf_index);
|
||||
// No need for shrink since buf is exactly the correct size.
|
||||
return buf;
|
||||
}
|
||||
|
||||
test "mem.join" {
|
||||
assert(eql(u8, try join(debug.global_allocator, ',', "a", "b", "c"), "a,b,c"));
|
||||
assert(eql(u8, try join(debug.global_allocator, ',', "a"), "a"));
|
||||
var buf: [1024]u8 = undefined;
|
||||
const a = &std.heap.FixedBufferAllocator.init(&buf).allocator;
|
||||
assert(eql(u8, try join(a, ",", [][]const u8{ "a", "b", "c" }), "a,b,c"));
|
||||
assert(eql(u8, try join(a, ",", [][]const u8{"a"}), "a"));
|
||||
assert(eql(u8, try join(a, ",", [][]const u8{ "a", "", "b", "", "c" }), "a,,b,,c"));
|
||||
}
|
||||
|
||||
test "testStringEquality" {
|
||||
|
@ -1366,3 +1364,23 @@ test "std.mem.subArrayPtr" {
|
|||
sub2[1] = 'X';
|
||||
debug.assert(std.mem.eql(u8, a2, "abcXef"));
|
||||
}
|
||||
|
||||
/// Round an address up to the nearest aligned address
|
||||
pub fn alignForward(addr: usize, alignment: usize) usize {
|
||||
return (addr + alignment - 1) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
test "std.mem.alignForward" {
|
||||
debug.assertOrPanic(alignForward(1, 1) == 1);
|
||||
debug.assertOrPanic(alignForward(2, 1) == 2);
|
||||
debug.assertOrPanic(alignForward(1, 2) == 2);
|
||||
debug.assertOrPanic(alignForward(2, 2) == 2);
|
||||
debug.assertOrPanic(alignForward(3, 2) == 4);
|
||||
debug.assertOrPanic(alignForward(4, 2) == 4);
|
||||
debug.assertOrPanic(alignForward(7, 8) == 8);
|
||||
debug.assertOrPanic(alignForward(8, 8) == 8);
|
||||
debug.assertOrPanic(alignForward(9, 8) == 16);
|
||||
debug.assertOrPanic(alignForward(15, 8) == 16);
|
||||
debug.assertOrPanic(alignForward(16, 8) == 16);
|
||||
debug.assertOrPanic(alignForward(17, 8) == 24);
|
||||
}
|
||||
|
|
|
@ -574,7 +574,7 @@ pub const ChildProcess = struct {
|
|||
// to match posix semantics
|
||||
const app_name = x: {
|
||||
if (self.cwd) |cwd| {
|
||||
const resolved = try os.path.resolve(self.allocator, cwd, self.argv[0]);
|
||||
const resolved = try os.path.resolve(self.allocator, [][]const u8{ cwd, self.argv[0] });
|
||||
defer self.allocator.free(resolved);
|
||||
break :x try cstr.addNullByte(self.allocator, resolved);
|
||||
} else {
|
||||
|
@ -597,10 +597,10 @@ pub const ChildProcess = struct {
|
|||
|
||||
var it = mem.tokenize(PATH, ";");
|
||||
while (it.next()) |search_path| {
|
||||
const joined_path = try os.path.join(self.allocator, search_path, app_name);
|
||||
const joined_path = try os.path.join(self.allocator, [][]const u8{ search_path, app_name });
|
||||
defer self.allocator.free(joined_path);
|
||||
|
||||
const joined_path_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, app_name);
|
||||
const joined_path_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, joined_path);
|
||||
defer self.allocator.free(joined_path_w);
|
||||
|
||||
if (windowsCreateProcess(joined_path_w.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo)) |_| {
|
||||
|
@ -610,6 +610,9 @@ pub const ChildProcess = struct {
|
|||
} else {
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
// Every other error would have been returned earlier.
|
||||
return error.FileNotFound;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD
|
|||
error.OutOfMemory => return error.OutOfMemory,
|
||||
};
|
||||
defer allocator.free(global_dir);
|
||||
return os.path.join(allocator, global_dir, appname);
|
||||
return os.path.join(allocator, [][]const u8{ global_dir, appname });
|
||||
},
|
||||
os.windows.E_OUTOFMEMORY => return error.OutOfMemory,
|
||||
else => return error.AppDataDirUnavailable,
|
||||
|
@ -41,14 +41,14 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD
|
|||
// TODO look in /etc/passwd
|
||||
return error.AppDataDirUnavailable;
|
||||
};
|
||||
return os.path.join(allocator, home_dir, "Library", "Application Support", appname);
|
||||
return os.path.join(allocator, [][]const u8{ home_dir, "Library", "Application Support", appname });
|
||||
},
|
||||
builtin.Os.linux, builtin.Os.freebsd => {
|
||||
const home_dir = os.getEnvPosix("HOME") orelse {
|
||||
// TODO look in /etc/passwd
|
||||
return error.AppDataDirUnavailable;
|
||||
};
|
||||
return os.path.join(allocator, home_dir, ".local", "share", appname);
|
||||
return os.path.join(allocator, [][]const u8{ home_dir, ".local", "share", appname });
|
||||
},
|
||||
else => @compileError("Unsupported OS"),
|
||||
}
|
||||
|
@ -67,4 +67,3 @@ test "std.os.getAppDataDir" {
|
|||
// We can't actually validate the result
|
||||
_ = getAppDataDir(allocator, "zig") catch return;
|
||||
}
|
||||
|
||||
|
|
113
std/os/index.zig
113
std/os/index.zig
|
@ -8,6 +8,10 @@ const is_posix = switch (builtin.os) {
|
|||
};
|
||||
const os = @This();
|
||||
|
||||
comptime {
|
||||
assert(@import("std") == std); // You have to run the std lib tests with --override-std-dir
|
||||
}
|
||||
|
||||
test "std.os" {
|
||||
_ = @import("child_process.zig");
|
||||
_ = @import("darwin.zig");
|
||||
|
@ -692,12 +696,7 @@ pub fn getBaseAddress() usize {
|
|||
return base;
|
||||
}
|
||||
const phdr = linuxGetAuxVal(std.elf.AT_PHDR);
|
||||
const ElfHeader = switch (@sizeOf(usize)) {
|
||||
4 => std.elf.Elf32_Ehdr,
|
||||
8 => std.elf.Elf64_Ehdr,
|
||||
else => @compileError("Unsupported architecture"),
|
||||
};
|
||||
return phdr - @sizeOf(ElfHeader);
|
||||
return phdr - @sizeOf(std.elf.Ehdr);
|
||||
},
|
||||
builtin.Os.macosx, builtin.Os.freebsd => return @ptrToInt(&std.c._mh_execute_header),
|
||||
builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)),
|
||||
|
@ -1285,7 +1284,7 @@ pub fn makeDirPosix(dir_path: []const u8) !void {
|
|||
/// already exists and is a directory.
|
||||
/// TODO determine if we can remove the allocator requirement from this function
|
||||
pub fn makePath(allocator: *Allocator, full_path: []const u8) !void {
|
||||
const resolved_path = try path.resolve(allocator, full_path);
|
||||
const resolved_path = try path.resolve(allocator, [][]const u8{full_path});
|
||||
defer allocator.free(resolved_path);
|
||||
|
||||
var end_index: usize = resolved_path.len;
|
||||
|
@ -2305,18 +2304,17 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
|
|||
switch (builtin.os) {
|
||||
Os.linux => return readLink(out_buffer, "/proc/self/exe"),
|
||||
Os.freebsd => {
|
||||
var mib = [4]c_int{ posix.CTL_KERN, posix.KERN_PROC, posix.KERN_PROC_PATHNAME, -1};
|
||||
var mib = [4]c_int{ posix.CTL_KERN, posix.KERN_PROC, posix.KERN_PROC_PATHNAME, -1 };
|
||||
var out_len: usize = out_buffer.len;
|
||||
const err = posix.getErrno(posix.sysctl(&mib, 4, out_buffer, &out_len, null, 0));
|
||||
|
||||
if (err == 0 ) return mem.toSlice(u8, out_buffer);
|
||||
if (err == 0) return mem.toSlice(u8, out_buffer);
|
||||
|
||||
return switch (err) {
|
||||
posix.EFAULT => error.BadAdress,
|
||||
posix.EPERM => error.PermissionDenied,
|
||||
else => unexpectedErrorPosix(err),
|
||||
};
|
||||
|
||||
},
|
||||
Os.windows => {
|
||||
var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
|
||||
|
@ -2908,14 +2906,15 @@ pub const Thread = struct {
|
|||
pub const Data = if (use_pthreads)
|
||||
struct {
|
||||
handle: Thread.Handle,
|
||||
stack_addr: usize,
|
||||
stack_len: usize,
|
||||
mmap_addr: usize,
|
||||
mmap_len: usize,
|
||||
}
|
||||
else switch (builtin.os) {
|
||||
builtin.Os.linux => struct {
|
||||
handle: Thread.Handle,
|
||||
stack_addr: usize,
|
||||
stack_len: usize,
|
||||
mmap_addr: usize,
|
||||
mmap_len: usize,
|
||||
tls_end_addr: usize,
|
||||
},
|
||||
builtin.Os.windows => struct {
|
||||
handle: Thread.Handle,
|
||||
|
@ -2955,7 +2954,7 @@ pub const Thread = struct {
|
|||
posix.EDEADLK => unreachable,
|
||||
else => unreachable,
|
||||
}
|
||||
assert(posix.munmap(self.data.stack_addr, self.data.stack_len) == 0);
|
||||
assert(posix.munmap(self.data.mmap_addr, self.data.mmap_len) == 0);
|
||||
} else switch (builtin.os) {
|
||||
builtin.Os.linux => {
|
||||
while (true) {
|
||||
|
@ -2969,7 +2968,7 @@ pub const Thread = struct {
|
|||
else => unreachable,
|
||||
}
|
||||
}
|
||||
assert(posix.munmap(self.data.stack_addr, self.data.stack_len) == 0);
|
||||
assert(posix.munmap(self.data.mmap_addr, self.data.mmap_len) == 0);
|
||||
},
|
||||
builtin.Os.windows => {
|
||||
assert(windows.WaitForSingleObject(self.data.handle, windows.INFINITE) == windows.WAIT_OBJECT_0);
|
||||
|
@ -3008,6 +3007,9 @@ pub const SpawnThreadError = error{
|
|||
Unexpected,
|
||||
};
|
||||
|
||||
pub var linux_tls_phdr: ?*std.elf.Phdr = null;
|
||||
pub var linux_tls_img_src: [*]const u8 = undefined; // defined if linux_tls_phdr is
|
||||
|
||||
/// caller must call wait on the returned thread
|
||||
/// fn startFn(@typeOf(context)) T
|
||||
/// where T is u8, noreturn, void, or !void
|
||||
|
@ -3097,42 +3099,56 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread
|
|||
|
||||
const MAP_GROWSDOWN = if (builtin.os == builtin.Os.linux) linux.MAP_GROWSDOWN else 0;
|
||||
|
||||
const mmap_len = default_stack_size;
|
||||
const stack_addr = posix.mmap(null, mmap_len, posix.PROT_READ | posix.PROT_WRITE, posix.MAP_PRIVATE | posix.MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0);
|
||||
if (stack_addr == posix.MAP_FAILED) return error.OutOfMemory;
|
||||
errdefer assert(posix.munmap(stack_addr, mmap_len) == 0);
|
||||
var stack_end_offset: usize = undefined;
|
||||
var thread_start_offset: usize = undefined;
|
||||
var context_start_offset: usize = undefined;
|
||||
var tls_start_offset: usize = undefined;
|
||||
const mmap_len = blk: {
|
||||
// First in memory will be the stack, which grows downwards.
|
||||
var l: usize = mem.alignForward(default_stack_size, os.page_size);
|
||||
stack_end_offset = l;
|
||||
// Above the stack, so that it can be in the same mmap call, put the Thread object.
|
||||
l = mem.alignForward(l, @alignOf(Thread));
|
||||
thread_start_offset = l;
|
||||
l += @sizeOf(Thread);
|
||||
// Next, the Context object.
|
||||
if (@sizeOf(Context) != 0) {
|
||||
l = mem.alignForward(l, @alignOf(Context));
|
||||
context_start_offset = l;
|
||||
l += @sizeOf(Context);
|
||||
}
|
||||
// Finally, the Thread Local Storage, if any.
|
||||
if (!Thread.use_pthreads) {
|
||||
if (linux_tls_phdr) |tls_phdr| {
|
||||
l = mem.alignForward(l, tls_phdr.p_align);
|
||||
tls_start_offset = l;
|
||||
l += tls_phdr.p_memsz;
|
||||
}
|
||||
}
|
||||
break :blk l;
|
||||
};
|
||||
const mmap_addr = posix.mmap(null, mmap_len, posix.PROT_READ | posix.PROT_WRITE, posix.MAP_PRIVATE | posix.MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0);
|
||||
if (mmap_addr == posix.MAP_FAILED) return error.OutOfMemory;
|
||||
errdefer assert(posix.munmap(mmap_addr, mmap_len) == 0);
|
||||
|
||||
const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(*Thread, mmap_addr + thread_start_offset));
|
||||
thread_ptr.data.mmap_addr = mmap_addr;
|
||||
thread_ptr.data.mmap_len = mmap_len;
|
||||
|
||||
var stack_end: usize = stack_addr + mmap_len;
|
||||
var arg: usize = undefined;
|
||||
if (@sizeOf(Context) != 0) {
|
||||
stack_end -= @sizeOf(Context);
|
||||
stack_end -= stack_end % @alignOf(Context);
|
||||
assert(stack_end >= stack_addr);
|
||||
const context_ptr = @alignCast(@alignOf(Context), @intToPtr(*Context, stack_end));
|
||||
arg = mmap_addr + context_start_offset;
|
||||
const context_ptr = @alignCast(@alignOf(Context), @intToPtr(*Context, arg));
|
||||
context_ptr.* = context;
|
||||
arg = stack_end;
|
||||
}
|
||||
|
||||
stack_end -= @sizeOf(Thread);
|
||||
stack_end -= stack_end % @alignOf(Thread);
|
||||
assert(stack_end >= stack_addr);
|
||||
const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(*Thread, stack_end));
|
||||
|
||||
thread_ptr.data.stack_addr = stack_addr;
|
||||
thread_ptr.data.stack_len = mmap_len;
|
||||
|
||||
if (builtin.os == builtin.Os.windows) {
|
||||
// use windows API directly
|
||||
@compileError("TODO support spawnThread for Windows");
|
||||
} else if (Thread.use_pthreads) {
|
||||
if (Thread.use_pthreads) {
|
||||
// use pthreads
|
||||
var attr: c.pthread_attr_t = undefined;
|
||||
if (c.pthread_attr_init(&attr) != 0) return SpawnThreadError.SystemResources;
|
||||
defer assert(c.pthread_attr_destroy(&attr) == 0);
|
||||
|
||||
// align to page
|
||||
stack_end -= stack_end % os.page_size;
|
||||
assert(c.pthread_attr_setstack(&attr, @intToPtr(*c_void, stack_addr), stack_end - stack_addr) == 0);
|
||||
assert(c.pthread_attr_setstack(&attr, @intToPtr(*c_void, mmap_addr), stack_end_offset) == 0);
|
||||
|
||||
const err = c.pthread_create(&thread_ptr.data.handle, &attr, MainFuncs.posixThreadMain, @intToPtr(*c_void, arg));
|
||||
switch (err) {
|
||||
|
@ -3143,10 +3159,17 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread
|
|||
else => return unexpectedErrorPosix(@intCast(usize, err)),
|
||||
}
|
||||
} else if (builtin.os == builtin.Os.linux) {
|
||||
// use linux API directly. TODO use posix.CLONE_SETTLS and initialize thread local storage correctly
|
||||
const flags = posix.CLONE_VM | posix.CLONE_FS | posix.CLONE_FILES | posix.CLONE_SIGHAND | posix.CLONE_THREAD | posix.CLONE_SYSVSEM | posix.CLONE_PARENT_SETTID | posix.CLONE_CHILD_CLEARTID | posix.CLONE_DETACHED;
|
||||
const newtls: usize = 0;
|
||||
const rc = posix.clone(MainFuncs.linuxThreadMain, stack_end, flags, arg, &thread_ptr.data.handle, newtls, &thread_ptr.data.handle);
|
||||
var flags: u32 = posix.CLONE_VM | posix.CLONE_FS | posix.CLONE_FILES | posix.CLONE_SIGHAND |
|
||||
posix.CLONE_THREAD | posix.CLONE_SYSVSEM | posix.CLONE_PARENT_SETTID | posix.CLONE_CHILD_CLEARTID |
|
||||
posix.CLONE_DETACHED;
|
||||
var newtls: usize = undefined;
|
||||
if (linux_tls_phdr) |tls_phdr| {
|
||||
@memcpy(@intToPtr([*]u8, mmap_addr + tls_start_offset), linux_tls_img_src, tls_phdr.p_filesz);
|
||||
thread_ptr.data.tls_end_addr = mmap_addr + mmap_len;
|
||||
newtls = @ptrToInt(&thread_ptr.data.tls_end_addr);
|
||||
flags |= posix.CLONE_SETTLS;
|
||||
}
|
||||
const rc = posix.clone(MainFuncs.linuxThreadMain, mmap_addr + stack_end_offset, flags, arg, &thread_ptr.data.handle, newtls, &thread_ptr.data.handle);
|
||||
const err = posix.getErrno(rc);
|
||||
switch (err) {
|
||||
0 => return thread_ptr,
|
||||
|
|
125
std/os/path.zig
125
std/os/path.zig
|
@ -33,40 +33,103 @@ pub fn isSep(byte: u8) bool {
|
|||
}
|
||||
}
|
||||
|
||||
/// This is different from mem.join in that the separator will not be repeated if
|
||||
/// it is found at the end or beginning of a pair of consecutive paths.
|
||||
fn joinSep(allocator: *Allocator, separator: u8, paths: []const []const u8) ![]u8 {
|
||||
if (paths.len == 0) return (([*]u8)(undefined))[0..0];
|
||||
|
||||
const total_len = blk: {
|
||||
var sum: usize = paths[0].len;
|
||||
var i: usize = 1;
|
||||
while (i < paths.len) : (i += 1) {
|
||||
const prev_path = paths[i - 1];
|
||||
const this_path = paths[i];
|
||||
const prev_sep = (prev_path.len != 0 and prev_path[prev_path.len - 1] == separator);
|
||||
const this_sep = (this_path.len != 0 and this_path[0] == separator);
|
||||
sum += @boolToInt(!prev_sep and !this_sep);
|
||||
sum += if (prev_sep and this_sep) this_path.len - 1 else this_path.len;
|
||||
}
|
||||
break :blk sum;
|
||||
};
|
||||
|
||||
const buf = try allocator.alloc(u8, total_len);
|
||||
errdefer allocator.free(buf);
|
||||
|
||||
mem.copy(u8, buf, paths[0]);
|
||||
var buf_index: usize = paths[0].len;
|
||||
var i: usize = 1;
|
||||
while (i < paths.len) : (i += 1) {
|
||||
const prev_path = paths[i - 1];
|
||||
const this_path = paths[i];
|
||||
const prev_sep = (prev_path.len != 0 and prev_path[prev_path.len - 1] == separator);
|
||||
const this_sep = (this_path.len != 0 and this_path[0] == separator);
|
||||
if (!prev_sep and !this_sep) {
|
||||
buf[buf_index] = separator;
|
||||
buf_index += 1;
|
||||
}
|
||||
const adjusted_path = if (prev_sep and this_sep) this_path[1..] else this_path;
|
||||
mem.copy(u8, buf[buf_index..], adjusted_path);
|
||||
buf_index += adjusted_path.len;
|
||||
}
|
||||
|
||||
// No need for shrink since buf is exactly the correct size.
|
||||
return buf;
|
||||
}
|
||||
|
||||
pub const join = if (is_windows) joinWindows else joinPosix;
|
||||
|
||||
/// Naively combines a series of paths with the native path seperator.
|
||||
/// Allocates memory for the result, which must be freed by the caller.
|
||||
pub fn join(allocator: *Allocator, paths: ...) ![]u8 {
|
||||
if (is_windows) {
|
||||
return joinWindows(allocator, paths);
|
||||
} else {
|
||||
return joinPosix(allocator, paths);
|
||||
}
|
||||
pub fn joinWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
|
||||
return joinSep(allocator, sep_windows, paths);
|
||||
}
|
||||
|
||||
pub fn joinWindows(allocator: *Allocator, paths: ...) ![]u8 {
|
||||
return mem.join(allocator, sep_windows, paths);
|
||||
/// Naively combines a series of paths with the native path seperator.
|
||||
/// Allocates memory for the result, which must be freed by the caller.
|
||||
pub fn joinPosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
|
||||
return joinSep(allocator, sep_posix, paths);
|
||||
}
|
||||
|
||||
pub fn joinPosix(allocator: *Allocator, paths: ...) ![]u8 {
|
||||
return mem.join(allocator, sep_posix, paths);
|
||||
fn testJoinWindows(paths: []const []const u8, expected: []const u8) void {
|
||||
var buf: [1024]u8 = undefined;
|
||||
const a = &std.heap.FixedBufferAllocator.init(&buf).allocator;
|
||||
const actual = joinWindows(a, paths) catch @panic("fail");
|
||||
debug.assertOrPanic(mem.eql(u8, actual, expected));
|
||||
}
|
||||
|
||||
fn testJoinPosix(paths: []const []const u8, expected: []const u8) void {
|
||||
var buf: [1024]u8 = undefined;
|
||||
const a = &std.heap.FixedBufferAllocator.init(&buf).allocator;
|
||||
const actual = joinPosix(a, paths) catch @panic("fail");
|
||||
debug.assertOrPanic(mem.eql(u8, actual, expected));
|
||||
}
|
||||
|
||||
test "os.path.join" {
|
||||
assert(mem.eql(u8, try joinWindows(debug.global_allocator, "c:\\a\\b", "c"), "c:\\a\\b\\c"));
|
||||
assert(mem.eql(u8, try joinWindows(debug.global_allocator, "c:\\a\\b\\", "c"), "c:\\a\\b\\c"));
|
||||
testJoinWindows([][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c");
|
||||
testJoinWindows([][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c");
|
||||
testJoinWindows([][]const u8{ "c:\\a\\b\\", "c" }, "c:\\a\\b\\c");
|
||||
|
||||
assert(mem.eql(u8, try joinWindows(debug.global_allocator, "c:\\", "a", "b\\", "c"), "c:\\a\\b\\c"));
|
||||
assert(mem.eql(u8, try joinWindows(debug.global_allocator, "c:\\a\\", "b\\", "c"), "c:\\a\\b\\c"));
|
||||
testJoinWindows([][]const u8{ "c:\\", "a", "b\\", "c" }, "c:\\a\\b\\c");
|
||||
testJoinWindows([][]const u8{ "c:\\a\\", "b\\", "c" }, "c:\\a\\b\\c");
|
||||
|
||||
assert(mem.eql(u8, try joinWindows(debug.global_allocator, "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std", "io.zig"), "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig"));
|
||||
testJoinWindows(
|
||||
[][]const u8{ "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std", "io.zig" },
|
||||
"c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig",
|
||||
);
|
||||
|
||||
assert(mem.eql(u8, try joinPosix(debug.global_allocator, "/a/b", "c"), "/a/b/c"));
|
||||
assert(mem.eql(u8, try joinPosix(debug.global_allocator, "/a/b/", "c"), "/a/b/c"));
|
||||
testJoinPosix([][]const u8{ "/a/b", "c" }, "/a/b/c");
|
||||
testJoinPosix([][]const u8{ "/a/b/", "c" }, "/a/b/c");
|
||||
|
||||
assert(mem.eql(u8, try joinPosix(debug.global_allocator, "/", "a", "b/", "c"), "/a/b/c"));
|
||||
assert(mem.eql(u8, try joinPosix(debug.global_allocator, "/a/", "b/", "c"), "/a/b/c"));
|
||||
testJoinPosix([][]const u8{ "/", "a", "b/", "c" }, "/a/b/c");
|
||||
testJoinPosix([][]const u8{ "/a/", "b/", "c" }, "/a/b/c");
|
||||
|
||||
assert(mem.eql(u8, try joinPosix(debug.global_allocator, "/home/andy/dev/zig/build/lib/zig/std", "io.zig"), "/home/andy/dev/zig/build/lib/zig/std/io.zig"));
|
||||
testJoinPosix(
|
||||
[][]const u8{ "/home/andy/dev/zig/build/lib/zig/std", "io.zig" },
|
||||
"/home/andy/dev/zig/build/lib/zig/std/io.zig",
|
||||
);
|
||||
|
||||
testJoinPosix([][]const u8{ "a", "/c" }, "a/c");
|
||||
testJoinPosix([][]const u8{ "a/", "/c" }, "a/c");
|
||||
}
|
||||
|
||||
pub fn isAbsolute(path: []const u8) bool {
|
||||
|
@ -312,18 +375,8 @@ fn asciiEqlIgnoreCase(s1: []const u8, s2: []const u8) bool {
|
|||
return true;
|
||||
}
|
||||
|
||||
/// Converts the command line arguments into a slice and calls `resolveSlice`.
|
||||
pub fn resolve(allocator: *Allocator, args: ...) ![]u8 {
|
||||
var paths: [args.len][]const u8 = undefined;
|
||||
comptime var arg_i = 0;
|
||||
inline while (arg_i < args.len) : (arg_i += 1) {
|
||||
paths[arg_i] = args[arg_i];
|
||||
}
|
||||
return resolveSlice(allocator, paths);
|
||||
}
|
||||
|
||||
/// On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`.
|
||||
pub fn resolveSlice(allocator: *Allocator, paths: []const []const u8) ![]u8 {
|
||||
pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 {
|
||||
if (is_windows) {
|
||||
return resolveWindows(allocator, paths);
|
||||
} else {
|
||||
|
@ -602,7 +655,10 @@ test "os.path.resolveWindows" {
|
|||
const parsed_cwd = windowsParsePath(cwd);
|
||||
{
|
||||
const result = testResolveWindows([][]const u8{ "/usr/local", "lib\\zig\\std\\array_list.zig" });
|
||||
const expected = try join(debug.global_allocator, parsed_cwd.disk_designator, "usr\\local\\lib\\zig\\std\\array_list.zig");
|
||||
const expected = try join(debug.global_allocator, [][]const u8{
|
||||
parsed_cwd.disk_designator,
|
||||
"usr\\local\\lib\\zig\\std\\array_list.zig",
|
||||
});
|
||||
if (parsed_cwd.kind == WindowsPath.Kind.Drive) {
|
||||
expected[0] = asciiUpper(parsed_cwd.disk_designator[0]);
|
||||
}
|
||||
|
@ -610,7 +666,10 @@ test "os.path.resolveWindows" {
|
|||
}
|
||||
{
|
||||
const result = testResolveWindows([][]const u8{ "usr/local", "lib\\zig" });
|
||||
const expected = try join(debug.global_allocator, cwd, "usr\\local\\lib\\zig");
|
||||
const expected = try join(debug.global_allocator, [][]const u8{
|
||||
cwd,
|
||||
"usr\\local\\lib\\zig",
|
||||
});
|
||||
if (parsed_cwd.kind == WindowsPath.Kind.Drive) {
|
||||
expected[0] = asciiUpper(parsed_cwd.disk_designator[0]);
|
||||
}
|
||||
|
|
|
@ -105,3 +105,19 @@ test "AtomicFile" {
|
|||
|
||||
try os.deleteFile(test_out_file);
|
||||
}
|
||||
|
||||
test "thread local storage" {
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
const thread1 = try std.os.spawnThread({}, testTls);
|
||||
const thread2 = try std.os.spawnThread({}, testTls);
|
||||
testTls({});
|
||||
thread1.wait();
|
||||
thread2.wait();
|
||||
}
|
||||
|
||||
threadlocal var x: i32 = 1234;
|
||||
fn testTls(context: void) void {
|
||||
if (x != 1234) @panic("bad start value");
|
||||
x += 1;
|
||||
if (x != 1235) @panic("bad end value");
|
||||
}
|
||||
|
|
|
@ -49,7 +49,10 @@ pub const UNICODE = false;
|
|||
pub const WCHAR = u16;
|
||||
pub const WORD = u16;
|
||||
pub const LARGE_INTEGER = i64;
|
||||
pub const LONG = c_long;
|
||||
pub const ULONG = u32;
|
||||
pub const LONG = i32;
|
||||
pub const ULONGLONG = u64;
|
||||
pub const LONGLONG = i64;
|
||||
|
||||
pub const TRUE = 1;
|
||||
pub const FALSE = 0;
|
||||
|
@ -380,3 +383,17 @@ pub const COORD = extern struct {
|
|||
};
|
||||
|
||||
pub const CREATE_UNICODE_ENVIRONMENT = 1024;
|
||||
|
||||
pub const TLS_OUT_OF_INDEXES = 4294967295;
|
||||
pub const IMAGE_TLS_DIRECTORY = extern struct {
|
||||
StartAddressOfRawData: usize,
|
||||
EndAddressOfRawData: usize,
|
||||
AddressOfIndex: usize,
|
||||
AddressOfCallBacks: usize,
|
||||
SizeOfZeroFill: u32,
|
||||
Characteristics: u32,
|
||||
};
|
||||
pub const IMAGE_TLS_DIRECTORY64 = IMAGE_TLS_DIRECTORY;
|
||||
pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY;
|
||||
|
||||
pub const PIMAGE_TLS_CALLBACK = ?extern fn(PVOID, DWORD, PVOID) void;
|
||||
|
|
|
@ -164,6 +164,10 @@ pub extern "kernel32" stdcallcc fn Sleep(dwMilliseconds: DWORD) void;
|
|||
|
||||
pub extern "kernel32" stdcallcc fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) BOOL;
|
||||
|
||||
pub extern "kernel32" stdcallcc fn TlsAlloc() DWORD;
|
||||
|
||||
pub extern "kernel32" stdcallcc fn TlsFree(dwTlsIndex: DWORD) BOOL;
|
||||
|
||||
pub extern "kernel32" stdcallcc fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) DWORD;
|
||||
|
||||
pub extern "kernel32" stdcallcc fn WriteFile(
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
const std = @import("../../index.zig");
|
||||
|
||||
export var _tls_index: u32 = std.os.windows.TLS_OUT_OF_INDEXES;
|
||||
export var _tls_start: u8 linksection(".tls") = 0;
|
||||
export var _tls_end: u8 linksection(".tls$ZZZ") = 0;
|
||||
export var __xl_a: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLA") = null;
|
||||
export var __xl_z: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLZ") = null;
|
||||
|
||||
// TODO this is how I would like it to be expressed
|
||||
// TODO also note, ReactOS has a +1 on StartAddressOfRawData and AddressOfCallBacks. Investigate
|
||||
// why they do that.
|
||||
//export const _tls_used linksection(".rdata$T") = std.os.windows.IMAGE_TLS_DIRECTORY {
|
||||
// .StartAddressOfRawData = @ptrToInt(&_tls_start),
|
||||
// .EndAddressOfRawData = @ptrToInt(&_tls_end),
|
||||
// .AddressOfIndex = @ptrToInt(&_tls_index),
|
||||
// .AddressOfCallBacks = @ptrToInt(__xl_a),
|
||||
// .SizeOfZeroFill = 0,
|
||||
// .Characteristics = 0,
|
||||
//};
|
||||
// This is the workaround because we can't do @ptrToInt at comptime like that.
|
||||
pub const IMAGE_TLS_DIRECTORY = extern struct {
|
||||
StartAddressOfRawData: *c_void,
|
||||
EndAddressOfRawData: *c_void,
|
||||
AddressOfIndex: *c_void,
|
||||
AddressOfCallBacks: *c_void,
|
||||
SizeOfZeroFill: u32,
|
||||
Characteristics: u32,
|
||||
};
|
||||
export const _tls_used linksection(".rdata$T") = IMAGE_TLS_DIRECTORY {
|
||||
.StartAddressOfRawData = &_tls_start,
|
||||
.EndAddressOfRawData = &_tls_end,
|
||||
.AddressOfIndex = &_tls_index,
|
||||
.AddressOfCallBacks = &__xl_a,
|
||||
.SizeOfZeroFill = 0,
|
||||
.Characteristics = 0,
|
||||
};
|
|
@ -4,6 +4,7 @@
|
|||
const root = @import("@root");
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const assert = std.debug.assert;
|
||||
|
||||
var argc_ptr: [*]usize = undefined;
|
||||
|
||||
|
@ -44,7 +45,9 @@ nakedcc fn _start() noreturn {
|
|||
|
||||
extern fn WinMainCRTStartup() noreturn {
|
||||
@setAlignStack(16);
|
||||
|
||||
if (!builtin.single_threaded) {
|
||||
_ = @import("../os/windows/tls.zig");
|
||||
}
|
||||
std.os.windows.ExitProcess(callMain());
|
||||
}
|
||||
|
||||
|
@ -61,9 +64,23 @@ fn posixCallMainAndExit() noreturn {
|
|||
while (envp_optional[envp_count]) |_| : (envp_count += 1) {}
|
||||
const envp = @ptrCast([*][*]u8, envp_optional)[0..envp_count];
|
||||
if (builtin.os == builtin.Os.linux) {
|
||||
const auxv = @ptrCast([*]usize, envp.ptr + envp_count + 1);
|
||||
std.os.linux_elf_aux_maybe = @ptrCast([*]std.elf.Auxv, auxv);
|
||||
std.debug.assert(std.os.linuxGetAuxVal(std.elf.AT_PAGESZ) == std.os.page_size);
|
||||
// Scan auxiliary vector.
|
||||
const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1);
|
||||
std.os.linux_elf_aux_maybe = auxv;
|
||||
var i: usize = 0;
|
||||
var at_phdr: usize = 0;
|
||||
var at_phnum: usize = 0;
|
||||
var at_phent: usize = 0;
|
||||
while (auxv[i].a_un.a_val != 0) : (i += 1) {
|
||||
switch (auxv[i].a_type) {
|
||||
std.elf.AT_PAGESZ => assert(auxv[i].a_un.a_val == std.os.page_size),
|
||||
std.elf.AT_PHDR => at_phdr = auxv[i].a_un.a_val,
|
||||
std.elf.AT_PHNUM => at_phnum = auxv[i].a_un.a_val,
|
||||
std.elf.AT_PHENT => at_phent = auxv[i].a_un.a_val,
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
if (!builtin.single_threaded) linuxInitializeThreadLocalStorage(at_phdr, at_phnum, at_phent);
|
||||
}
|
||||
|
||||
std.os.posix.exit(callMainWithArgs(argc, argv, envp));
|
||||
|
@ -116,3 +133,41 @@ inline fn callMain() u8 {
|
|||
else => @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'"),
|
||||
}
|
||||
}
|
||||
|
||||
var tls_end_addr: usize = undefined;
|
||||
const main_thread_tls_align = 32;
|
||||
var main_thread_tls_bytes: [64]u8 align(main_thread_tls_align) = [1]u8{0} ** 64;
|
||||
|
||||
fn linuxInitializeThreadLocalStorage(at_phdr: usize, at_phnum: usize, at_phent: usize) void {
|
||||
var phdr_addr = at_phdr;
|
||||
var n = at_phnum;
|
||||
var base: usize = 0;
|
||||
while (n != 0) : ({n -= 1; phdr_addr += at_phent;}) {
|
||||
const phdr = @intToPtr(*std.elf.Phdr, phdr_addr);
|
||||
// TODO look for PT_DYNAMIC when we have https://github.com/ziglang/zig/issues/1917
|
||||
switch (phdr.p_type) {
|
||||
std.elf.PT_PHDR => base = at_phdr - phdr.p_vaddr,
|
||||
std.elf.PT_TLS => std.os.linux_tls_phdr = phdr,
|
||||
else => continue,
|
||||
}
|
||||
}
|
||||
const tls_phdr = std.os.linux_tls_phdr orelse return;
|
||||
std.os.linux_tls_img_src = @intToPtr([*]const u8, base + tls_phdr.p_vaddr);
|
||||
assert(main_thread_tls_bytes.len >= tls_phdr.p_memsz); // not enough preallocated Thread Local Storage
|
||||
assert(main_thread_tls_align >= tls_phdr.p_align); // preallocated Thread Local Storage not aligned enough
|
||||
@memcpy(&main_thread_tls_bytes, std.os.linux_tls_img_src, tls_phdr.p_filesz);
|
||||
tls_end_addr = @ptrToInt(&main_thread_tls_bytes) + tls_phdr.p_memsz;
|
||||
linuxSetThreadArea(@ptrToInt(&tls_end_addr));
|
||||
}
|
||||
|
||||
fn linuxSetThreadArea(addr: usize) void {
|
||||
switch (builtin.arch) {
|
||||
builtin.Arch.x86_64 => {
|
||||
const ARCH_SET_FS = 0x1002;
|
||||
const rc = std.os.linux.syscall2(std.os.linux.SYS_arch_prctl, ARCH_SET_FS, addr);
|
||||
// acrh_prctl is documented to never fail
|
||||
assert(rc == 0);
|
||||
},
|
||||
else => @compileError("Unsupported architecture"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,9 +27,9 @@ pub fn main() !void {
|
|||
std.debug.warn("Expected second argument to be cache root directory path\n");
|
||||
return error.InvalidArgs;
|
||||
});
|
||||
const zig_exe = try os.path.resolve(a, zig_exe_rel);
|
||||
const zig_exe = try os.path.resolve(a, [][]const u8{zig_exe_rel});
|
||||
|
||||
const dir_path = try os.path.join(a, cache_root, "clitest");
|
||||
const dir_path = try os.path.join(a, [][]const u8{ cache_root, "clitest" });
|
||||
const TestFn = fn ([]const u8, []const u8) anyerror!void;
|
||||
const test_fns = []TestFn{
|
||||
testZigInitLib,
|
||||
|
@ -99,8 +99,8 @@ fn testZigInitExe(zig_exe: []const u8, dir_path: []const u8) !void {
|
|||
fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void {
|
||||
if (builtin.os != builtin.Os.linux or builtin.arch != builtin.Arch.x86_64) return;
|
||||
|
||||
const example_zig_path = try os.path.join(a, dir_path, "example.zig");
|
||||
const example_s_path = try os.path.join(a, dir_path, "example.s");
|
||||
const example_zig_path = try os.path.join(a, [][]const u8{ dir_path, "example.zig" });
|
||||
const example_s_path = try os.path.join(a, [][]const u8{ dir_path, "example.s" });
|
||||
|
||||
try std.io.writeFile(example_zig_path,
|
||||
\\// Type your code here, or load an example.
|
||||
|
|
|
@ -1,6 +1,25 @@
|
|||
const tests = @import("tests.zig");
|
||||
|
||||
pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
cases.add(
|
||||
"threadlocal qualifier on const",
|
||||
\\threadlocal const x: i32 = 1234;
|
||||
\\export fn entry() i32 {
|
||||
\\ return x;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:1:13: error: threadlocal variable cannot be constant",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
"threadlocal qualifier on local variable",
|
||||
\\export fn entry() void {
|
||||
\\ threadlocal var x: i32 = 1234;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:2:5: error: function-local variable 'x' cannot be threadlocal",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
"@bitCast same size but bit count mismatch",
|
||||
\\export fn entry(byte: u8) void {
|
||||
|
|
|
@ -685,3 +685,11 @@ test "fn call returning scalar optional in equality expression" {
|
|||
fn getNull() ?*i32 {
|
||||
return null;
|
||||
}
|
||||
|
||||
test "thread local variable" {
|
||||
const S = struct {
|
||||
threadlocal var t: i32 = 1234;
|
||||
};
|
||||
S.t += 1;
|
||||
assertOrPanic(S.t == 1235);
|
||||
}
|
||||
|
|
|
@ -1,20 +1,17 @@
|
|||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const assertOrPanic = std.debug.assertOrPanic;
|
||||
|
||||
test "implicit array to vector and vector to array" {
|
||||
test "vector wrap operators" {
|
||||
const S = struct {
|
||||
fn doTheTest() void {
|
||||
var v: @Vector(4, i32) = [4]i32{10, 20, 30, 40};
|
||||
const x: @Vector(4, i32) = [4]i32{1, 2, 3, 4};
|
||||
v +%= x;
|
||||
const result: [4]i32 = v;
|
||||
assertOrPanic(result[0] == 11);
|
||||
assertOrPanic(result[1] == 22);
|
||||
assertOrPanic(result[2] == 33);
|
||||
assertOrPanic(result[3] == 44);
|
||||
const v: @Vector(4, i32) = [4]i32{ 10, 20, 30, 40 };
|
||||
const x: @Vector(4, i32) = [4]i32{ 1, 2, 3, 4 };
|
||||
assertOrPanic(mem.eql(i32, ([4]i32)(v +% x), [4]i32{ 11, 22, 33, 44 }));
|
||||
assertOrPanic(mem.eql(i32, ([4]i32)(v -% x), [4]i32{ 9, 18, 27, 36 }));
|
||||
assertOrPanic(mem.eql(i32, ([4]i32)(v *% x), [4]i32{ 10, 40, 90, 160 }));
|
||||
}
|
||||
};
|
||||
S.doTheTest();
|
||||
comptime S.doTheTest();
|
||||
}
|
||||
|
||||
|
|
|
@ -194,6 +194,9 @@ pub fn addPkgTests(b: *build.Builder, test_filter: ?[]const u8, root_src: []cons
|
|||
if (link_libc) {
|
||||
these_tests.linkSystemLibrary("c");
|
||||
}
|
||||
if (mem.eql(u8, name, "std")) {
|
||||
these_tests.overrideStdDir("std");
|
||||
}
|
||||
step.dependOn(&these_tests.step);
|
||||
}
|
||||
}
|
||||
|
@ -436,7 +439,10 @@ pub const CompareOutputContext = struct {
|
|||
pub fn addCase(self: *CompareOutputContext, case: TestCase) void {
|
||||
const b = self.b;
|
||||
|
||||
const root_src = os.path.join(b.allocator, b.cache_root, case.sources.items[0].filename) catch unreachable;
|
||||
const root_src = os.path.join(
|
||||
b.allocator,
|
||||
[][]const u8{ b.cache_root, case.sources.items[0].filename },
|
||||
) catch unreachable;
|
||||
|
||||
switch (case.special) {
|
||||
Special.Asm => {
|
||||
|
@ -449,7 +455,10 @@ pub const CompareOutputContext = struct {
|
|||
exe.addAssemblyFile(root_src);
|
||||
|
||||
for (case.sources.toSliceConst()) |src_file| {
|
||||
const expanded_src_path = os.path.join(b.allocator, b.cache_root, src_file.filename) catch unreachable;
|
||||
const expanded_src_path = os.path.join(
|
||||
b.allocator,
|
||||
[][]const u8{ b.cache_root, src_file.filename },
|
||||
) catch unreachable;
|
||||
const write_src = b.addWriteFile(expanded_src_path, src_file.source);
|
||||
exe.step.dependOn(&write_src.step);
|
||||
}
|
||||
|
@ -473,7 +482,10 @@ pub const CompareOutputContext = struct {
|
|||
}
|
||||
|
||||
for (case.sources.toSliceConst()) |src_file| {
|
||||
const expanded_src_path = os.path.join(b.allocator, b.cache_root, src_file.filename) catch unreachable;
|
||||
const expanded_src_path = os.path.join(
|
||||
b.allocator,
|
||||
[][]const u8{ b.cache_root, src_file.filename },
|
||||
) catch unreachable;
|
||||
const write_src = b.addWriteFile(expanded_src_path, src_file.source);
|
||||
exe.step.dependOn(&write_src.step);
|
||||
}
|
||||
|
@ -496,7 +508,10 @@ pub const CompareOutputContext = struct {
|
|||
}
|
||||
|
||||
for (case.sources.toSliceConst()) |src_file| {
|
||||
const expanded_src_path = os.path.join(b.allocator, b.cache_root, src_file.filename) catch unreachable;
|
||||
const expanded_src_path = os.path.join(
|
||||
b.allocator,
|
||||
[][]const u8{ b.cache_root, src_file.filename },
|
||||
) catch unreachable;
|
||||
const write_src = b.addWriteFile(expanded_src_path, src_file.source);
|
||||
exe.step.dependOn(&write_src.step);
|
||||
}
|
||||
|
@ -569,8 +584,14 @@ pub const CompileErrorContext = struct {
|
|||
const self = @fieldParentPtr(CompileCmpOutputStep, "step", step);
|
||||
const b = self.context.b;
|
||||
|
||||
const root_src = os.path.join(b.allocator, b.cache_root, self.case.sources.items[0].filename) catch unreachable;
|
||||
const obj_path = os.path.join(b.allocator, b.cache_root, "test.o") catch unreachable;
|
||||
const root_src = os.path.join(
|
||||
b.allocator,
|
||||
[][]const u8{ b.cache_root, self.case.sources.items[0].filename },
|
||||
) catch unreachable;
|
||||
const obj_path = os.path.join(
|
||||
b.allocator,
|
||||
[][]const u8{ b.cache_root, "test.o" },
|
||||
) catch unreachable;
|
||||
|
||||
var zig_args = ArrayList([]const u8).init(b.allocator);
|
||||
zig_args.append(b.zig_exe) catch unreachable;
|
||||
|
@ -718,7 +739,10 @@ pub const CompileErrorContext = struct {
|
|||
self.step.dependOn(&compile_and_cmp_errors.step);
|
||||
|
||||
for (case.sources.toSliceConst()) |src_file| {
|
||||
const expanded_src_path = os.path.join(b.allocator, b.cache_root, src_file.filename) catch unreachable;
|
||||
const expanded_src_path = os.path.join(
|
||||
b.allocator,
|
||||
[][]const u8{ b.cache_root, src_file.filename },
|
||||
) catch unreachable;
|
||||
const write_src = b.addWriteFile(expanded_src_path, src_file.source);
|
||||
compile_and_cmp_errors.step.dependOn(&write_src.step);
|
||||
}
|
||||
|
@ -849,7 +873,10 @@ pub const TranslateCContext = struct {
|
|||
const self = @fieldParentPtr(TranslateCCmpOutputStep, "step", step);
|
||||
const b = self.context.b;
|
||||
|
||||
const root_src = os.path.join(b.allocator, b.cache_root, self.case.sources.items[0].filename) catch unreachable;
|
||||
const root_src = os.path.join(
|
||||
b.allocator,
|
||||
[][]const u8{ b.cache_root, self.case.sources.items[0].filename },
|
||||
) catch unreachable;
|
||||
|
||||
var zig_args = ArrayList([]const u8).init(b.allocator);
|
||||
zig_args.append(b.zig_exe) catch unreachable;
|
||||
|
@ -983,7 +1010,10 @@ pub const TranslateCContext = struct {
|
|||
self.step.dependOn(&translate_c_and_cmp.step);
|
||||
|
||||
for (case.sources.toSliceConst()) |src_file| {
|
||||
const expanded_src_path = os.path.join(b.allocator, b.cache_root, src_file.filename) catch unreachable;
|
||||
const expanded_src_path = os.path.join(
|
||||
b.allocator,
|
||||
[][]const u8{ b.cache_root, src_file.filename },
|
||||
) catch unreachable;
|
||||
const write_src = b.addWriteFile(expanded_src_path, src_file.source);
|
||||
translate_c_and_cmp.step.dependOn(&write_src.step);
|
||||
}
|
||||
|
@ -1098,7 +1128,10 @@ pub const GenHContext = struct {
|
|||
|
||||
pub fn addCase(self: *GenHContext, case: *const TestCase) void {
|
||||
const b = self.b;
|
||||
const root_src = os.path.join(b.allocator, b.cache_root, case.sources.items[0].filename) catch unreachable;
|
||||
const root_src = os.path.join(
|
||||
b.allocator,
|
||||
[][]const u8{ b.cache_root, case.sources.items[0].filename },
|
||||
) catch unreachable;
|
||||
|
||||
const mode = builtin.Mode.Debug;
|
||||
const annotated_case_name = fmt.allocPrint(self.b.allocator, "gen-h {} ({})", case.name, @tagName(mode)) catch unreachable;
|
||||
|
@ -1110,7 +1143,10 @@ pub const GenHContext = struct {
|
|||
obj.setBuildMode(mode);
|
||||
|
||||
for (case.sources.toSliceConst()) |src_file| {
|
||||
const expanded_src_path = os.path.join(b.allocator, b.cache_root, src_file.filename) catch unreachable;
|
||||
const expanded_src_path = os.path.join(
|
||||
b.allocator,
|
||||
[][]const u8{ b.cache_root, src_file.filename },
|
||||
) catch unreachable;
|
||||
const write_src = b.addWriteFile(expanded_src_path, src_file.source);
|
||||
obj.step.dependOn(&write_src.step);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue