improvements for windows and libc integration
* standard library knows if it is linking against libc and will sometimes call libc functions in that case instead of providing redundant definitions * fix infinite loop bug when resolving use declarations * allow calling the same C function from different C imports. closes #277 * push more logic from compiler to std/bootstrap.zig * standard library provides way to access errno closes #274 * fix compile error in standard library for windows * add implementation of getRandomBytes for windows
This commit is contained in:
parent
01b2bf4a44
commit
d6856859d3
@ -204,6 +204,10 @@ install(FILES ${C_HEADERS} DESTINATION ${C_HEADERS_DEST})
|
|||||||
install(FILES "${CMAKE_SOURCE_DIR}/std/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}")
|
install(FILES "${CMAKE_SOURCE_DIR}/std/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||||
install(FILES "${CMAKE_SOURCE_DIR}/std/build.zig" DESTINATION "${ZIG_STD_DEST}")
|
install(FILES "${CMAKE_SOURCE_DIR}/std/build.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||||
install(FILES "${CMAKE_SOURCE_DIR}/std/builtin.zig" DESTINATION "${ZIG_STD_DEST}")
|
install(FILES "${CMAKE_SOURCE_DIR}/std/builtin.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||||
|
install(FILES "${CMAKE_SOURCE_DIR}/std/c/darwin.zig" DESTINATION "${ZIG_STD_DEST}/c")
|
||||||
|
install(FILES "${CMAKE_SOURCE_DIR}/std/c/index.zig" DESTINATION "${ZIG_STD_DEST}/c")
|
||||||
|
install(FILES "${CMAKE_SOURCE_DIR}/std/c/linux.zig" DESTINATION "${ZIG_STD_DEST}/c")
|
||||||
|
install(FILES "${CMAKE_SOURCE_DIR}/std/c/windows.zig" DESTINATION "${ZIG_STD_DEST}/c")
|
||||||
install(FILES "${CMAKE_SOURCE_DIR}/std/compiler_rt.zig" DESTINATION "${ZIG_STD_DEST}")
|
install(FILES "${CMAKE_SOURCE_DIR}/std/compiler_rt.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||||
install(FILES "${CMAKE_SOURCE_DIR}/std/cstr.zig" DESTINATION "${ZIG_STD_DEST}")
|
install(FILES "${CMAKE_SOURCE_DIR}/std/cstr.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||||
install(FILES "${CMAKE_SOURCE_DIR}/std/darwin.zig" DESTINATION "${ZIG_STD_DEST}")
|
install(FILES "${CMAKE_SOURCE_DIR}/std/darwin.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||||
@ -231,6 +235,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}")
|
|||||||
install(FILES "${CMAKE_SOURCE_DIR}/std/rand_test.zig" DESTINATION "${ZIG_STD_DEST}")
|
install(FILES "${CMAKE_SOURCE_DIR}/std/rand_test.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||||
install(FILES "${CMAKE_SOURCE_DIR}/std/sort.zig" DESTINATION "${ZIG_STD_DEST}")
|
install(FILES "${CMAKE_SOURCE_DIR}/std/sort.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||||
install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner.zig" DESTINATION "${ZIG_STD_DEST}")
|
install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||||
|
install(FILES "${CMAKE_SOURCE_DIR}/std/windows.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||||
|
|
||||||
add_executable(run_tests ${TEST_SOURCES})
|
add_executable(run_tests ${TEST_SOURCES})
|
||||||
target_link_libraries(run_tests)
|
target_link_libraries(run_tests)
|
||||||
|
@ -246,6 +246,7 @@ enum TldId {
|
|||||||
|
|
||||||
enum TldResolution {
|
enum TldResolution {
|
||||||
TldResolutionUnresolved,
|
TldResolutionUnresolved,
|
||||||
|
TldResolutionResolving,
|
||||||
TldResolutionInvalid,
|
TldResolutionInvalid,
|
||||||
TldResolutionOk,
|
TldResolutionOk,
|
||||||
};
|
};
|
||||||
|
@ -2423,8 +2423,8 @@ Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) {
|
|||||||
AstNode *use_decl_node = import->use_decls.at(i);
|
AstNode *use_decl_node = import->use_decls.at(i);
|
||||||
if (use_decl_node->data.use.resolution == TldResolutionUnresolved) {
|
if (use_decl_node->data.use.resolution == TldResolutionUnresolved) {
|
||||||
preview_use_decl(g, use_decl_node);
|
preview_use_decl(g, use_decl_node);
|
||||||
|
resolve_use_decl(g, use_decl_node);
|
||||||
}
|
}
|
||||||
resolve_use_decl(g, use_decl_node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (scope) {
|
while (scope) {
|
||||||
@ -2795,14 +2795,18 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *
|
|||||||
void resolve_use_decl(CodeGen *g, AstNode *node) {
|
void resolve_use_decl(CodeGen *g, AstNode *node) {
|
||||||
assert(node->type == NodeTypeUse);
|
assert(node->type == NodeTypeUse);
|
||||||
|
|
||||||
if (node->data.use.resolution != TldResolutionUnresolved)
|
if (node->data.use.resolution == TldResolutionOk ||
|
||||||
|
node->data.use.resolution == TldResolutionInvalid)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
add_symbols_from_import(g, node, node);
|
add_symbols_from_import(g, node, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
void preview_use_decl(CodeGen *g, AstNode *node) {
|
void preview_use_decl(CodeGen *g, AstNode *node) {
|
||||||
assert(node->type == NodeTypeUse);
|
assert(node->type == NodeTypeUse);
|
||||||
|
|
||||||
|
node->data.use.resolution = TldResolutionResolving;
|
||||||
IrInstruction *result = analyze_const_value(g, &node->owner->decls_scope->base,
|
IrInstruction *result = analyze_const_value(g, &node->owner->decls_scope->base,
|
||||||
node->data.use.expr, g->builtin_types.entry_namespace, nullptr);
|
node->data.use.expr, g->builtin_types.entry_namespace, nullptr);
|
||||||
|
|
||||||
|
@ -272,7 +272,17 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TypeTableEntry *fn_type = fn_table_entry->type_entry;
|
TypeTableEntry *fn_type = fn_table_entry->type_entry;
|
||||||
fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_type->data.fn.raw_type_ref);
|
LLVMTypeRef fn_llvm_type = fn_type->data.fn.raw_type_ref;
|
||||||
|
if (!fn_table_entry->internal_linkage && fn_table_entry->body_node == nullptr) {
|
||||||
|
LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name));
|
||||||
|
if (existing_llvm_fn) {
|
||||||
|
fn_table_entry->llvm_value = LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0));
|
||||||
|
} else {
|
||||||
|
fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
|
||||||
|
}
|
||||||
|
|
||||||
switch (fn_table_entry->fn_inline) {
|
switch (fn_table_entry->fn_inline) {
|
||||||
case FnInlineAlways:
|
case FnInlineAlways:
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
const root = @import("@root");
|
const root = @import("@root");
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
const want_main_symbol = std.build.linkingLibrary("c");
|
const want_main_symbol = std.build.linking_libc;
|
||||||
const want_start_symbol = !want_main_symbol;
|
const want_start_symbol = !want_main_symbol;
|
||||||
|
|
||||||
const exit = switch(@compileVar("os")) {
|
const exit = switch(@compileVar("os")) {
|
||||||
@ -18,6 +18,9 @@ var argv: &&u8 = undefined;
|
|||||||
|
|
||||||
export nakedcc fn _start() -> unreachable {
|
export nakedcc fn _start() -> unreachable {
|
||||||
@setFnVisible(this, want_start_symbol);
|
@setFnVisible(this, want_start_symbol);
|
||||||
|
if (!want_start_symbol) {
|
||||||
|
@unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
switch (@compileVar("arch")) {
|
switch (@compileVar("arch")) {
|
||||||
Arch.x86_64 => {
|
Arch.x86_64 => {
|
||||||
@ -49,6 +52,9 @@ fn callMainAndExit() -> unreachable {
|
|||||||
|
|
||||||
export fn main(c_argc: i32, c_argv: &&u8) -> i32 {
|
export fn main(c_argc: i32, c_argv: &&u8) -> i32 {
|
||||||
@setFnVisible(this, want_main_symbol);
|
@setFnVisible(this, want_main_symbol);
|
||||||
|
if (!want_main_symbol) {
|
||||||
|
@unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
argc = usize(c_argc);
|
argc = usize(c_argc);
|
||||||
argv = c_argv;
|
argv = c_argv;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
const mem = @import("mem.zig");
|
const mem = @import("mem.zig");
|
||||||
|
|
||||||
|
pub const linking_libc = linkingLibrary("c");
|
||||||
|
|
||||||
pub fn linkingLibrary(lib_name: []const u8) -> bool {
|
pub fn linkingLibrary(lib_name: []const u8) -> bool {
|
||||||
// TODO shouldn't need this if
|
// TODO shouldn't need this if
|
||||||
if (@compileVar("link_libs").len != 0) {
|
if (@compileVar("link_libs").len != 0) {
|
||||||
|
4
std/c/darwin.zig
Normal file
4
std/c/darwin.zig
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
pub extern fn getrandom(buf_ptr: &u8, buf_len: usize) -> c_int;
|
||||||
|
|
||||||
|
extern fn __error() -> &c_int;
|
||||||
|
pub const _errno = __error;
|
13
std/c/index.zig
Normal file
13
std/c/index.zig
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
pub use @import("errno.zig");
|
||||||
|
|
||||||
|
pub use switch(@compileVar("os")) {
|
||||||
|
Os.linux => @import("c/linux.zig"),
|
||||||
|
Os.windows => @import("c/windows.zig"),
|
||||||
|
Os.darwin, Os.macosx, Os.ios => @import("c/darwin.zig"),
|
||||||
|
else => empty_import,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub extern fn abort() -> unreachable;
|
||||||
|
|
||||||
|
|
||||||
|
const empty_import = @import("empty.zig");
|
4
std/c/linux.zig
Normal file
4
std/c/linux.zig
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
pub extern fn getrandom(buf_ptr: &u8, buf_len: usize, flags: c_uint) -> c_int;
|
||||||
|
|
||||||
|
extern fn __errno_location() -> &c_int;
|
||||||
|
pub const _errno = __errno_location;
|
1
std/c/windows.zig
Normal file
1
std/c/windows.zig
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub extern fn _errno() -> &c_int;
|
@ -78,13 +78,13 @@ pub fn writeStackTrace(out_stream: &io.OutStream) -> %void {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
ObjectFormat.coff => {
|
ObjectFormat.coff => {
|
||||||
out_stream.write("(stack trace unavailable for COFF object format)\n");
|
%return out_stream.write("(stack trace unavailable for COFF object format)\n");
|
||||||
},
|
},
|
||||||
ObjectFormat.macho => {
|
ObjectFormat.macho => {
|
||||||
%return out_stream.write("(stack trace unavailable for Mach-O object format)\n");
|
%return out_stream.write("(stack trace unavailable for Mach-O object format)\n");
|
||||||
},
|
},
|
||||||
ObjectFormat.unknown => {
|
ObjectFormat.unknown => {
|
||||||
out_stream.write("(stack trace unavailable for unknown object format)\n");
|
%return out_stream.write("(stack trace unavailable for unknown object format)\n");
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
57
std/os.zig
57
std/os.zig
@ -1,20 +1,49 @@
|
|||||||
const system = switch(@compileVar("os")) {
|
const posix = switch(@compileVar("os")) {
|
||||||
Os.linux => @import("linux.zig"),
|
Os.linux => @import("linux.zig"),
|
||||||
Os.darwin => @import("darwin.zig"),
|
Os.darwin, Os.macosx, Os.ios => @import("darwin.zig"),
|
||||||
else => @compileError("Unsupported OS"),
|
else => @compileError("Unsupported OS"),
|
||||||
};
|
};
|
||||||
|
const windows = @import("windows.zig");
|
||||||
const errno = @import("errno.zig");
|
const errno = @import("errno.zig");
|
||||||
|
const linking_libc = @import("build.zig").linking_libc;
|
||||||
|
const c = @import("c/index.zig");
|
||||||
|
|
||||||
error Unexpected;
|
error Unexpected;
|
||||||
|
|
||||||
|
/// Fills `buf` with random bytes. If linking against libc, this calls the
|
||||||
|
/// appropriate OS-specific library call. Otherwise it uses the zig standard
|
||||||
|
/// library implementation.
|
||||||
pub fn getRandomBytes(buf: []u8) -> %void {
|
pub fn getRandomBytes(buf: []u8) -> %void {
|
||||||
while (true) {
|
while (true) {
|
||||||
const ret = switch (@compileVar("os")) {
|
const err = switch (@compileVar("os")) {
|
||||||
Os.linux => system.getrandom(buf.ptr, buf.len, 0),
|
Os.linux => {
|
||||||
Os.darwin => system.getrandom(buf.ptr, buf.len),
|
if (linking_libc) {
|
||||||
else => @compileError("unsupported os"),
|
if (c.getrandom(buf.ptr, buf.len, 0) == -1) *c._errno() else 0
|
||||||
|
} else {
|
||||||
|
posix.getErrno(posix.getrandom(buf.ptr, buf.len, 0))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Os.darwin, Os.macosx, Os.ios => {
|
||||||
|
if (linking_libc) {
|
||||||
|
if (posix.getrandom(buf.ptr, buf.len) == -1) *c._errno() else 0
|
||||||
|
} else {
|
||||||
|
posix.getErrno(posix.getrandom(buf.ptr, buf.len))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Os.windows => {
|
||||||
|
var hCryptProv: windows.HCRYPTPROV = undefined;
|
||||||
|
if (!windows.CryptAcquireContext(&hCryptProv, null, null, windows.PROV_RSA_FULL, 0)) {
|
||||||
|
return error.Unexpected;
|
||||||
|
}
|
||||||
|
defer _ = windows.CryptReleaseContext(hCryptProv, 0);
|
||||||
|
|
||||||
|
if (!windows.CryptGenRandom(hCryptProv, windows.DWORD(buf.len), buf.ptr)) {
|
||||||
|
return error.Unexpected;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
else => @compileError("Unsupported OS"),
|
||||||
};
|
};
|
||||||
const err = system.getErrno(ret);
|
|
||||||
if (err > 0) {
|
if (err > 0) {
|
||||||
return switch (err) {
|
return switch (err) {
|
||||||
errno.EINVAL => @unreachable(),
|
errno.EINVAL => @unreachable(),
|
||||||
@ -27,13 +56,19 @@ pub fn getRandomBytes(buf: []u8) -> %void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Raises a signal in the current kernel thread, ending its execution.
|
||||||
|
/// If linking against libc, this calls the abort() libc function. Otherwise
|
||||||
|
/// it uses the zig standard library implementation.
|
||||||
pub coldcc fn abort() -> unreachable {
|
pub coldcc fn abort() -> unreachable {
|
||||||
|
if (linking_libc) {
|
||||||
|
c.abort();
|
||||||
|
}
|
||||||
switch (@compileVar("os")) {
|
switch (@compileVar("os")) {
|
||||||
Os.linux, Os.darwin => {
|
Os.linux => {
|
||||||
_ = system.raise(system.SIGABRT);
|
_ = posix.raise(posix.SIGABRT);
|
||||||
_ = system.raise(system.SIGKILL);
|
_ = posix.raise(posix.SIGKILL);
|
||||||
while (true) {}
|
while (true) {}
|
||||||
},
|
},
|
||||||
else => @compileError("unsupported os"),
|
else => @compileError("Unsupported OS"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
17
std/windows.zig
Normal file
17
std/windows.zig
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
pub extern fn CryptAcquireContext(phProv: &HCRYPTPROV, pszContainer: LPCTSTR,
|
||||||
|
pszProvider: LPCTSTR, dwProvType: DWORD, dwFlags: DWORD) -> bool;
|
||||||
|
|
||||||
|
pub extern fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> bool;
|
||||||
|
|
||||||
|
pub extern fn CryptGenRandom(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: &BYTE) -> bool;
|
||||||
|
|
||||||
|
pub const PROV_RSA_FULL = 1;
|
||||||
|
|
||||||
|
|
||||||
|
pub const BYTE = u8;
|
||||||
|
pub const DWORD = u32;
|
||||||
|
// TODO something about unicode WCHAR vs char
|
||||||
|
pub const TCHAR = u8;
|
||||||
|
pub const LPCTSTR = ?&const TCHAR;
|
||||||
|
pub const ULONG_PTR = usize;
|
||||||
|
pub const HCRYPTPROV = ULONG_PTR;
|
Loading…
x
Reference in New Issue
Block a user