authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-03-23 02:59:58-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-03-23 02:59:58-04:00
logd6856859d3082d9b66aac7c25ceb2abcd13e2f7c
treedacade36cf18d88b1c21414130b33da91d7f7784
parent01b2bf4a44c586f2fa51e8824be608b92d82fed4

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

13 files changed, 119 insertions(+), 17 deletions(-)

CMakeLists.txt+5
...@@ -204,6 +204,10 @@ install(FILES ${C_HEADERS} DESTINATION ${C_HEADERS_DEST})...@@ -204,6 +204,10 @@ install(FILES ${C_HEADERS} DESTINATION ${C_HEADERS_DEST})
204install(FILES "${CMAKE_SOURCE_DIR}/std/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}")204install(FILES "${CMAKE_SOURCE_DIR}/std/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}")
205install(FILES "${CMAKE_SOURCE_DIR}/std/build.zig" DESTINATION "${ZIG_STD_DEST}")205install(FILES "${CMAKE_SOURCE_DIR}/std/build.zig" DESTINATION "${ZIG_STD_DEST}")
206install(FILES "${CMAKE_SOURCE_DIR}/std/builtin.zig" DESTINATION "${ZIG_STD_DEST}")206install(FILES "${CMAKE_SOURCE_DIR}/std/builtin.zig" DESTINATION "${ZIG_STD_DEST}")
207install(FILES "${CMAKE_SOURCE_DIR}/std/c/darwin.zig" DESTINATION "${ZIG_STD_DEST}/c")
208install(FILES "${CMAKE_SOURCE_DIR}/std/c/index.zig" DESTINATION "${ZIG_STD_DEST}/c")
209install(FILES "${CMAKE_SOURCE_DIR}/std/c/linux.zig" DESTINATION "${ZIG_STD_DEST}/c")
210install(FILES "${CMAKE_SOURCE_DIR}/std/c/windows.zig" DESTINATION "${ZIG_STD_DEST}/c")
207install(FILES "${CMAKE_SOURCE_DIR}/std/compiler_rt.zig" DESTINATION "${ZIG_STD_DEST}")211install(FILES "${CMAKE_SOURCE_DIR}/std/compiler_rt.zig" DESTINATION "${ZIG_STD_DEST}")
208install(FILES "${CMAKE_SOURCE_DIR}/std/cstr.zig" DESTINATION "${ZIG_STD_DEST}")212install(FILES "${CMAKE_SOURCE_DIR}/std/cstr.zig" DESTINATION "${ZIG_STD_DEST}")
209install(FILES "${CMAKE_SOURCE_DIR}/std/darwin.zig" DESTINATION "${ZIG_STD_DEST}")213install(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}")...@@ -231,6 +235,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}")
231install(FILES "${CMAKE_SOURCE_DIR}/std/rand_test.zig" DESTINATION "${ZIG_STD_DEST}")235install(FILES "${CMAKE_SOURCE_DIR}/std/rand_test.zig" DESTINATION "${ZIG_STD_DEST}")
232install(FILES "${CMAKE_SOURCE_DIR}/std/sort.zig" DESTINATION "${ZIG_STD_DEST}")236install(FILES "${CMAKE_SOURCE_DIR}/std/sort.zig" DESTINATION "${ZIG_STD_DEST}")
233install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner.zig" DESTINATION "${ZIG_STD_DEST}")237install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner.zig" DESTINATION "${ZIG_STD_DEST}")
238install(FILES "${CMAKE_SOURCE_DIR}/std/windows.zig" DESTINATION "${ZIG_STD_DEST}")
234239
235add_executable(run_tests ${TEST_SOURCES})240add_executable(run_tests ${TEST_SOURCES})
236target_link_libraries(run_tests)241target_link_libraries(run_tests)
src/all_types.hpp+1
...@@ -246,6 +246,7 @@ enum TldId {...@@ -246,6 +246,7 @@ enum TldId {
246246
247enum TldResolution {247enum TldResolution {
248 TldResolutionUnresolved,248 TldResolutionUnresolved,
249 TldResolutionResolving,
249 TldResolutionInvalid,250 TldResolutionInvalid,
250 TldResolutionOk,251 TldResolutionOk,
251};252};
src/analyze.cpp+6-2
...@@ -2423,8 +2423,8 @@ Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) {...@@ -2423,8 +2423,8 @@ Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) {
2423 AstNode *use_decl_node = import->use_decls.at(i);2423 AstNode *use_decl_node = import->use_decls.at(i);
2424 if (use_decl_node->data.use.resolution == TldResolutionUnresolved) {2424 if (use_decl_node->data.use.resolution == TldResolutionUnresolved) {
2425 preview_use_decl(g, use_decl_node);2425 preview_use_decl(g, use_decl_node);
2426 resolve_use_decl(g, use_decl_node);
2426 }2427 }
2427 resolve_use_decl(g, use_decl_node);
2428 }2428 }
24292429
2430 while (scope) {2430 while (scope) {
...@@ -2795,14 +2795,18 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *...@@ -2795,14 +2795,18 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *
2795void resolve_use_decl(CodeGen *g, AstNode *node) {2795void resolve_use_decl(CodeGen *g, AstNode *node) {
2796 assert(node->type == NodeTypeUse);2796 assert(node->type == NodeTypeUse);
27972797
2798 if (node->data.use.resolution != TldResolutionUnresolved)2798 if (node->data.use.resolution == TldResolutionOk ||
2799 node->data.use.resolution == TldResolutionInvalid)
2800 {
2799 return;2801 return;
2802 }
2800 add_symbols_from_import(g, node, node);2803 add_symbols_from_import(g, node, node);
2801}2804}
28022805
2803void preview_use_decl(CodeGen *g, AstNode *node) {2806void preview_use_decl(CodeGen *g, AstNode *node) {
2804 assert(node->type == NodeTypeUse);2807 assert(node->type == NodeTypeUse);
28052808
2809 node->data.use.resolution = TldResolutionResolving;
2806 IrInstruction *result = analyze_const_value(g, &node->owner->decls_scope->base,2810 IrInstruction *result = analyze_const_value(g, &node->owner->decls_scope->base,
2807 node->data.use.expr, g->builtin_types.entry_namespace, nullptr);2811 node->data.use.expr, g->builtin_types.entry_namespace, nullptr);
28082812
src/codegen.cpp+11-1
...@@ -272,7 +272,17 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {...@@ -272,7 +272,17 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
272 }272 }
273273
274 TypeTableEntry *fn_type = fn_table_entry->type_entry;274 TypeTableEntry *fn_type = fn_table_entry->type_entry;
275 fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_type->data.fn.raw_type_ref);275 LLVMTypeRef fn_llvm_type = fn_type->data.fn.raw_type_ref;
276 if (!fn_table_entry->internal_linkage && fn_table_entry->body_node == nullptr) {
277 LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name));
278 if (existing_llvm_fn) {
279 fn_table_entry->llvm_value = LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0));
280 } else {
281 fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
282 }
283 } else {
284 fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
285 }
276286
277 switch (fn_table_entry->fn_inline) {287 switch (fn_table_entry->fn_inline) {
278 case FnInlineAlways:288 case FnInlineAlways:
std/bootstrap.zig+7-1
...@@ -4,7 +4,7 @@...@@ -4,7 +4,7 @@
4const root = @import("@root");4const root = @import("@root");
5const std = @import("std");5const std = @import("std");
66
7const want_main_symbol = std.build.linkingLibrary("c");7const want_main_symbol = std.build.linking_libc;
8const want_start_symbol = !want_main_symbol;8const want_start_symbol = !want_main_symbol;
99
10const exit = switch(@compileVar("os")) {10const exit = switch(@compileVar("os")) {
...@@ -18,6 +18,9 @@ var argv: &&u8 = undefined;...@@ -18,6 +18,9 @@ var argv: &&u8 = undefined;
1818
19export nakedcc fn _start() -> unreachable {19export nakedcc fn _start() -> unreachable {
20 @setFnVisible(this, want_start_symbol);20 @setFnVisible(this, want_start_symbol);
21 if (!want_start_symbol) {
22 @unreachable();
23 }
2124
22 switch (@compileVar("arch")) {25 switch (@compileVar("arch")) {
23 Arch.x86_64 => {26 Arch.x86_64 => {
...@@ -49,6 +52,9 @@ fn callMainAndExit() -> unreachable {...@@ -49,6 +52,9 @@ fn callMainAndExit() -> unreachable {
4952
50export fn main(c_argc: i32, c_argv: &&u8) -> i32 {53export fn main(c_argc: i32, c_argv: &&u8) -> i32 {
51 @setFnVisible(this, want_main_symbol);54 @setFnVisible(this, want_main_symbol);
55 if (!want_main_symbol) {
56 @unreachable();
57 }
5258
53 argc = usize(c_argc);59 argc = usize(c_argc);
54 argv = c_argv;60 argv = c_argv;
std/build.zig+2
...@@ -1,5 +1,7 @@...@@ -1,5 +1,7 @@
1const mem = @import("mem.zig");1const mem = @import("mem.zig");
22
3pub const linking_libc = linkingLibrary("c");
4
3pub fn linkingLibrary(lib_name: []const u8) -> bool {5pub fn linkingLibrary(lib_name: []const u8) -> bool {
4 // TODO shouldn't need this if6 // TODO shouldn't need this if
5 if (@compileVar("link_libs").len != 0) {7 if (@compileVar("link_libs").len != 0) {
std/c/darwin.zig created+4
...@@ -0,0 +1,4 @@
1pub extern fn getrandom(buf_ptr: &u8, buf_len: usize) -> c_int;
2
3extern fn __error() -> &c_int;
4pub const _errno = __error;
std/c/index.zig created+13
...@@ -0,0 +1,13 @@
1pub use @import("errno.zig");
2
3pub use switch(@compileVar("os")) {
4 Os.linux => @import("c/linux.zig"),
5 Os.windows => @import("c/windows.zig"),
6 Os.darwin, Os.macosx, Os.ios => @import("c/darwin.zig"),
7 else => empty_import,
8};
9
10pub extern fn abort() -> unreachable;
11
12
13const empty_import = @import("empty.zig");
std/c/linux.zig created+4
...@@ -0,0 +1,4 @@
1pub extern fn getrandom(buf_ptr: &u8, buf_len: usize, flags: c_uint) -> c_int;
2
3extern fn __errno_location() -> &c_int;
4pub const _errno = __errno_location;
std/c/windows.zig created+1
...@@ -0,0 +1 @@
1pub extern fn _errno() -> &c_int;
std/debug.zig+2-2
...@@ -78,13 +78,13 @@ pub fn writeStackTrace(out_stream: &io.OutStream) -> %void {...@@ -78,13 +78,13 @@ pub fn writeStackTrace(out_stream: &io.OutStream) -> %void {
78 }78 }
79 },79 },
80 ObjectFormat.coff => {80 ObjectFormat.coff => {
81 out_stream.write("(stack trace unavailable for COFF object format)\n");81 %return out_stream.write("(stack trace unavailable for COFF object format)\n");
82 },82 },
83 ObjectFormat.macho => {83 ObjectFormat.macho => {
84 %return out_stream.write("(stack trace unavailable for Mach-O object format)\n");84 %return out_stream.write("(stack trace unavailable for Mach-O object format)\n");
85 },85 },
86 ObjectFormat.unknown => {86 ObjectFormat.unknown => {
87 out_stream.write("(stack trace unavailable for unknown object format)\n");87 %return out_stream.write("(stack trace unavailable for unknown object format)\n");
88 },88 },
89 }89 }
90}90}
std/os.zig+46-11
...@@ -1,20 +1,49 @@...@@ -1,20 +1,49 @@
1const system = switch(@compileVar("os")) {1const posix = switch(@compileVar("os")) {
2 Os.linux => @import("linux.zig"),2 Os.linux => @import("linux.zig"),
3 Os.darwin => @import("darwin.zig"),3 Os.darwin, Os.macosx, Os.ios => @import("darwin.zig"),
4 else => @compileError("Unsupported OS"),4 else => @compileError("Unsupported OS"),
5};5};
6const windows = @import("windows.zig");
6const errno = @import("errno.zig");7const errno = @import("errno.zig");
8const linking_libc = @import("build.zig").linking_libc;
9const c = @import("c/index.zig");
710
8error Unexpected;11error Unexpected;
912
13/// Fills `buf` with random bytes. If linking against libc, this calls the
14/// appropriate OS-specific library call. Otherwise it uses the zig standard
15/// library implementation.
10pub fn getRandomBytes(buf: []u8) -> %void {16pub fn getRandomBytes(buf: []u8) -> %void {
11 while (true) {17 while (true) {
12 const ret = switch (@compileVar("os")) {18 const err = switch (@compileVar("os")) {
13 Os.linux => system.getrandom(buf.ptr, buf.len, 0),19 Os.linux => {
14 Os.darwin => system.getrandom(buf.ptr, buf.len),20 if (linking_libc) {
15 else => @compileError("unsupported os"),21 if (c.getrandom(buf.ptr, buf.len, 0) == -1) *c._errno() else 0
22 } else {
23 posix.getErrno(posix.getrandom(buf.ptr, buf.len, 0))
24 }
25 },
26 Os.darwin, Os.macosx, Os.ios => {
27 if (linking_libc) {
28 if (posix.getrandom(buf.ptr, buf.len) == -1) *c._errno() else 0
29 } else {
30 posix.getErrno(posix.getrandom(buf.ptr, buf.len))
31 }
32 },
33 Os.windows => {
34 var hCryptProv: windows.HCRYPTPROV = undefined;
35 if (!windows.CryptAcquireContext(&hCryptProv, null, null, windows.PROV_RSA_FULL, 0)) {
36 return error.Unexpected;
37 }
38 defer _ = windows.CryptReleaseContext(hCryptProv, 0);
39
40 if (!windows.CryptGenRandom(hCryptProv, windows.DWORD(buf.len), buf.ptr)) {
41 return error.Unexpected;
42 }
43 return;
44 },
45 else => @compileError("Unsupported OS"),
16 };46 };
17 const err = system.getErrno(ret);
18 if (err > 0) {47 if (err > 0) {
19 return switch (err) {48 return switch (err) {
20 errno.EINVAL => @unreachable(),49 errno.EINVAL => @unreachable(),
...@@ -27,13 +56,19 @@ pub fn getRandomBytes(buf: []u8) -> %void {...@@ -27,13 +56,19 @@ pub fn getRandomBytes(buf: []u8) -> %void {
27 }56 }
28}57}
2958
59/// Raises a signal in the current kernel thread, ending its execution.
60/// If linking against libc, this calls the abort() libc function. Otherwise
61/// it uses the zig standard library implementation.
30pub coldcc fn abort() -> unreachable {62pub coldcc fn abort() -> unreachable {
63 if (linking_libc) {
64 c.abort();
65 }
31 switch (@compileVar("os")) {66 switch (@compileVar("os")) {
32 Os.linux, Os.darwin => {67 Os.linux => {
33 _ = system.raise(system.SIGABRT);68 _ = posix.raise(posix.SIGABRT);
34 _ = system.raise(system.SIGKILL);69 _ = posix.raise(posix.SIGKILL);
35 while (true) {}70 while (true) {}
36 },71 },
37 else => @compileError("unsupported os"),72 else => @compileError("Unsupported OS"),
38 }73 }
39}74}
std/windows.zig created+17
...@@ -0,0 +1,17 @@
1pub extern fn CryptAcquireContext(phProv: &HCRYPTPROV, pszContainer: LPCTSTR,
2 pszProvider: LPCTSTR, dwProvType: DWORD, dwFlags: DWORD) -> bool;
3
4pub extern fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> bool;
5
6pub extern fn CryptGenRandom(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: &BYTE) -> bool;
7
8pub const PROV_RSA_FULL = 1;
9
10
11pub const BYTE = u8;
12pub const DWORD = u32;
13// TODO something about unicode WCHAR vs char
14pub const TCHAR = u8;
15pub const LPCTSTR = ?&const TCHAR;
16pub const ULONG_PTR = usize;
17pub const HCRYPTPROV = ULONG_PTR;