| author | |
| committer | |
| log | 0cfd019377c4e91924d8f57a4c7400a2d62f8751 |
| tree | 9c62a0569648d505233743409fade82e0f36b172 |
| parent | 7bd8a2695b5fe0b1993003c0c6e02cb99de5ab33 |
| parent | 3a49d115cf38154f0094d9615334529890059006 |
| signature |
stage1 caching30 files changed, 2644 insertions(+), 535 deletions(-)
CMakeLists.txt+13-1| ... | @@ -390,7 +390,7 @@ if(MSVC) | ... | @@ -390,7 +390,7 @@ if(MSVC) |
| 390 | ) | 390 | ) |
| 391 | else() | 391 | else() |
| 392 | set_target_properties(embedded_softfloat PROPERTIES | 392 | set_target_properties(embedded_softfloat PROPERTIES |
| 393 | COMPILE_FLAGS "-std=c99" | 393 | COMPILE_FLAGS "-std=c99 -O3" |
| 394 | ) | 394 | ) |
| 395 | endif() | 395 | endif() |
| 396 | target_include_directories(embedded_softfloat PUBLIC | 396 | target_include_directories(embedded_softfloat PUBLIC |
| ... | @@ -409,7 +409,9 @@ set(ZIG_SOURCES | ... | @@ -409,7 +409,9 @@ set(ZIG_SOURCES |
| 409 | "${CMAKE_SOURCE_DIR}/src/bigint.cpp" | 409 | "${CMAKE_SOURCE_DIR}/src/bigint.cpp" |
| 410 | "${CMAKE_SOURCE_DIR}/src/buffer.cpp" | 410 | "${CMAKE_SOURCE_DIR}/src/buffer.cpp" |
| 411 | "${CMAKE_SOURCE_DIR}/src/c_tokenizer.cpp" | 411 | "${CMAKE_SOURCE_DIR}/src/c_tokenizer.cpp" |
| 412 | "${CMAKE_SOURCE_DIR}/src/cache_hash.cpp" | ||
| 412 | "${CMAKE_SOURCE_DIR}/src/codegen.cpp" | 413 | "${CMAKE_SOURCE_DIR}/src/codegen.cpp" |
| 414 | "${CMAKE_SOURCE_DIR}/src/compiler.cpp" | ||
| 413 | "${CMAKE_SOURCE_DIR}/src/errmsg.cpp" | 415 | "${CMAKE_SOURCE_DIR}/src/errmsg.cpp" |
| 414 | "${CMAKE_SOURCE_DIR}/src/error.cpp" | 416 | "${CMAKE_SOURCE_DIR}/src/error.cpp" |
| 415 | "${CMAKE_SOURCE_DIR}/src/ir.cpp" | 417 | "${CMAKE_SOURCE_DIR}/src/ir.cpp" |
| ... | @@ -424,6 +426,9 @@ set(ZIG_SOURCES | ... | @@ -424,6 +426,9 @@ set(ZIG_SOURCES |
| 424 | "${CMAKE_SOURCE_DIR}/src/util.cpp" | 426 | "${CMAKE_SOURCE_DIR}/src/util.cpp" |
| 425 | "${CMAKE_SOURCE_DIR}/src/translate_c.cpp" | 427 | "${CMAKE_SOURCE_DIR}/src/translate_c.cpp" |
| 426 | ) | 428 | ) |
| 429 | set(BLAKE_SOURCES | ||
| 430 | "${CMAKE_SOURCE_DIR}/src/blake2b.c" | ||
| 431 | ) | ||
| 427 | set(ZIG_CPP_SOURCES | 432 | set(ZIG_CPP_SOURCES |
| 428 | "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" | 433 | "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" |
| 429 | "${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp" | 434 | "${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp" |
| ... | @@ -790,6 +795,7 @@ else() | ... | @@ -790,6 +795,7 @@ else() |
| 790 | set(EXE_CFLAGS "${EXE_CFLAGS} -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D_GNU_SOURCE -fno-exceptions -fno-rtti -Werror=strict-prototypes -Werror=old-style-definition -Werror=type-limits -Wno-missing-braces") | 795 | set(EXE_CFLAGS "${EXE_CFLAGS} -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D_GNU_SOURCE -fno-exceptions -fno-rtti -Werror=strict-prototypes -Werror=old-style-definition -Werror=type-limits -Wno-missing-braces") |
| 791 | endif() | 796 | endif() |
| 792 | 797 | ||
| 798 | set(BLAKE_CFLAGS "-std=c99") | ||
| 793 | 799 | ||
| 794 | set(EXE_LDFLAGS " ") | 800 | set(EXE_LDFLAGS " ") |
| 795 | if(MINGW) | 801 | if(MINGW) |
| ... | @@ -811,6 +817,11 @@ set_target_properties(zig_cpp PROPERTIES | ... | @@ -811,6 +817,11 @@ set_target_properties(zig_cpp PROPERTIES |
| 811 | COMPILE_FLAGS ${EXE_CFLAGS} | 817 | COMPILE_FLAGS ${EXE_CFLAGS} |
| 812 | ) | 818 | ) |
| 813 | 819 | ||
| 820 | add_library(embedded_blake STATIC ${BLAKE_SOURCES}) | ||
| 821 | set_target_properties(embedded_blake PROPERTIES | ||
| 822 | COMPILE_FLAGS "${BLAKE_CFLAGS} -O3" | ||
| 823 | ) | ||
| 824 | |||
| 814 | add_executable(zig ${ZIG_SOURCES}) | 825 | add_executable(zig ${ZIG_SOURCES}) |
| 815 | set_target_properties(zig PROPERTIES | 826 | set_target_properties(zig PROPERTIES |
| 816 | COMPILE_FLAGS ${EXE_CFLAGS} | 827 | COMPILE_FLAGS ${EXE_CFLAGS} |
| ... | @@ -819,6 +830,7 @@ set_target_properties(zig PROPERTIES | ... | @@ -819,6 +830,7 @@ set_target_properties(zig PROPERTIES |
| 819 | 830 | ||
| 820 | target_link_libraries(zig LINK_PUBLIC | 831 | target_link_libraries(zig LINK_PUBLIC |
| 821 | zig_cpp | 832 | zig_cpp |
| 833 | embedded_blake | ||
| 822 | ${SOFTFLOAT_LIBRARIES} | 834 | ${SOFTFLOAT_LIBRARIES} |
| 823 | ${CLANG_LIBRARIES} | 835 | ${CLANG_LIBRARIES} |
| 824 | ${LLD_LIBRARIES} | 836 | ${LLD_LIBRARIES} |
build.zig+2-1| ... | @@ -16,11 +16,12 @@ pub fn build(b: *Builder) !void { | ... | @@ -16,11 +16,12 @@ pub fn build(b: *Builder) !void { |
| 16 | var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig"); | 16 | var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig"); |
| 17 | 17 | ||
| 18 | const rel_zig_exe = try os.path.relative(b.allocator, b.build_root, b.zig_exe); | 18 | const rel_zig_exe = try os.path.relative(b.allocator, b.build_root, b.zig_exe); |
| 19 | const langref_out_path = os.path.join(b.allocator, b.cache_root, "langref.html") catch unreachable; | ||
| 19 | var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8{ | 20 | var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8{ |
| 20 | docgen_exe.getOutputPath(), | 21 | docgen_exe.getOutputPath(), |
| 21 | rel_zig_exe, | 22 | rel_zig_exe, |
| 22 | "doc" ++ os.path.sep_str ++ "langref.html.in", | 23 | "doc" ++ os.path.sep_str ++ "langref.html.in", |
| 23 | os.path.join(b.allocator, b.cache_root, "langref.html") catch unreachable, | 24 | langref_out_path, |
| 24 | }); | 25 | }); |
| 25 | docgen_cmd.step.dependOn(&docgen_exe.step); | 26 | docgen_cmd.step.dependOn(&docgen_exe.step); |
| 26 | 27 |
doc/docgen.zig+7| ... | @@ -11,6 +11,7 @@ const max_doc_file_size = 10 * 1024 * 1024; | ... | @@ -11,6 +11,7 @@ const max_doc_file_size = 10 * 1024 * 1024; |
| 11 | const exe_ext = std.build.Target(std.build.Target.Native).exeFileExt(); | 11 | const exe_ext = std.build.Target(std.build.Target.Native).exeFileExt(); |
| 12 | const obj_ext = std.build.Target(std.build.Target.Native).oFileExt(); | 12 | const obj_ext = std.build.Target(std.build.Target.Native).oFileExt(); |
| 13 | const tmp_dir_name = "docgen_tmp"; | 13 | const tmp_dir_name = "docgen_tmp"; |
| 14 | const test_out_path = tmp_dir_name ++ os.path.sep_str ++ "test" ++ exe_ext; | ||
| 14 | 15 | ||
| 15 | pub fn main() !void { | 16 | pub fn main() !void { |
| 16 | var direct_allocator = std.heap.DirectAllocator.init(); | 17 | var direct_allocator = std.heap.DirectAllocator.init(); |
| ... | @@ -821,6 +822,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var | ... | @@ -821,6 +822,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var |
| 821 | zig_exe, | 822 | zig_exe, |
| 822 | "test", | 823 | "test", |
| 823 | tmp_source_file_name, | 824 | tmp_source_file_name, |
| 825 | "--output", | ||
| 826 | test_out_path, | ||
| 824 | }); | 827 | }); |
| 825 | try out.print("<pre><code class=\"shell\">$ zig test {}.zig", code.name); | 828 | try out.print("<pre><code class=\"shell\">$ zig test {}.zig", code.name); |
| 826 | switch (code.mode) { | 829 | switch (code.mode) { |
| ... | @@ -863,6 +866,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var | ... | @@ -863,6 +866,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var |
| 863 | "--color", | 866 | "--color", |
| 864 | "on", | 867 | "on", |
| 865 | tmp_source_file_name, | 868 | tmp_source_file_name, |
| 869 | "--output", | ||
| 870 | test_out_path, | ||
| 866 | }); | 871 | }); |
| 867 | try out.print("<pre><code class=\"shell\">$ zig test {}.zig", code.name); | 872 | try out.print("<pre><code class=\"shell\">$ zig test {}.zig", code.name); |
| 868 | switch (code.mode) { | 873 | switch (code.mode) { |
| ... | @@ -918,6 +923,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var | ... | @@ -918,6 +923,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var |
| 918 | zig_exe, | 923 | zig_exe, |
| 919 | "test", | 924 | "test", |
| 920 | tmp_source_file_name, | 925 | tmp_source_file_name, |
| 926 | "--output", | ||
| 927 | test_out_path, | ||
| 921 | }); | 928 | }); |
| 922 | switch (code.mode) { | 929 | switch (code.mode) { |
| 923 | builtin.Mode.Debug => {}, | 930 | builtin.Mode.Debug => {}, |
src/all_types.hpp+137-137| ... | @@ -10,6 +10,7 @@ | ... | @@ -10,6 +10,7 @@ |
| 10 | 10 | ||
| 11 | #include "list.hpp" | 11 | #include "list.hpp" |
| 12 | #include "buffer.hpp" | 12 | #include "buffer.hpp" |
| 13 | #include "cache_hash.hpp" | ||
| 13 | #include "zig_llvm.h" | 14 | #include "zig_llvm.h" |
| 14 | #include "hash_map.hpp" | 15 | #include "hash_map.hpp" |
| 15 | #include "errmsg.hpp" | 16 | #include "errmsg.hpp" |
| ... | @@ -1550,22 +1551,50 @@ struct LinkLib { | ... | @@ -1550,22 +1551,50 @@ struct LinkLib { |
| 1550 | bool provided_explicitly; | 1551 | bool provided_explicitly; |
| 1551 | }; | 1552 | }; |
| 1552 | 1553 | ||
| 1554 | // When adding fields, check if they should be added to the hash computation in build_with_cache | ||
| 1553 | struct CodeGen { | 1555 | struct CodeGen { |
| 1556 | //////////////////////////// Runtime State | ||
| 1554 | LLVMModuleRef module; | 1557 | LLVMModuleRef module; |
| 1555 | ZigList<ErrorMsg*> errors; | 1558 | ZigList<ErrorMsg*> errors; |
| 1556 | LLVMBuilderRef builder; | 1559 | LLVMBuilderRef builder; |
| 1557 | ZigLLVMDIBuilder *dbuilder; | 1560 | ZigLLVMDIBuilder *dbuilder; |
| 1558 | ZigLLVMDICompileUnit *compile_unit; | 1561 | ZigLLVMDICompileUnit *compile_unit; |
| 1559 | ZigLLVMDIFile *compile_unit_file; | 1562 | ZigLLVMDIFile *compile_unit_file; |
| 1560 | |||
| 1561 | ZigList<LinkLib *> link_libs_list; | ||
| 1562 | LinkLib *libc_link_lib; | 1563 | LinkLib *libc_link_lib; |
| 1563 | 1564 | LLVMTargetDataRef target_data_ref; | |
| 1564 | // add -framework [name] args to linker | 1565 | LLVMTargetMachineRef target_machine; |
| 1565 | ZigList<Buf *> darwin_frameworks; | 1566 | ZigLLVMDIFile *dummy_di_file; |
| 1566 | // add -rpath [name] args to linker | 1567 | LLVMValueRef cur_ret_ptr; |
| 1567 | ZigList<Buf *> rpath_list; | 1568 | LLVMValueRef cur_fn_val; |
| 1568 | 1569 | LLVMValueRef cur_err_ret_trace_val_arg; | |
| 1570 | LLVMValueRef cur_err_ret_trace_val_stack; | ||
| 1571 | LLVMValueRef memcpy_fn_val; | ||
| 1572 | LLVMValueRef memset_fn_val; | ||
| 1573 | LLVMValueRef trap_fn_val; | ||
| 1574 | LLVMValueRef return_address_fn_val; | ||
| 1575 | LLVMValueRef frame_address_fn_val; | ||
| 1576 | LLVMValueRef coro_destroy_fn_val; | ||
| 1577 | LLVMValueRef coro_id_fn_val; | ||
| 1578 | LLVMValueRef coro_alloc_fn_val; | ||
| 1579 | LLVMValueRef coro_size_fn_val; | ||
| 1580 | LLVMValueRef coro_begin_fn_val; | ||
| 1581 | LLVMValueRef coro_suspend_fn_val; | ||
| 1582 | LLVMValueRef coro_end_fn_val; | ||
| 1583 | LLVMValueRef coro_free_fn_val; | ||
| 1584 | LLVMValueRef coro_resume_fn_val; | ||
| 1585 | LLVMValueRef coro_save_fn_val; | ||
| 1586 | LLVMValueRef coro_promise_fn_val; | ||
| 1587 | LLVMValueRef coro_alloc_helper_fn_val; | ||
| 1588 | LLVMValueRef coro_frame_fn_val; | ||
| 1589 | LLVMValueRef merge_err_ret_traces_fn_val; | ||
| 1590 | LLVMValueRef add_error_return_trace_addr_fn_val; | ||
| 1591 | LLVMValueRef stacksave_fn_val; | ||
| 1592 | LLVMValueRef stackrestore_fn_val; | ||
| 1593 | LLVMValueRef write_register_fn_val; | ||
| 1594 | LLVMValueRef sp_md_node; | ||
| 1595 | LLVMValueRef err_name_table; | ||
| 1596 | LLVMValueRef safety_crash_err_fn; | ||
| 1597 | LLVMValueRef return_err_fn; | ||
| 1569 | 1598 | ||
| 1570 | // reminder: hash tables must be initialized before use | 1599 | // reminder: hash tables must be initialized before use |
| 1571 | HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table; | 1600 | HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table; |
| ... | @@ -1582,15 +1611,29 @@ struct CodeGen { | ... | @@ -1582,15 +1611,29 @@ struct CodeGen { |
| 1582 | HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table; | 1611 | HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table; |
| 1583 | HashMap<const ZigType *, ConstExprValue *, type_ptr_hash, type_ptr_eql> type_info_cache; | 1612 | HashMap<const ZigType *, ConstExprValue *, type_ptr_hash, type_ptr_eql> type_info_cache; |
| 1584 | 1613 | ||
| 1585 | |||
| 1586 | ZigList<ImportTableEntry *> import_queue; | 1614 | ZigList<ImportTableEntry *> import_queue; |
| 1587 | size_t import_queue_index; | 1615 | size_t import_queue_index; |
| 1588 | ZigList<Tld *> resolve_queue; | 1616 | ZigList<Tld *> resolve_queue; |
| 1589 | size_t resolve_queue_index; | 1617 | size_t resolve_queue_index; |
| 1590 | ZigList<AstNode *> use_queue; | 1618 | ZigList<AstNode *> use_queue; |
| 1591 | size_t use_queue_index; | 1619 | size_t use_queue_index; |
| 1620 | ZigList<TimeEvent> timing_events; | ||
| 1621 | ZigList<ZigLLVMDIType **> error_di_types; | ||
| 1622 | ZigList<AstNode *> tld_ref_source_node_stack; | ||
| 1623 | ZigList<ZigFn *> inline_fns; | ||
| 1624 | ZigList<ZigFn *> test_fns; | ||
| 1625 | ZigList<ZigLLVMDIEnumerator *> err_enumerators; | ||
| 1626 | ZigList<ErrorTableEntry *> errors_by_index; | ||
| 1627 | size_t largest_err_name_len; | ||
| 1592 | 1628 | ||
| 1593 | uint32_t next_unresolved_index; | 1629 | PackageTableEntry *std_package; |
| 1630 | PackageTableEntry *panic_package; | ||
| 1631 | PackageTableEntry *test_runner_package; | ||
| 1632 | PackageTableEntry *compile_var_package; | ||
| 1633 | ImportTableEntry *compile_var_import; | ||
| 1634 | ImportTableEntry *root_import; | ||
| 1635 | ImportTableEntry *bootstrap_import; | ||
| 1636 | ImportTableEntry *test_runner_import; | ||
| 1594 | 1637 | ||
| 1595 | struct { | 1638 | struct { |
| 1596 | ZigType *entry_bool; | 1639 | ZigType *entry_bool; |
| ... | @@ -1626,165 +1669,122 @@ struct CodeGen { | ... | @@ -1626,165 +1669,122 @@ struct CodeGen { |
| 1626 | ZigType *entry_arg_tuple; | 1669 | ZigType *entry_arg_tuple; |
| 1627 | ZigType *entry_promise; | 1670 | ZigType *entry_promise; |
| 1628 | } builtin_types; | 1671 | } builtin_types; |
| 1672 | ZigType *align_amt_type; | ||
| 1673 | ZigType *stack_trace_type; | ||
| 1674 | ZigType *ptr_to_stack_trace_type; | ||
| 1675 | ZigType *err_tag_type; | ||
| 1676 | ZigType *test_fn_type; | ||
| 1629 | 1677 | ||
| 1630 | EmitFileType emit_file_type; | ||
| 1631 | ZigTarget zig_target; | ||
| 1632 | LLVMTargetDataRef target_data_ref; | ||
| 1633 | unsigned pointer_size_bytes; | ||
| 1634 | bool is_big_endian; | ||
| 1635 | bool is_static; | ||
| 1636 | bool strip_debug_symbols; | ||
| 1637 | bool want_h_file; | ||
| 1638 | bool have_pub_main; | ||
| 1639 | bool have_c_main; | ||
| 1640 | bool have_winmain; | ||
| 1641 | bool have_winmain_crt_startup; | ||
| 1642 | bool have_dllmain_crt_startup; | ||
| 1643 | bool have_pub_panic; | ||
| 1644 | Buf *libc_lib_dir; | ||
| 1645 | Buf *libc_static_lib_dir; | ||
| 1646 | Buf *libc_include_dir; | ||
| 1647 | Buf *msvc_lib_dir; | ||
| 1648 | Buf *kernel32_lib_dir; | ||
| 1649 | Buf *zig_lib_dir; | ||
| 1650 | Buf *zig_std_dir; | ||
| 1651 | Buf *zig_c_headers_dir; | ||
| 1652 | Buf *zig_std_special_dir; | ||
| 1653 | Buf *dynamic_linker; | ||
| 1654 | Buf *ar_path; | ||
| 1655 | ZigWindowsSDK *win_sdk; | ||
| 1656 | Buf triple_str; | 1678 | Buf triple_str; |
| 1657 | BuildMode build_mode; | 1679 | Buf global_asm; |
| 1658 | bool is_test_build; | 1680 | Buf *out_h_path; |
| 1659 | bool have_err_ret_tracing; | 1681 | Buf artifact_dir; |
| 1660 | uint32_t target_os_index; | 1682 | Buf output_file_path; |
| 1661 | uint32_t target_arch_index; | 1683 | Buf o_file_output_path; |
| 1662 | uint32_t target_environ_index; | 1684 | Buf *wanted_output_file_path; |
| 1663 | uint32_t target_oformat_index; | 1685 | Buf cache_dir; |
| 1664 | LLVMTargetMachineRef target_machine; | 1686 | |
| 1665 | ZigLLVMDIFile *dummy_di_file; | 1687 | IrInstruction *invalid_instruction; |
| 1666 | bool is_native_target; | 1688 | |
| 1667 | PackageTableEntry *root_package; | 1689 | ConstExprValue const_void_val; |
| 1668 | PackageTableEntry *std_package; | 1690 | ConstExprValue panic_msg_vals[PanicMsgIdCount]; |
| 1669 | PackageTableEntry *panic_package; | ||
| 1670 | PackageTableEntry *test_runner_package; | ||
| 1671 | PackageTableEntry *compile_var_package; | ||
| 1672 | ImportTableEntry *compile_var_import; | ||
| 1673 | Buf *root_out_name; | ||
| 1674 | bool windows_subsystem_windows; | ||
| 1675 | bool windows_subsystem_console; | ||
| 1676 | Buf *mmacosx_version_min; | ||
| 1677 | Buf *mios_version_min; | ||
| 1678 | bool linker_rdynamic; | ||
| 1679 | const char *linker_script; | ||
| 1680 | 1691 | ||
| 1681 | // The function definitions this module includes. | 1692 | // The function definitions this module includes. |
| 1682 | ZigList<ZigFn *> fn_defs; | 1693 | ZigList<ZigFn *> fn_defs; |
| 1683 | size_t fn_defs_index; | 1694 | size_t fn_defs_index; |
| 1684 | ZigList<TldVar *> global_vars; | 1695 | ZigList<TldVar *> global_vars; |
| 1685 | 1696 | ||
| 1686 | OutType out_type; | ||
| 1687 | ZigFn *cur_fn; | 1697 | ZigFn *cur_fn; |
| 1688 | ZigFn *main_fn; | 1698 | ZigFn *main_fn; |
| 1689 | ZigFn *panic_fn; | 1699 | ZigFn *panic_fn; |
| 1690 | LLVMValueRef cur_ret_ptr; | 1700 | AstNode *root_export_decl; |
| 1691 | LLVMValueRef cur_fn_val; | 1701 | |
| 1692 | LLVMValueRef cur_err_ret_trace_val_arg; | 1702 | CacheHash cache_hash; |
| 1693 | LLVMValueRef cur_err_ret_trace_val_stack; | 1703 | ErrColor err_color; |
| 1704 | uint32_t next_unresolved_index; | ||
| 1705 | unsigned pointer_size_bytes; | ||
| 1706 | uint32_t target_os_index; | ||
| 1707 | uint32_t target_arch_index; | ||
| 1708 | uint32_t target_environ_index; | ||
| 1709 | uint32_t target_oformat_index; | ||
| 1710 | bool is_big_endian; | ||
| 1711 | bool want_h_file; | ||
| 1712 | bool have_pub_main; | ||
| 1713 | bool have_c_main; | ||
| 1714 | bool have_winmain; | ||
| 1715 | bool have_winmain_crt_startup; | ||
| 1716 | bool have_dllmain_crt_startup; | ||
| 1717 | bool have_pub_panic; | ||
| 1718 | bool have_err_ret_tracing; | ||
| 1694 | bool c_want_stdint; | 1719 | bool c_want_stdint; |
| 1695 | bool c_want_stdbool; | 1720 | bool c_want_stdbool; |
| 1696 | AstNode *root_export_decl; | ||
| 1697 | size_t version_major; | ||
| 1698 | size_t version_minor; | ||
| 1699 | size_t version_patch; | ||
| 1700 | bool verbose_tokenize; | 1721 | bool verbose_tokenize; |
| 1701 | bool verbose_ast; | 1722 | bool verbose_ast; |
| 1702 | bool verbose_link; | 1723 | bool verbose_link; |
| 1703 | bool verbose_ir; | 1724 | bool verbose_ir; |
| 1704 | bool verbose_llvm_ir; | 1725 | bool verbose_llvm_ir; |
| 1705 | bool verbose_cimport; | 1726 | bool verbose_cimport; |
| 1706 | ErrColor err_color; | ||
| 1707 | ImportTableEntry *root_import; | ||
| 1708 | ImportTableEntry *bootstrap_import; | ||
| 1709 | ImportTableEntry *test_runner_import; | ||
| 1710 | LLVMValueRef memcpy_fn_val; | ||
| 1711 | LLVMValueRef memset_fn_val; | ||
| 1712 | LLVMValueRef trap_fn_val; | ||
| 1713 | LLVMValueRef return_address_fn_val; | ||
| 1714 | LLVMValueRef frame_address_fn_val; | ||
| 1715 | LLVMValueRef coro_destroy_fn_val; | ||
| 1716 | LLVMValueRef coro_id_fn_val; | ||
| 1717 | LLVMValueRef coro_alloc_fn_val; | ||
| 1718 | LLVMValueRef coro_size_fn_val; | ||
| 1719 | LLVMValueRef coro_begin_fn_val; | ||
| 1720 | LLVMValueRef coro_suspend_fn_val; | ||
| 1721 | LLVMValueRef coro_end_fn_val; | ||
| 1722 | LLVMValueRef coro_free_fn_val; | ||
| 1723 | LLVMValueRef coro_resume_fn_val; | ||
| 1724 | LLVMValueRef coro_save_fn_val; | ||
| 1725 | LLVMValueRef coro_promise_fn_val; | ||
| 1726 | LLVMValueRef coro_alloc_helper_fn_val; | ||
| 1727 | LLVMValueRef coro_frame_fn_val; | ||
| 1728 | LLVMValueRef merge_err_ret_traces_fn_val; | ||
| 1729 | LLVMValueRef add_error_return_trace_addr_fn_val; | ||
| 1730 | LLVMValueRef stacksave_fn_val; | ||
| 1731 | LLVMValueRef stackrestore_fn_val; | ||
| 1732 | LLVMValueRef write_register_fn_val; | ||
| 1733 | bool error_during_imports; | 1727 | bool error_during_imports; |
| 1728 | bool generate_error_name_table; | ||
| 1729 | bool enable_cache; | ||
| 1730 | bool enable_time_report; | ||
| 1734 | 1731 | ||
| 1735 | LLVMValueRef sp_md_node; | 1732 | //////////////////////////// Participates in Input Parameter Cache Hash |
| 1736 | 1733 | ZigList<LinkLib *> link_libs_list; | |
| 1737 | const char **clang_argv; | 1734 | // add -framework [name] args to linker |
| 1738 | size_t clang_argv_len; | 1735 | ZigList<Buf *> darwin_frameworks; |
| 1736 | // add -rpath [name] args to linker | ||
| 1737 | ZigList<Buf *> rpath_list; | ||
| 1738 | ZigList<Buf *> forbidden_libs; | ||
| 1739 | ZigList<Buf *> link_objects; | ||
| 1740 | ZigList<Buf *> assembly_files; | ||
| 1739 | ZigList<const char *> lib_dirs; | 1741 | ZigList<const char *> lib_dirs; |
| 1740 | 1742 | ||
| 1741 | const char **llvm_argv; | 1743 | size_t version_major; |
| 1742 | size_t llvm_argv_len; | 1744 | size_t version_minor; |
| 1743 | 1745 | size_t version_patch; | |
| 1744 | ZigList<ZigFn *> test_fns; | 1746 | const char *linker_script; |
| 1745 | ZigType *test_fn_type; | ||
| 1746 | 1747 | ||
| 1748 | EmitFileType emit_file_type; | ||
| 1749 | BuildMode build_mode; | ||
| 1750 | OutType out_type; | ||
| 1751 | ZigTarget zig_target; | ||
| 1752 | bool is_static; | ||
| 1753 | bool strip_debug_symbols; | ||
| 1754 | bool is_test_build; | ||
| 1755 | bool is_native_target; | ||
| 1756 | bool windows_subsystem_windows; | ||
| 1757 | bool windows_subsystem_console; | ||
| 1758 | bool linker_rdynamic; | ||
| 1759 | bool no_rosegment_workaround; | ||
| 1747 | bool each_lib_rpath; | 1760 | bool each_lib_rpath; |
| 1748 | 1761 | ||
| 1749 | ZigType *err_tag_type; | 1762 | Buf *mmacosx_version_min; |
| 1750 | ZigList<ZigLLVMDIEnumerator *> err_enumerators; | 1763 | Buf *mios_version_min; |
| 1751 | ZigList<ErrorTableEntry *> errors_by_index; | 1764 | Buf *root_out_name; |
| 1752 | bool generate_error_name_table; | ||
| 1753 | LLVMValueRef err_name_table; | ||
| 1754 | size_t largest_err_name_len; | ||
| 1755 | LLVMValueRef safety_crash_err_fn; | ||
| 1756 | |||
| 1757 | LLVMValueRef return_err_fn; | ||
| 1758 | |||
| 1759 | IrInstruction *invalid_instruction; | ||
| 1760 | ConstExprValue const_void_val; | ||
| 1761 | |||
| 1762 | ConstExprValue panic_msg_vals[PanicMsgIdCount]; | ||
| 1763 | |||
| 1764 | Buf global_asm; | ||
| 1765 | ZigList<Buf *> link_objects; | ||
| 1766 | ZigList<Buf *> assembly_files; | ||
| 1767 | |||
| 1768 | Buf *test_filter; | 1765 | Buf *test_filter; |
| 1769 | Buf *test_name_prefix; | 1766 | Buf *test_name_prefix; |
| 1767 | PackageTableEntry *root_package; | ||
| 1770 | 1768 | ||
| 1771 | ZigList<TimeEvent> timing_events; | 1769 | const char **llvm_argv; |
| 1772 | 1770 | size_t llvm_argv_len; | |
| 1773 | Buf cache_dir; | ||
| 1774 | Buf *out_h_path; | ||
| 1775 | |||
| 1776 | ZigList<ZigFn *> inline_fns; | ||
| 1777 | ZigList<AstNode *> tld_ref_source_node_stack; | ||
| 1778 | |||
| 1779 | ZigType *align_amt_type; | ||
| 1780 | ZigType *stack_trace_type; | ||
| 1781 | ZigType *ptr_to_stack_trace_type; | ||
| 1782 | 1771 | ||
| 1783 | ZigList<ZigLLVMDIType **> error_di_types; | 1772 | const char **clang_argv; |
| 1773 | size_t clang_argv_len; | ||
| 1784 | 1774 | ||
| 1785 | ZigList<Buf *> forbidden_libs; | 1775 | //////////////////////////// Unsorted |
| 1786 | 1776 | ||
| 1787 | bool no_rosegment_workaround; | 1777 | Buf *libc_lib_dir; |
| 1778 | Buf *libc_static_lib_dir; | ||
| 1779 | Buf *libc_include_dir; | ||
| 1780 | Buf *msvc_lib_dir; | ||
| 1781 | Buf *kernel32_lib_dir; | ||
| 1782 | Buf *zig_lib_dir; | ||
| 1783 | Buf *zig_std_dir; | ||
| 1784 | Buf *zig_c_headers_dir; | ||
| 1785 | Buf *zig_std_special_dir; | ||
| 1786 | Buf *dynamic_linker; | ||
| 1787 | ZigWindowsSDK *win_sdk; | ||
| 1788 | }; | 1788 | }; |
| 1789 | 1789 | ||
| 1790 | enum VarLinkage { | 1790 | enum VarLinkage { |
src/analyze.cpp+14-1| ... | @@ -6289,6 +6289,12 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) { | ... | @@ -6289,6 +6289,12 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) { |
| 6289 | if (is_libc && g->libc_link_lib != nullptr) | 6289 | if (is_libc && g->libc_link_lib != nullptr) |
| 6290 | return g->libc_link_lib; | 6290 | return g->libc_link_lib; |
| 6291 | 6291 | ||
| 6292 | if (g->enable_cache && is_libc && g->zig_target.os != OsMacOSX && g->zig_target.os != OsIOS) { | ||
| 6293 | fprintf(stderr, "TODO linking against libc is currently incompatible with `--cache on`.\n" | ||
| 6294 | "Zig is not yet capable of determining whether the libc installation has changed on subsequent builds.\n"); | ||
| 6295 | exit(1); | ||
| 6296 | } | ||
| 6297 | |||
| 6292 | for (size_t i = 0; i < g->link_libs_list.length; i += 1) { | 6298 | for (size_t i = 0; i < g->link_libs_list.length; i += 1) { |
| 6293 | LinkLib *existing_lib = g->link_libs_list.at(i); | 6299 | LinkLib *existing_lib = g->link_libs_list.at(i); |
| 6294 | if (buf_eql_buf(existing_lib->name, name)) { | 6300 | if (buf_eql_buf(existing_lib->name, name)) { |
| ... | @@ -6398,6 +6404,14 @@ not_integer: | ... | @@ -6398,6 +6404,14 @@ not_integer: |
| 6398 | return nullptr; | 6404 | return nullptr; |
| 6399 | } | 6405 | } |
| 6400 | 6406 | ||
| 6407 | Error file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents) { | ||
| 6408 | if (g->enable_cache) { | ||
| 6409 | return cache_add_file_fetch(&g->cache_hash, resolved_path, contents); | ||
| 6410 | } else { | ||
| 6411 | return os_fetch_file_path(resolved_path, contents, false); | ||
| 6412 | } | ||
| 6413 | } | ||
| 6414 | |||
| 6401 | X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) { | 6415 | X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) { |
| 6402 | size_t ty_size = type_size(g, ty); | 6416 | size_t ty_size = type_size(g, ty); |
| 6403 | if (get_codegen_ptr_type(ty) != nullptr) | 6417 | if (get_codegen_ptr_type(ty) != nullptr) |
| ... | @@ -6478,4 +6492,3 @@ bool type_is_c_abi_int(CodeGen *g, ZigType *ty) { | ... | @@ -6478,4 +6492,3 @@ bool type_is_c_abi_int(CodeGen *g, ZigType *ty) { |
| 6478 | ty->id == ZigTypeIdUnreachable || | 6492 | ty->id == ZigTypeIdUnreachable || |
| 6479 | get_codegen_ptr_type(ty) != nullptr); | 6493 | get_codegen_ptr_type(ty) != nullptr); |
| 6480 | } | 6494 | } |
| 6481 |
src/analyze.hpp+2| ... | @@ -209,6 +209,8 @@ ZigType *get_primitive_type(CodeGen *g, Buf *name); | ... | @@ -209,6 +209,8 @@ ZigType *get_primitive_type(CodeGen *g, Buf *name); |
| 209 | bool calling_convention_allows_zig_types(CallingConvention cc); | 209 | bool calling_convention_allows_zig_types(CallingConvention cc); |
| 210 | const char *calling_convention_name(CallingConvention cc); | 210 | const char *calling_convention_name(CallingConvention cc); |
| 211 | 211 | ||
| 212 | Error ATTRIBUTE_MUST_USE file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents); | ||
| 213 | |||
| 212 | void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk); | 214 | void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk); |
| 213 | X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty); | 215 | X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty); |
| 214 | bool type_is_c_abi_int(CodeGen *g, ZigType *ty); | 216 | bool type_is_c_abi_int(CodeGen *g, ZigType *ty); |
src/blake2.h created+196| ... | @@ -0,0 +1,196 @@ | ||
| 1 | /* | ||
| 2 | BLAKE2 reference source code package - reference C implementations | ||
| 3 | |||
| 4 | Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the | ||
| 5 | terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at | ||
| 6 | your option. The terms of these licenses can be found at: | ||
| 7 | |||
| 8 | - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 | ||
| 9 | - OpenSSL license : https://www.openssl.org/source/license.html | ||
| 10 | - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 | ||
| 11 | |||
| 12 | More information about the BLAKE2 hash function can be found at | ||
| 13 | https://blake2.net. | ||
| 14 | */ | ||
| 15 | #ifndef BLAKE2_H | ||
| 16 | #define BLAKE2_H | ||
| 17 | |||
| 18 | #include <stddef.h> | ||
| 19 | #include <stdint.h> | ||
| 20 | |||
| 21 | #if defined(_MSC_VER) | ||
| 22 | #define BLAKE2_PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop)) | ||
| 23 | #else | ||
| 24 | #define BLAKE2_PACKED(x) x __attribute__((packed)) | ||
| 25 | #endif | ||
| 26 | |||
| 27 | #if defined(__cplusplus) | ||
| 28 | extern "C" { | ||
| 29 | #endif | ||
| 30 | |||
| 31 | enum blake2s_constant | ||
| 32 | { | ||
| 33 | BLAKE2S_BLOCKBYTES = 64, | ||
| 34 | BLAKE2S_OUTBYTES = 32, | ||
| 35 | BLAKE2S_KEYBYTES = 32, | ||
| 36 | BLAKE2S_SALTBYTES = 8, | ||
| 37 | BLAKE2S_PERSONALBYTES = 8 | ||
| 38 | }; | ||
| 39 | |||
| 40 | enum blake2b_constant | ||
| 41 | { | ||
| 42 | BLAKE2B_BLOCKBYTES = 128, | ||
| 43 | BLAKE2B_OUTBYTES = 64, | ||
| 44 | BLAKE2B_KEYBYTES = 64, | ||
| 45 | BLAKE2B_SALTBYTES = 16, | ||
| 46 | BLAKE2B_PERSONALBYTES = 16 | ||
| 47 | }; | ||
| 48 | |||
| 49 | typedef struct blake2s_state__ | ||
| 50 | { | ||
| 51 | uint32_t h[8]; | ||
| 52 | uint32_t t[2]; | ||
| 53 | uint32_t f[2]; | ||
| 54 | uint8_t buf[BLAKE2S_BLOCKBYTES]; | ||
| 55 | size_t buflen; | ||
| 56 | size_t outlen; | ||
| 57 | uint8_t last_node; | ||
| 58 | } blake2s_state; | ||
| 59 | |||
| 60 | typedef struct blake2b_state__ | ||
| 61 | { | ||
| 62 | uint64_t h[8]; | ||
| 63 | uint64_t t[2]; | ||
| 64 | uint64_t f[2]; | ||
| 65 | uint8_t buf[BLAKE2B_BLOCKBYTES]; | ||
| 66 | size_t buflen; | ||
| 67 | size_t outlen; | ||
| 68 | uint8_t last_node; | ||
| 69 | } blake2b_state; | ||
| 70 | |||
| 71 | typedef struct blake2sp_state__ | ||
| 72 | { | ||
| 73 | blake2s_state S[8][1]; | ||
| 74 | blake2s_state R[1]; | ||
| 75 | uint8_t buf[8 * BLAKE2S_BLOCKBYTES]; | ||
| 76 | size_t buflen; | ||
| 77 | size_t outlen; | ||
| 78 | } blake2sp_state; | ||
| 79 | |||
| 80 | typedef struct blake2bp_state__ | ||
| 81 | { | ||
| 82 | blake2b_state S[4][1]; | ||
| 83 | blake2b_state R[1]; | ||
| 84 | uint8_t buf[4 * BLAKE2B_BLOCKBYTES]; | ||
| 85 | size_t buflen; | ||
| 86 | size_t outlen; | ||
| 87 | } blake2bp_state; | ||
| 88 | |||
| 89 | |||
| 90 | BLAKE2_PACKED(struct blake2s_param__ | ||
| 91 | { | ||
| 92 | uint8_t digest_length; /* 1 */ | ||
| 93 | uint8_t key_length; /* 2 */ | ||
| 94 | uint8_t fanout; /* 3 */ | ||
| 95 | uint8_t depth; /* 4 */ | ||
| 96 | uint32_t leaf_length; /* 8 */ | ||
| 97 | uint32_t node_offset; /* 12 */ | ||
| 98 | uint16_t xof_length; /* 14 */ | ||
| 99 | uint8_t node_depth; /* 15 */ | ||
| 100 | uint8_t inner_length; /* 16 */ | ||
| 101 | /* uint8_t reserved[0]; */ | ||
| 102 | uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */ | ||
| 103 | uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */ | ||
| 104 | }); | ||
| 105 | |||
| 106 | typedef struct blake2s_param__ blake2s_param; | ||
| 107 | |||
| 108 | BLAKE2_PACKED(struct blake2b_param__ | ||
| 109 | { | ||
| 110 | uint8_t digest_length; /* 1 */ | ||
| 111 | uint8_t key_length; /* 2 */ | ||
| 112 | uint8_t fanout; /* 3 */ | ||
| 113 | uint8_t depth; /* 4 */ | ||
| 114 | uint32_t leaf_length; /* 8 */ | ||
| 115 | uint32_t node_offset; /* 12 */ | ||
| 116 | uint32_t xof_length; /* 16 */ | ||
| 117 | uint8_t node_depth; /* 17 */ | ||
| 118 | uint8_t inner_length; /* 18 */ | ||
| 119 | uint8_t reserved[14]; /* 32 */ | ||
| 120 | uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */ | ||
| 121 | uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */ | ||
| 122 | }); | ||
| 123 | |||
| 124 | typedef struct blake2b_param__ blake2b_param; | ||
| 125 | |||
| 126 | typedef struct blake2xs_state__ | ||
| 127 | { | ||
| 128 | blake2s_state S[1]; | ||
| 129 | blake2s_param P[1]; | ||
| 130 | } blake2xs_state; | ||
| 131 | |||
| 132 | typedef struct blake2xb_state__ | ||
| 133 | { | ||
| 134 | blake2b_state S[1]; | ||
| 135 | blake2b_param P[1]; | ||
| 136 | } blake2xb_state; | ||
| 137 | |||
| 138 | /* Padded structs result in a compile-time error */ | ||
| 139 | enum { | ||
| 140 | BLAKE2_DUMMY_1 = 1/(sizeof(blake2s_param) == BLAKE2S_OUTBYTES), | ||
| 141 | BLAKE2_DUMMY_2 = 1/(sizeof(blake2b_param) == BLAKE2B_OUTBYTES) | ||
| 142 | }; | ||
| 143 | |||
| 144 | /* Streaming API */ | ||
| 145 | int blake2s_init( blake2s_state *S, size_t outlen ); | ||
| 146 | int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen ); | ||
| 147 | int blake2s_init_param( blake2s_state *S, const blake2s_param *P ); | ||
| 148 | int blake2s_update( blake2s_state *S, const void *in, size_t inlen ); | ||
| 149 | int blake2s_final( blake2s_state *S, void *out, size_t outlen ); | ||
| 150 | |||
| 151 | int blake2b_init( blake2b_state *S, size_t outlen ); | ||
| 152 | int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen ); | ||
| 153 | int blake2b_init_param( blake2b_state *S, const blake2b_param *P ); | ||
| 154 | int blake2b_update( blake2b_state *S, const void *in, size_t inlen ); | ||
| 155 | int blake2b_final( blake2b_state *S, void *out, size_t outlen ); | ||
| 156 | |||
| 157 | int blake2sp_init( blake2sp_state *S, size_t outlen ); | ||
| 158 | int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen ); | ||
| 159 | int blake2sp_update( blake2sp_state *S, const void *in, size_t inlen ); | ||
| 160 | int blake2sp_final( blake2sp_state *S, void *out, size_t outlen ); | ||
| 161 | |||
| 162 | int blake2bp_init( blake2bp_state *S, size_t outlen ); | ||
| 163 | int blake2bp_init_key( blake2bp_state *S, size_t outlen, const void *key, size_t keylen ); | ||
| 164 | int blake2bp_update( blake2bp_state *S, const void *in, size_t inlen ); | ||
| 165 | int blake2bp_final( blake2bp_state *S, void *out, size_t outlen ); | ||
| 166 | |||
| 167 | /* Variable output length API */ | ||
| 168 | int blake2xs_init( blake2xs_state *S, const size_t outlen ); | ||
| 169 | int blake2xs_init_key( blake2xs_state *S, const size_t outlen, const void *key, size_t keylen ); | ||
| 170 | int blake2xs_update( blake2xs_state *S, const void *in, size_t inlen ); | ||
| 171 | int blake2xs_final(blake2xs_state *S, void *out, size_t outlen); | ||
| 172 | |||
| 173 | int blake2xb_init( blake2xb_state *S, const size_t outlen ); | ||
| 174 | int blake2xb_init_key( blake2xb_state *S, const size_t outlen, const void *key, size_t keylen ); | ||
| 175 | int blake2xb_update( blake2xb_state *S, const void *in, size_t inlen ); | ||
| 176 | int blake2xb_final(blake2xb_state *S, void *out, size_t outlen); | ||
| 177 | |||
| 178 | /* Simple API */ | ||
| 179 | int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); | ||
| 180 | int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); | ||
| 181 | |||
| 182 | int blake2sp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); | ||
| 183 | int blake2bp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); | ||
| 184 | |||
| 185 | int blake2xs( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); | ||
| 186 | int blake2xb( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); | ||
| 187 | |||
| 188 | /* This is simply an alias for blake2b */ | ||
| 189 | int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); | ||
| 190 | |||
| 191 | #if defined(__cplusplus) | ||
| 192 | } | ||
| 193 | #endif | ||
| 194 | |||
| 195 | #endif | ||
| 196 | |||
src/blake2b.c created+539| ... | @@ -0,0 +1,539 @@ | ||
| 1 | /* | ||
| 2 | BLAKE2 reference source code package - reference C implementations | ||
| 3 | |||
| 4 | Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the | ||
| 5 | terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at | ||
| 6 | your option. The terms of these licenses can be found at: | ||
| 7 | |||
| 8 | - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 | ||
| 9 | - OpenSSL license : https://www.openssl.org/source/license.html | ||
| 10 | - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 | ||
| 11 | |||
| 12 | More information about the BLAKE2 hash function can be found at | ||
| 13 | https://blake2.net. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <stdint.h> | ||
| 17 | #include <string.h> | ||
| 18 | #include <stdio.h> | ||
| 19 | |||
| 20 | #include "blake2.h" | ||
| 21 | /* | ||
| 22 | BLAKE2 reference source code package - reference C implementations | ||
| 23 | |||
| 24 | Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the | ||
| 25 | terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at | ||
| 26 | your option. The terms of these licenses can be found at: | ||
| 27 | |||
| 28 | - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 | ||
| 29 | - OpenSSL license : https://www.openssl.org/source/license.html | ||
| 30 | - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 | ||
| 31 | |||
| 32 | More information about the BLAKE2 hash function can be found at | ||
| 33 | https://blake2.net. | ||
| 34 | */ | ||
| 35 | #ifndef BLAKE2_IMPL_H | ||
| 36 | #define BLAKE2_IMPL_H | ||
| 37 | |||
| 38 | #include <stdint.h> | ||
| 39 | #include <string.h> | ||
| 40 | |||
| 41 | #if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L) | ||
| 42 | #if defined(_MSC_VER) | ||
| 43 | #define BLAKE2_INLINE __inline | ||
| 44 | #elif defined(__GNUC__) | ||
| 45 | #define BLAKE2_INLINE __inline__ | ||
| 46 | #else | ||
| 47 | #define BLAKE2_INLINE | ||
| 48 | #endif | ||
| 49 | #else | ||
| 50 | #define BLAKE2_INLINE inline | ||
| 51 | #endif | ||
| 52 | |||
| 53 | static BLAKE2_INLINE uint32_t load32( const void *src ) | ||
| 54 | { | ||
| 55 | #if defined(NATIVE_LITTLE_ENDIAN) | ||
| 56 | uint32_t w; | ||
| 57 | memcpy(&w, src, sizeof w); | ||
| 58 | return w; | ||
| 59 | #else | ||
| 60 | const uint8_t *p = ( const uint8_t * )src; | ||
| 61 | return (( uint32_t )( p[0] ) << 0) | | ||
| 62 | (( uint32_t )( p[1] ) << 8) | | ||
| 63 | (( uint32_t )( p[2] ) << 16) | | ||
| 64 | (( uint32_t )( p[3] ) << 24) ; | ||
| 65 | #endif | ||
| 66 | } | ||
| 67 | |||
| 68 | static BLAKE2_INLINE uint64_t load64( const void *src ) | ||
| 69 | { | ||
| 70 | #if defined(NATIVE_LITTLE_ENDIAN) | ||
| 71 | uint64_t w; | ||
| 72 | memcpy(&w, src, sizeof w); | ||
| 73 | return w; | ||
| 74 | #else | ||
| 75 | const uint8_t *p = ( const uint8_t * )src; | ||
| 76 | return (( uint64_t )( p[0] ) << 0) | | ||
| 77 | (( uint64_t )( p[1] ) << 8) | | ||
| 78 | (( uint64_t )( p[2] ) << 16) | | ||
| 79 | (( uint64_t )( p[3] ) << 24) | | ||
| 80 | (( uint64_t )( p[4] ) << 32) | | ||
| 81 | (( uint64_t )( p[5] ) << 40) | | ||
| 82 | (( uint64_t )( p[6] ) << 48) | | ||
| 83 | (( uint64_t )( p[7] ) << 56) ; | ||
| 84 | #endif | ||
| 85 | } | ||
| 86 | |||
| 87 | static BLAKE2_INLINE uint16_t load16( const void *src ) | ||
| 88 | { | ||
| 89 | #if defined(NATIVE_LITTLE_ENDIAN) | ||
| 90 | uint16_t w; | ||
| 91 | memcpy(&w, src, sizeof w); | ||
| 92 | return w; | ||
| 93 | #else | ||
| 94 | const uint8_t *p = ( const uint8_t * )src; | ||
| 95 | return ( uint16_t )((( uint32_t )( p[0] ) << 0) | | ||
| 96 | (( uint32_t )( p[1] ) << 8)); | ||
| 97 | #endif | ||
| 98 | } | ||
| 99 | |||
| 100 | static BLAKE2_INLINE void store16( void *dst, uint16_t w ) | ||
| 101 | { | ||
| 102 | #if defined(NATIVE_LITTLE_ENDIAN) | ||
| 103 | memcpy(dst, &w, sizeof w); | ||
| 104 | #else | ||
| 105 | uint8_t *p = ( uint8_t * )dst; | ||
| 106 | *p++ = ( uint8_t )w; w >>= 8; | ||
| 107 | *p++ = ( uint8_t )w; | ||
| 108 | #endif | ||
| 109 | } | ||
| 110 | |||
| 111 | static BLAKE2_INLINE void store32( void *dst, uint32_t w ) | ||
| 112 | { | ||
| 113 | #if defined(NATIVE_LITTLE_ENDIAN) | ||
| 114 | memcpy(dst, &w, sizeof w); | ||
| 115 | #else | ||
| 116 | uint8_t *p = ( uint8_t * )dst; | ||
| 117 | p[0] = (uint8_t)(w >> 0); | ||
| 118 | p[1] = (uint8_t)(w >> 8); | ||
| 119 | p[2] = (uint8_t)(w >> 16); | ||
| 120 | p[3] = (uint8_t)(w >> 24); | ||
| 121 | #endif | ||
| 122 | } | ||
| 123 | |||
| 124 | static BLAKE2_INLINE void store64( void *dst, uint64_t w ) | ||
| 125 | { | ||
| 126 | #if defined(NATIVE_LITTLE_ENDIAN) | ||
| 127 | memcpy(dst, &w, sizeof w); | ||
| 128 | #else | ||
| 129 | uint8_t *p = ( uint8_t * )dst; | ||
| 130 | p[0] = (uint8_t)(w >> 0); | ||
| 131 | p[1] = (uint8_t)(w >> 8); | ||
| 132 | p[2] = (uint8_t)(w >> 16); | ||
| 133 | p[3] = (uint8_t)(w >> 24); | ||
| 134 | p[4] = (uint8_t)(w >> 32); | ||
| 135 | p[5] = (uint8_t)(w >> 40); | ||
| 136 | p[6] = (uint8_t)(w >> 48); | ||
| 137 | p[7] = (uint8_t)(w >> 56); | ||
| 138 | #endif | ||
| 139 | } | ||
| 140 | |||
| 141 | static BLAKE2_INLINE uint64_t load48( const void *src ) | ||
| 142 | { | ||
| 143 | const uint8_t *p = ( const uint8_t * )src; | ||
| 144 | return (( uint64_t )( p[0] ) << 0) | | ||
| 145 | (( uint64_t )( p[1] ) << 8) | | ||
| 146 | (( uint64_t )( p[2] ) << 16) | | ||
| 147 | (( uint64_t )( p[3] ) << 24) | | ||
| 148 | (( uint64_t )( p[4] ) << 32) | | ||
| 149 | (( uint64_t )( p[5] ) << 40) ; | ||
| 150 | } | ||
| 151 | |||
| 152 | static BLAKE2_INLINE void store48( void *dst, uint64_t w ) | ||
| 153 | { | ||
| 154 | uint8_t *p = ( uint8_t * )dst; | ||
| 155 | p[0] = (uint8_t)(w >> 0); | ||
| 156 | p[1] = (uint8_t)(w >> 8); | ||
| 157 | p[2] = (uint8_t)(w >> 16); | ||
| 158 | p[3] = (uint8_t)(w >> 24); | ||
| 159 | p[4] = (uint8_t)(w >> 32); | ||
| 160 | p[5] = (uint8_t)(w >> 40); | ||
| 161 | } | ||
| 162 | |||
| 163 | static BLAKE2_INLINE uint32_t rotr32( const uint32_t w, const unsigned c ) | ||
| 164 | { | ||
| 165 | return ( w >> c ) | ( w << ( 32 - c ) ); | ||
| 166 | } | ||
| 167 | |||
| 168 | static BLAKE2_INLINE uint64_t rotr64( const uint64_t w, const unsigned c ) | ||
| 169 | { | ||
| 170 | return ( w >> c ) | ( w << ( 64 - c ) ); | ||
| 171 | } | ||
| 172 | |||
| 173 | /* prevents compiler optimizing out memset() */ | ||
| 174 | static BLAKE2_INLINE void secure_zero_memory(void *v, size_t n) | ||
| 175 | { | ||
| 176 | static void *(*const volatile memset_v)(void *, int, size_t) = &memset; | ||
| 177 | memset_v(v, 0, n); | ||
| 178 | } | ||
| 179 | |||
| 180 | #endif | ||
| 181 | |||
| 182 | static const uint64_t blake2b_IV[8] = | ||
| 183 | { | ||
| 184 | 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, | ||
| 185 | 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, | ||
| 186 | 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, | ||
| 187 | 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL | ||
| 188 | }; | ||
| 189 | |||
| 190 | static const uint8_t blake2b_sigma[12][16] = | ||
| 191 | { | ||
| 192 | { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , | ||
| 193 | { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , | ||
| 194 | { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , | ||
| 195 | { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , | ||
| 196 | { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , | ||
| 197 | { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , | ||
| 198 | { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , | ||
| 199 | { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , | ||
| 200 | { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , | ||
| 201 | { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , | ||
| 202 | { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , | ||
| 203 | { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } | ||
| 204 | }; | ||
| 205 | |||
| 206 | |||
| 207 | static void blake2b_set_lastnode( blake2b_state *S ) | ||
| 208 | { | ||
| 209 | S->f[1] = (uint64_t)-1; | ||
| 210 | } | ||
| 211 | |||
| 212 | /* Some helper functions, not necessarily useful */ | ||
| 213 | static int blake2b_is_lastblock( const blake2b_state *S ) | ||
| 214 | { | ||
| 215 | return S->f[0] != 0; | ||
| 216 | } | ||
| 217 | |||
| 218 | static void blake2b_set_lastblock( blake2b_state *S ) | ||
| 219 | { | ||
| 220 | if( S->last_node ) blake2b_set_lastnode( S ); | ||
| 221 | |||
| 222 | S->f[0] = (uint64_t)-1; | ||
| 223 | } | ||
| 224 | |||
| 225 | static void blake2b_increment_counter( blake2b_state *S, const uint64_t inc ) | ||
| 226 | { | ||
| 227 | S->t[0] += inc; | ||
| 228 | S->t[1] += ( S->t[0] < inc ); | ||
| 229 | } | ||
| 230 | |||
| 231 | static void blake2b_init0( blake2b_state *S ) | ||
| 232 | { | ||
| 233 | size_t i; | ||
| 234 | memset( S, 0, sizeof( blake2b_state ) ); | ||
| 235 | |||
| 236 | for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i]; | ||
| 237 | } | ||
| 238 | |||
| 239 | /* init xors IV with input parameter block */ | ||
| 240 | int blake2b_init_param( blake2b_state *S, const blake2b_param *P ) | ||
| 241 | { | ||
| 242 | const uint8_t *p = ( const uint8_t * )( P ); | ||
| 243 | size_t i; | ||
| 244 | |||
| 245 | blake2b_init0( S ); | ||
| 246 | |||
| 247 | /* IV XOR ParamBlock */ | ||
| 248 | for( i = 0; i < 8; ++i ) | ||
| 249 | S->h[i] ^= load64( p + sizeof( S->h[i] ) * i ); | ||
| 250 | |||
| 251 | S->outlen = P->digest_length; | ||
| 252 | return 0; | ||
| 253 | } | ||
| 254 | |||
| 255 | |||
| 256 | |||
| 257 | int blake2b_init( blake2b_state *S, size_t outlen ) | ||
| 258 | { | ||
| 259 | blake2b_param P[1]; | ||
| 260 | |||
| 261 | if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; | ||
| 262 | |||
| 263 | P->digest_length = (uint8_t)outlen; | ||
| 264 | P->key_length = 0; | ||
| 265 | P->fanout = 1; | ||
| 266 | P->depth = 1; | ||
| 267 | store32( &P->leaf_length, 0 ); | ||
| 268 | store32( &P->node_offset, 0 ); | ||
| 269 | store32( &P->xof_length, 0 ); | ||
| 270 | P->node_depth = 0; | ||
| 271 | P->inner_length = 0; | ||
| 272 | memset( P->reserved, 0, sizeof( P->reserved ) ); | ||
| 273 | memset( P->salt, 0, sizeof( P->salt ) ); | ||
| 274 | memset( P->personal, 0, sizeof( P->personal ) ); | ||
| 275 | return blake2b_init_param( S, P ); | ||
| 276 | } | ||
| 277 | |||
| 278 | |||
| 279 | int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen ) | ||
| 280 | { | ||
| 281 | blake2b_param P[1]; | ||
| 282 | |||
| 283 | if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; | ||
| 284 | |||
| 285 | if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1; | ||
| 286 | |||
| 287 | P->digest_length = (uint8_t)outlen; | ||
| 288 | P->key_length = (uint8_t)keylen; | ||
| 289 | P->fanout = 1; | ||
| 290 | P->depth = 1; | ||
| 291 | store32( &P->leaf_length, 0 ); | ||
| 292 | store32( &P->node_offset, 0 ); | ||
| 293 | store32( &P->xof_length, 0 ); | ||
| 294 | P->node_depth = 0; | ||
| 295 | P->inner_length = 0; | ||
| 296 | memset( P->reserved, 0, sizeof( P->reserved ) ); | ||
| 297 | memset( P->salt, 0, sizeof( P->salt ) ); | ||
| 298 | memset( P->personal, 0, sizeof( P->personal ) ); | ||
| 299 | |||
| 300 | if( blake2b_init_param( S, P ) < 0 ) return -1; | ||
| 301 | |||
| 302 | { | ||
| 303 | uint8_t block[BLAKE2B_BLOCKBYTES]; | ||
| 304 | memset( block, 0, BLAKE2B_BLOCKBYTES ); | ||
| 305 | memcpy( block, key, keylen ); | ||
| 306 | blake2b_update( S, block, BLAKE2B_BLOCKBYTES ); | ||
| 307 | secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ | ||
| 308 | } | ||
| 309 | return 0; | ||
| 310 | } | ||
| 311 | |||
| 312 | #define G(r,i,a,b,c,d) \ | ||
| 313 | do { \ | ||
| 314 | a = a + b + m[blake2b_sigma[r][2*i+0]]; \ | ||
| 315 | d = rotr64(d ^ a, 32); \ | ||
| 316 | c = c + d; \ | ||
| 317 | b = rotr64(b ^ c, 24); \ | ||
| 318 | a = a + b + m[blake2b_sigma[r][2*i+1]]; \ | ||
| 319 | d = rotr64(d ^ a, 16); \ | ||
| 320 | c = c + d; \ | ||
| 321 | b = rotr64(b ^ c, 63); \ | ||
| 322 | } while(0) | ||
| 323 | |||
| 324 | #define ROUND(r) \ | ||
| 325 | do { \ | ||
| 326 | G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ | ||
| 327 | G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ | ||
| 328 | G(r,2,v[ 2],v[ 6],v[10],v[14]); \ | ||
| 329 | G(r,3,v[ 3],v[ 7],v[11],v[15]); \ | ||
| 330 | G(r,4,v[ 0],v[ 5],v[10],v[15]); \ | ||
| 331 | G(r,5,v[ 1],v[ 6],v[11],v[12]); \ | ||
| 332 | G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ | ||
| 333 | G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ | ||
| 334 | } while(0) | ||
| 335 | |||
| 336 | static void blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] ) | ||
| 337 | { | ||
| 338 | uint64_t m[16]; | ||
| 339 | uint64_t v[16]; | ||
| 340 | size_t i; | ||
| 341 | |||
| 342 | for( i = 0; i < 16; ++i ) { | ||
| 343 | m[i] = load64( block + i * sizeof( m[i] ) ); | ||
| 344 | } | ||
| 345 | |||
| 346 | for( i = 0; i < 8; ++i ) { | ||
| 347 | v[i] = S->h[i]; | ||
| 348 | } | ||
| 349 | |||
| 350 | v[ 8] = blake2b_IV[0]; | ||
| 351 | v[ 9] = blake2b_IV[1]; | ||
| 352 | v[10] = blake2b_IV[2]; | ||
| 353 | v[11] = blake2b_IV[3]; | ||
| 354 | v[12] = blake2b_IV[4] ^ S->t[0]; | ||
| 355 | v[13] = blake2b_IV[5] ^ S->t[1]; | ||
| 356 | v[14] = blake2b_IV[6] ^ S->f[0]; | ||
| 357 | v[15] = blake2b_IV[7] ^ S->f[1]; | ||
| 358 | |||
| 359 | ROUND( 0 ); | ||
| 360 | ROUND( 1 ); | ||
| 361 | ROUND( 2 ); | ||
| 362 | ROUND( 3 ); | ||
| 363 | ROUND( 4 ); | ||
| 364 | ROUND( 5 ); | ||
| 365 | ROUND( 6 ); | ||
| 366 | ROUND( 7 ); | ||
| 367 | ROUND( 8 ); | ||
| 368 | ROUND( 9 ); | ||
| 369 | ROUND( 10 ); | ||
| 370 | ROUND( 11 ); | ||
| 371 | |||
| 372 | for( i = 0; i < 8; ++i ) { | ||
| 373 | S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; | ||
| 374 | } | ||
| 375 | } | ||
| 376 | |||
| 377 | #undef G | ||
| 378 | #undef ROUND | ||
| 379 | |||
| 380 | int blake2b_update( blake2b_state *S, const void *pin, size_t inlen ) | ||
| 381 | { | ||
| 382 | const unsigned char * in = (const unsigned char *)pin; | ||
| 383 | if( inlen > 0 ) | ||
| 384 | { | ||
| 385 | size_t left = S->buflen; | ||
| 386 | size_t fill = BLAKE2B_BLOCKBYTES - left; | ||
| 387 | if( inlen > fill ) | ||
| 388 | { | ||
| 389 | S->buflen = 0; | ||
| 390 | memcpy( S->buf + left, in, fill ); /* Fill buffer */ | ||
| 391 | blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES ); | ||
| 392 | blake2b_compress( S, S->buf ); /* Compress */ | ||
| 393 | in += fill; inlen -= fill; | ||
| 394 | while(inlen > BLAKE2B_BLOCKBYTES) { | ||
| 395 | blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); | ||
| 396 | blake2b_compress( S, in ); | ||
| 397 | in += BLAKE2B_BLOCKBYTES; | ||
| 398 | inlen -= BLAKE2B_BLOCKBYTES; | ||
| 399 | } | ||
| 400 | } | ||
| 401 | memcpy( S->buf + S->buflen, in, inlen ); | ||
| 402 | S->buflen += inlen; | ||
| 403 | } | ||
| 404 | return 0; | ||
| 405 | } | ||
| 406 | |||
| 407 | int blake2b_final( blake2b_state *S, void *out, size_t outlen ) | ||
| 408 | { | ||
| 409 | uint8_t buffer[BLAKE2B_OUTBYTES] = {0}; | ||
| 410 | size_t i; | ||
| 411 | |||
| 412 | if( out == NULL || outlen < S->outlen ) | ||
| 413 | return -1; | ||
| 414 | |||
| 415 | if( blake2b_is_lastblock( S ) ) | ||
| 416 | return -1; | ||
| 417 | |||
| 418 | blake2b_increment_counter( S, S->buflen ); | ||
| 419 | blake2b_set_lastblock( S ); | ||
| 420 | memset( S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */ | ||
| 421 | blake2b_compress( S, S->buf ); | ||
| 422 | |||
| 423 | for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ | ||
| 424 | store64( buffer + sizeof( S->h[i] ) * i, S->h[i] ); | ||
| 425 | |||
| 426 | memcpy( out, buffer, S->outlen ); | ||
| 427 | secure_zero_memory(buffer, sizeof(buffer)); | ||
| 428 | return 0; | ||
| 429 | } | ||
| 430 | |||
| 431 | /* inlen, at least, should be uint64_t. Others can be size_t. */ | ||
| 432 | int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) | ||
| 433 | { | ||
| 434 | blake2b_state S[1]; | ||
| 435 | |||
| 436 | /* Verify parameters */ | ||
| 437 | if ( NULL == in && inlen > 0 ) return -1; | ||
| 438 | |||
| 439 | if ( NULL == out ) return -1; | ||
| 440 | |||
| 441 | if( NULL == key && keylen > 0 ) return -1; | ||
| 442 | |||
| 443 | if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1; | ||
| 444 | |||
| 445 | if( keylen > BLAKE2B_KEYBYTES ) return -1; | ||
| 446 | |||
| 447 | if( keylen > 0 ) | ||
| 448 | { | ||
| 449 | if( blake2b_init_key( S, outlen, key, keylen ) < 0 ) return -1; | ||
| 450 | } | ||
| 451 | else | ||
| 452 | { | ||
| 453 | if( blake2b_init( S, outlen ) < 0 ) return -1; | ||
| 454 | } | ||
| 455 | |||
| 456 | blake2b_update( S, ( const uint8_t * )in, inlen ); | ||
| 457 | blake2b_final( S, out, outlen ); | ||
| 458 | return 0; | ||
| 459 | } | ||
| 460 | |||
| 461 | int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) { | ||
| 462 | return blake2b(out, outlen, in, inlen, key, keylen); | ||
| 463 | } | ||
| 464 | |||
| 465 | #if defined(SUPERCOP) | ||
| 466 | int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen ) | ||
| 467 | { | ||
| 468 | return blake2b( out, BLAKE2B_OUTBYTES, in, inlen, NULL, 0 ); | ||
| 469 | } | ||
| 470 | #endif | ||
| 471 | |||
| 472 | #if defined(BLAKE2B_SELFTEST) | ||
| 473 | #include <string.h> | ||
| 474 | #include "blake2-kat.h" | ||
| 475 | int main( void ) | ||
| 476 | { | ||
| 477 | uint8_t key[BLAKE2B_KEYBYTES]; | ||
| 478 | uint8_t buf[BLAKE2_KAT_LENGTH]; | ||
| 479 | size_t i, step; | ||
| 480 | |||
| 481 | for( i = 0; i < BLAKE2B_KEYBYTES; ++i ) | ||
| 482 | key[i] = ( uint8_t )i; | ||
| 483 | |||
| 484 | for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) | ||
| 485 | buf[i] = ( uint8_t )i; | ||
| 486 | |||
| 487 | /* Test simple API */ | ||
| 488 | for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) | ||
| 489 | { | ||
| 490 | uint8_t hash[BLAKE2B_OUTBYTES]; | ||
| 491 | blake2b( hash, BLAKE2B_OUTBYTES, buf, i, key, BLAKE2B_KEYBYTES ); | ||
| 492 | |||
| 493 | if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) ) | ||
| 494 | { | ||
| 495 | goto fail; | ||
| 496 | } | ||
| 497 | } | ||
| 498 | |||
| 499 | /* Test streaming API */ | ||
| 500 | for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) { | ||
| 501 | for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) { | ||
| 502 | uint8_t hash[BLAKE2B_OUTBYTES]; | ||
| 503 | blake2b_state S; | ||
| 504 | uint8_t * p = buf; | ||
| 505 | size_t mlen = i; | ||
| 506 | int err = 0; | ||
| 507 | |||
| 508 | if( (err = blake2b_init_key(&S, BLAKE2B_OUTBYTES, key, BLAKE2B_KEYBYTES)) < 0 ) { | ||
| 509 | goto fail; | ||
| 510 | } | ||
| 511 | |||
| 512 | while (mlen >= step) { | ||
| 513 | if ( (err = blake2b_update(&S, p, step)) < 0 ) { | ||
| 514 | goto fail; | ||
| 515 | } | ||
| 516 | mlen -= step; | ||
| 517 | p += step; | ||
| 518 | } | ||
| 519 | if ( (err = blake2b_update(&S, p, mlen)) < 0) { | ||
| 520 | goto fail; | ||
| 521 | } | ||
| 522 | if ( (err = blake2b_final(&S, hash, BLAKE2B_OUTBYTES)) < 0) { | ||
| 523 | goto fail; | ||
| 524 | } | ||
| 525 | |||
| 526 | if (0 != memcmp(hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES)) { | ||
| 527 | goto fail; | ||
| 528 | } | ||
| 529 | } | ||
| 530 | } | ||
| 531 | |||
| 532 | puts( "ok" ); | ||
| 533 | return 0; | ||
| 534 | fail: | ||
| 535 | puts("error"); | ||
| 536 | return -1; | ||
| 537 | } | ||
| 538 | #endif | ||
| 539 | |||
src/buffer.hpp+4| ... | @@ -78,6 +78,10 @@ static inline Buf *buf_create_from_mem(const char *ptr, size_t len) { | ... | @@ -78,6 +78,10 @@ static inline Buf *buf_create_from_mem(const char *ptr, size_t len) { |
| 78 | return buf; | 78 | return buf; |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | static inline Buf *buf_create_from_slice(Slice<uint8_t> slice) { | ||
| 82 | return buf_create_from_mem((const char *)slice.ptr, slice.len); | ||
| 83 | } | ||
| 84 | |||
| 81 | static inline Buf *buf_create_from_str(const char *str) { | 85 | static inline Buf *buf_create_from_str(const char *str) { |
| 82 | return buf_create_from_mem(str, strlen(str)); | 86 | return buf_create_from_mem(str, strlen(str)); |
| 83 | } | 87 | } |
src/cache_hash.cpp created+469| ... | @@ -0,0 +1,469 @@ | ||
| 1 | /* | ||
| 2 | * Copyright (c) 2018 Andrew Kelley | ||
| 3 | * | ||
| 4 | * This file is part of zig, which is MIT licensed. | ||
| 5 | * See http://opensource.org/licenses/MIT | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include "cache_hash.hpp" | ||
| 9 | #include "all_types.hpp" | ||
| 10 | #include "buffer.hpp" | ||
| 11 | #include "os.hpp" | ||
| 12 | |||
| 13 | #include <stdio.h> | ||
| 14 | |||
| 15 | void cache_init(CacheHash *ch, Buf *manifest_dir) { | ||
| 16 | int rc = blake2b_init(&ch->blake, 48); | ||
| 17 | assert(rc == 0); | ||
| 18 | ch->files = {}; | ||
| 19 | ch->manifest_dir = manifest_dir; | ||
| 20 | ch->manifest_file_path = nullptr; | ||
| 21 | ch->manifest_dirty = false; | ||
| 22 | } | ||
| 23 | |||
| 24 | void cache_str(CacheHash *ch, const char *ptr) { | ||
| 25 | assert(ch->manifest_file_path == nullptr); | ||
| 26 | assert(ptr != nullptr); | ||
| 27 | // + 1 to include the null byte | ||
| 28 | blake2b_update(&ch->blake, ptr, strlen(ptr) + 1); | ||
| 29 | } | ||
| 30 | |||
| 31 | void cache_int(CacheHash *ch, int x) { | ||
| 32 | assert(ch->manifest_file_path == nullptr); | ||
| 33 | // + 1 to include the null byte | ||
| 34 | uint8_t buf[sizeof(int) + 1]; | ||
| 35 | memcpy(buf, &x, sizeof(int)); | ||
| 36 | buf[sizeof(int)] = 0; | ||
| 37 | blake2b_update(&ch->blake, buf, sizeof(int) + 1); | ||
| 38 | } | ||
| 39 | |||
| 40 | void cache_usize(CacheHash *ch, size_t x) { | ||
| 41 | assert(ch->manifest_file_path == nullptr); | ||
| 42 | // + 1 to include the null byte | ||
| 43 | uint8_t buf[sizeof(size_t) + 1]; | ||
| 44 | memcpy(buf, &x, sizeof(size_t)); | ||
| 45 | buf[sizeof(size_t)] = 0; | ||
| 46 | blake2b_update(&ch->blake, buf, sizeof(size_t) + 1); | ||
| 47 | } | ||
| 48 | |||
| 49 | void cache_bool(CacheHash *ch, bool x) { | ||
| 50 | assert(ch->manifest_file_path == nullptr); | ||
| 51 | blake2b_update(&ch->blake, &x, 1); | ||
| 52 | } | ||
| 53 | |||
| 54 | void cache_buf(CacheHash *ch, Buf *buf) { | ||
| 55 | assert(ch->manifest_file_path == nullptr); | ||
| 56 | assert(buf != nullptr); | ||
| 57 | // + 1 to include the null byte | ||
| 58 | blake2b_update(&ch->blake, buf_ptr(buf), buf_len(buf) + 1); | ||
| 59 | } | ||
| 60 | |||
| 61 | void cache_buf_opt(CacheHash *ch, Buf *buf) { | ||
| 62 | assert(ch->manifest_file_path == nullptr); | ||
| 63 | if (buf == nullptr) { | ||
| 64 | cache_str(ch, ""); | ||
| 65 | cache_str(ch, ""); | ||
| 66 | } else { | ||
| 67 | cache_buf(ch, buf); | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | void cache_list_of_link_lib(CacheHash *ch, LinkLib **ptr, size_t len) { | ||
| 72 | assert(ch->manifest_file_path == nullptr); | ||
| 73 | for (size_t i = 0; i < len; i += 1) { | ||
| 74 | LinkLib *lib = ptr[i]; | ||
| 75 | if (lib->provided_explicitly) { | ||
| 76 | cache_buf(ch, lib->name); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | cache_str(ch, ""); | ||
| 80 | } | ||
| 81 | |||
| 82 | void cache_list_of_buf(CacheHash *ch, Buf **ptr, size_t len) { | ||
| 83 | assert(ch->manifest_file_path == nullptr); | ||
| 84 | for (size_t i = 0; i < len; i += 1) { | ||
| 85 | Buf *buf = ptr[i]; | ||
| 86 | cache_buf(ch, buf); | ||
| 87 | } | ||
| 88 | cache_str(ch, ""); | ||
| 89 | } | ||
| 90 | |||
| 91 | void cache_list_of_file(CacheHash *ch, Buf **ptr, size_t len) { | ||
| 92 | assert(ch->manifest_file_path == nullptr); | ||
| 93 | |||
| 94 | for (size_t i = 0; i < len; i += 1) { | ||
| 95 | Buf *buf = ptr[i]; | ||
| 96 | cache_file(ch, buf); | ||
| 97 | } | ||
| 98 | cache_str(ch, ""); | ||
| 99 | } | ||
| 100 | |||
| 101 | void cache_list_of_str(CacheHash *ch, const char **ptr, size_t len) { | ||
| 102 | assert(ch->manifest_file_path == nullptr); | ||
| 103 | |||
| 104 | for (size_t i = 0; i < len; i += 1) { | ||
| 105 | const char *s = ptr[i]; | ||
| 106 | cache_str(ch, s); | ||
| 107 | } | ||
| 108 | cache_str(ch, ""); | ||
| 109 | } | ||
| 110 | |||
| 111 | void cache_file(CacheHash *ch, Buf *file_path) { | ||
| 112 | assert(ch->manifest_file_path == nullptr); | ||
| 113 | assert(file_path != nullptr); | ||
| 114 | Buf *resolved_path = buf_alloc(); | ||
| 115 | *resolved_path = os_path_resolve(&file_path, 1); | ||
| 116 | CacheHashFile *chf = ch->files.add_one(); | ||
| 117 | chf->path = resolved_path; | ||
| 118 | cache_buf(ch, resolved_path); | ||
| 119 | } | ||
| 120 | |||
| 121 | void cache_file_opt(CacheHash *ch, Buf *file_path) { | ||
| 122 | assert(ch->manifest_file_path == nullptr); | ||
| 123 | if (file_path == nullptr) { | ||
| 124 | cache_str(ch, ""); | ||
| 125 | cache_str(ch, ""); | ||
| 126 | } else { | ||
| 127 | cache_file(ch, file_path); | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | // Ported from std/base64.zig | ||
| 132 | static uint8_t base64_fs_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; | ||
| 133 | static void base64_encode(Slice<uint8_t> dest, Slice<uint8_t> source) { | ||
| 134 | size_t dest_len = ((source.len + 2) / 3) * 4; | ||
| 135 | assert(dest.len == dest_len); | ||
| 136 | |||
| 137 | size_t i = 0; | ||
| 138 | size_t out_index = 0; | ||
| 139 | for (; i + 2 < source.len; i += 3) { | ||
| 140 | dest.ptr[out_index] = base64_fs_alphabet[(source.ptr[i] >> 2) & 0x3f]; | ||
| 141 | out_index += 1; | ||
| 142 | |||
| 143 | dest.ptr[out_index] = base64_fs_alphabet[((source.ptr[i] & 0x3) << 4) | ((source.ptr[i + 1] & 0xf0) >> 4)]; | ||
| 144 | out_index += 1; | ||
| 145 | |||
| 146 | dest.ptr[out_index] = base64_fs_alphabet[((source.ptr[i + 1] & 0xf) << 2) | ((source.ptr[i + 2] & 0xc0) >> 6)]; | ||
| 147 | out_index += 1; | ||
| 148 | |||
| 149 | dest.ptr[out_index] = base64_fs_alphabet[source.ptr[i + 2] & 0x3f]; | ||
| 150 | out_index += 1; | ||
| 151 | } | ||
| 152 | |||
| 153 | // Assert that we never need pad characters. | ||
| 154 | assert(i == source.len); | ||
| 155 | } | ||
| 156 | |||
| 157 | // Ported from std/base64.zig | ||
| 158 | static Error base64_decode(Slice<uint8_t> dest, Slice<uint8_t> source) { | ||
| 159 | assert(source.len % 4 == 0); | ||
| 160 | assert(dest.len == (source.len / 4) * 3); | ||
| 161 | |||
| 162 | // In Zig this is comptime computed. In C++ it's not worth it to do that. | ||
| 163 | uint8_t char_to_index[256]; | ||
| 164 | bool char_in_alphabet[256] = {0}; | ||
| 165 | for (size_t i = 0; i < 64; i += 1) { | ||
| 166 | uint8_t c = base64_fs_alphabet[i]; | ||
| 167 | assert(!char_in_alphabet[c]); | ||
| 168 | char_in_alphabet[c] = true; | ||
| 169 | char_to_index[c] = i; | ||
| 170 | } | ||
| 171 | |||
| 172 | size_t src_cursor = 0; | ||
| 173 | size_t dest_cursor = 0; | ||
| 174 | |||
| 175 | for (;src_cursor < source.len; src_cursor += 4) { | ||
| 176 | if (!char_in_alphabet[source.ptr[src_cursor + 0]]) return ErrorInvalidFormat; | ||
| 177 | if (!char_in_alphabet[source.ptr[src_cursor + 1]]) return ErrorInvalidFormat; | ||
| 178 | if (!char_in_alphabet[source.ptr[src_cursor + 2]]) return ErrorInvalidFormat; | ||
| 179 | if (!char_in_alphabet[source.ptr[src_cursor + 3]]) return ErrorInvalidFormat; | ||
| 180 | dest.ptr[dest_cursor + 0] = (char_to_index[source.ptr[src_cursor + 0]] << 2) | (char_to_index[source.ptr[src_cursor + 1]] >> 4); | ||
| 181 | dest.ptr[dest_cursor + 1] = (char_to_index[source.ptr[src_cursor + 1]] << 4) | (char_to_index[source.ptr[src_cursor + 2]] >> 2); | ||
| 182 | dest.ptr[dest_cursor + 2] = (char_to_index[source.ptr[src_cursor + 2]] << 6) | (char_to_index[source.ptr[src_cursor + 3]]); | ||
| 183 | dest_cursor += 3; | ||
| 184 | } | ||
| 185 | |||
| 186 | assert(src_cursor == source.len); | ||
| 187 | assert(dest_cursor == dest.len); | ||
| 188 | return ErrorNone; | ||
| 189 | } | ||
| 190 | |||
| 191 | static Error hash_file(uint8_t *digest, OsFile handle, Buf *contents) { | ||
| 192 | Error err; | ||
| 193 | |||
| 194 | if (contents) { | ||
| 195 | buf_resize(contents, 0); | ||
| 196 | } | ||
| 197 | |||
| 198 | blake2b_state blake; | ||
| 199 | int rc = blake2b_init(&blake, 48); | ||
| 200 | assert(rc == 0); | ||
| 201 | |||
| 202 | for (;;) { | ||
| 203 | uint8_t buf[4096]; | ||
| 204 | size_t amt = 4096; | ||
| 205 | if ((err = os_file_read(handle, buf, &amt))) | ||
| 206 | return err; | ||
| 207 | if (amt == 0) { | ||
| 208 | rc = blake2b_final(&blake, digest, 48); | ||
| 209 | assert(rc == 0); | ||
| 210 | return ErrorNone; | ||
| 211 | } | ||
| 212 | blake2b_update(&blake, buf, amt); | ||
| 213 | if (contents) { | ||
| 214 | buf_append_mem(contents, (char*)buf, amt); | ||
| 215 | } | ||
| 216 | } | ||
| 217 | } | ||
| 218 | |||
| 219 | static Error populate_file_hash(CacheHash *ch, CacheHashFile *chf, Buf *contents) { | ||
| 220 | Error err; | ||
| 221 | |||
| 222 | assert(chf->path != nullptr); | ||
| 223 | |||
| 224 | OsFile this_file; | ||
| 225 | if ((err = os_file_open_r(chf->path, &this_file))) | ||
| 226 | return err; | ||
| 227 | |||
| 228 | if ((err = os_file_mtime(this_file, &chf->mtime))) { | ||
| 229 | os_file_close(this_file); | ||
| 230 | return err; | ||
| 231 | } | ||
| 232 | |||
| 233 | if ((err = hash_file(chf->bin_digest, this_file, contents))) { | ||
| 234 | os_file_close(this_file); | ||
| 235 | return err; | ||
| 236 | } | ||
| 237 | os_file_close(this_file); | ||
| 238 | |||
| 239 | blake2b_update(&ch->blake, chf->bin_digest, 48); | ||
| 240 | |||
| 241 | return ErrorNone; | ||
| 242 | } | ||
| 243 | |||
| 244 | Error cache_hit(CacheHash *ch, Buf *out_digest) { | ||
| 245 | Error err; | ||
| 246 | |||
| 247 | uint8_t bin_digest[48]; | ||
| 248 | int rc = blake2b_final(&ch->blake, bin_digest, 48); | ||
| 249 | assert(rc == 0); | ||
| 250 | |||
| 251 | if (ch->files.length == 0) { | ||
| 252 | buf_resize(out_digest, 64); | ||
| 253 | base64_encode(buf_to_slice(out_digest), {bin_digest, 48}); | ||
| 254 | return ErrorNone; | ||
| 255 | } | ||
| 256 | |||
| 257 | Buf b64_digest = BUF_INIT; | ||
| 258 | buf_resize(&b64_digest, 64); | ||
| 259 | base64_encode(buf_to_slice(&b64_digest), {bin_digest, 48}); | ||
| 260 | |||
| 261 | rc = blake2b_init(&ch->blake, 48); | ||
| 262 | assert(rc == 0); | ||
| 263 | blake2b_update(&ch->blake, bin_digest, 48); | ||
| 264 | |||
| 265 | ch->manifest_file_path = buf_alloc(); | ||
| 266 | os_path_join(ch->manifest_dir, &b64_digest, ch->manifest_file_path); | ||
| 267 | |||
| 268 | buf_append_str(ch->manifest_file_path, ".txt"); | ||
| 269 | |||
| 270 | if ((err = os_make_path(ch->manifest_dir))) | ||
| 271 | return err; | ||
| 272 | |||
| 273 | if ((err = os_file_open_lock_rw(ch->manifest_file_path, &ch->manifest_file))) | ||
| 274 | return err; | ||
| 275 | |||
| 276 | Buf line_buf = BUF_INIT; | ||
| 277 | buf_resize(&line_buf, 512); | ||
| 278 | if ((err = os_file_read_all(ch->manifest_file, &line_buf))) { | ||
| 279 | os_file_close(ch->manifest_file); | ||
| 280 | return err; | ||
| 281 | } | ||
| 282 | |||
| 283 | size_t input_file_count = ch->files.length; | ||
| 284 | bool any_file_changed = false; | ||
| 285 | size_t file_i = 0; | ||
| 286 | SplitIterator line_it = memSplit(buf_to_slice(&line_buf), str("\n")); | ||
| 287 | for (;; file_i += 1) { | ||
| 288 | Optional<Slice<uint8_t>> opt_line = SplitIterator_next(&line_it); | ||
| 289 | if (!opt_line.is_some) | ||
| 290 | break; | ||
| 291 | |||
| 292 | CacheHashFile *chf; | ||
| 293 | if (file_i < input_file_count) { | ||
| 294 | chf = &ch->files.at(file_i); | ||
| 295 | } else if (any_file_changed) { | ||
| 296 | // cache miss. | ||
| 297 | // keep the the manifest file open with the rw lock | ||
| 298 | // reset the hash | ||
| 299 | rc = blake2b_init(&ch->blake, 48); | ||
| 300 | assert(rc == 0); | ||
| 301 | blake2b_update(&ch->blake, bin_digest, 48); | ||
| 302 | ch->files.resize(input_file_count); | ||
| 303 | // bring the hash up to the input file hashes | ||
| 304 | for (file_i = 0; file_i < input_file_count; file_i += 1) { | ||
| 305 | blake2b_update(&ch->blake, ch->files.at(file_i).bin_digest, 48); | ||
| 306 | } | ||
| 307 | // caller can notice that out_digest is unmodified. | ||
| 308 | return ErrorNone; | ||
| 309 | } else { | ||
| 310 | chf = ch->files.add_one(); | ||
| 311 | chf->path = nullptr; | ||
| 312 | } | ||
| 313 | |||
| 314 | SplitIterator it = memSplit(opt_line.value, str(" ")); | ||
| 315 | |||
| 316 | Optional<Slice<uint8_t>> opt_mtime_sec = SplitIterator_next(&it); | ||
| 317 | if (!opt_mtime_sec.is_some) { | ||
| 318 | os_file_close(ch->manifest_file); | ||
| 319 | return ErrorInvalidFormat; | ||
| 320 | } | ||
| 321 | chf->mtime.sec = strtoull((const char *)opt_mtime_sec.value.ptr, nullptr, 10); | ||
| 322 | |||
| 323 | Optional<Slice<uint8_t>> opt_mtime_nsec = SplitIterator_next(&it); | ||
| 324 | if (!opt_mtime_nsec.is_some) { | ||
| 325 | os_file_close(ch->manifest_file); | ||
| 326 | return ErrorInvalidFormat; | ||
| 327 | } | ||
| 328 | chf->mtime.nsec = strtoull((const char *)opt_mtime_nsec.value.ptr, nullptr, 10); | ||
| 329 | |||
| 330 | Optional<Slice<uint8_t>> opt_digest = SplitIterator_next(&it); | ||
| 331 | if (!opt_digest.is_some) { | ||
| 332 | os_file_close(ch->manifest_file); | ||
| 333 | return ErrorInvalidFormat; | ||
| 334 | } | ||
| 335 | if ((err = base64_decode({chf->bin_digest, 48}, opt_digest.value))) { | ||
| 336 | os_file_close(ch->manifest_file); | ||
| 337 | return ErrorInvalidFormat; | ||
| 338 | } | ||
| 339 | |||
| 340 | Optional<Slice<uint8_t>> opt_file_path = SplitIterator_next(&it); | ||
| 341 | if (!opt_file_path.is_some) { | ||
| 342 | os_file_close(ch->manifest_file); | ||
| 343 | return ErrorInvalidFormat; | ||
| 344 | } | ||
| 345 | Buf *this_path = buf_create_from_slice(opt_file_path.value); | ||
| 346 | if (chf->path != nullptr && !buf_eql_buf(this_path, chf->path)) { | ||
| 347 | os_file_close(ch->manifest_file); | ||
| 348 | return ErrorInvalidFormat; | ||
| 349 | } | ||
| 350 | chf->path = this_path; | ||
| 351 | |||
| 352 | // if the mtime matches we can trust the digest | ||
| 353 | OsFile this_file; | ||
| 354 | if ((err = os_file_open_r(chf->path, &this_file))) { | ||
| 355 | os_file_close(ch->manifest_file); | ||
| 356 | return err; | ||
| 357 | } | ||
| 358 | OsTimeStamp actual_mtime; | ||
| 359 | if ((err = os_file_mtime(this_file, &actual_mtime))) { | ||
| 360 | os_file_close(this_file); | ||
| 361 | os_file_close(ch->manifest_file); | ||
| 362 | return err; | ||
| 363 | } | ||
| 364 | if (chf->mtime.sec == actual_mtime.sec && chf->mtime.nsec == actual_mtime.nsec) { | ||
| 365 | os_file_close(this_file); | ||
| 366 | } else { | ||
| 367 | // we have to recompute the digest. | ||
| 368 | // later we'll rewrite the manifest with the new mtime/digest values | ||
| 369 | ch->manifest_dirty = true; | ||
| 370 | chf->mtime = actual_mtime; | ||
| 371 | |||
| 372 | uint8_t actual_digest[48]; | ||
| 373 | if ((err = hash_file(actual_digest, this_file, nullptr))) { | ||
| 374 | os_file_close(this_file); | ||
| 375 | os_file_close(ch->manifest_file); | ||
| 376 | return err; | ||
| 377 | } | ||
| 378 | os_file_close(this_file); | ||
| 379 | if (memcmp(chf->bin_digest, actual_digest, 48) != 0) { | ||
| 380 | memcpy(chf->bin_digest, actual_digest, 48); | ||
| 381 | // keep going until we have the input file digests | ||
| 382 | any_file_changed = true; | ||
| 383 | } | ||
| 384 | } | ||
| 385 | if (!any_file_changed) { | ||
| 386 | blake2b_update(&ch->blake, chf->bin_digest, 48); | ||
| 387 | } | ||
| 388 | } | ||
| 389 | if (file_i < input_file_count) { | ||
| 390 | // manifest file is empty or missing entries, so this is a cache miss | ||
| 391 | ch->manifest_dirty = true; | ||
| 392 | for (; file_i < input_file_count; file_i += 1) { | ||
| 393 | CacheHashFile *chf = &ch->files.at(file_i); | ||
| 394 | if ((err = populate_file_hash(ch, chf, nullptr))) { | ||
| 395 | os_file_close(ch->manifest_file); | ||
| 396 | return err; | ||
| 397 | } | ||
| 398 | } | ||
| 399 | return ErrorNone; | ||
| 400 | } | ||
| 401 | // Cache Hit | ||
| 402 | return cache_final(ch, out_digest); | ||
| 403 | } | ||
| 404 | |||
| 405 | Error cache_add_file_fetch(CacheHash *ch, Buf *resolved_path, Buf *contents) { | ||
| 406 | Error err; | ||
| 407 | |||
| 408 | assert(ch->manifest_file_path != nullptr); | ||
| 409 | CacheHashFile *chf = ch->files.add_one(); | ||
| 410 | chf->path = resolved_path; | ||
| 411 | if ((err = populate_file_hash(ch, chf, contents))) { | ||
| 412 | os_file_close(ch->manifest_file); | ||
| 413 | return err; | ||
| 414 | } | ||
| 415 | |||
| 416 | return ErrorNone; | ||
| 417 | } | ||
| 418 | |||
| 419 | Error cache_add_file(CacheHash *ch, Buf *path) { | ||
| 420 | Buf *resolved_path = buf_alloc(); | ||
| 421 | *resolved_path = os_path_resolve(&path, 1); | ||
| 422 | return cache_add_file_fetch(ch, resolved_path, nullptr); | ||
| 423 | } | ||
| 424 | |||
| 425 | static Error write_manifest_file(CacheHash *ch) { | ||
| 426 | Error err; | ||
| 427 | Buf contents = BUF_INIT; | ||
| 428 | buf_resize(&contents, 0); | ||
| 429 | uint8_t encoded_digest[65]; | ||
| 430 | encoded_digest[64] = 0; | ||
| 431 | for (size_t i = 0; i < ch->files.length; i += 1) { | ||
| 432 | CacheHashFile *chf = &ch->files.at(i); | ||
| 433 | base64_encode({encoded_digest, 64}, {chf->bin_digest, 48}); | ||
| 434 | buf_appendf(&contents, "%" ZIG_PRI_u64 " %" ZIG_PRI_u64 " %s %s\n", | ||
| 435 | chf->mtime.sec, chf->mtime.nsec, encoded_digest, buf_ptr(chf->path)); | ||
| 436 | } | ||
| 437 | if ((err = os_file_overwrite(ch->manifest_file, &contents))) | ||
| 438 | return err; | ||
| 439 | |||
| 440 | return ErrorNone; | ||
| 441 | } | ||
| 442 | |||
| 443 | Error cache_final(CacheHash *ch, Buf *out_digest) { | ||
| 444 | Error err; | ||
| 445 | |||
| 446 | assert(ch->manifest_file_path != nullptr); | ||
| 447 | |||
| 448 | if (ch->manifest_dirty) { | ||
| 449 | if ((err = write_manifest_file(ch))) { | ||
| 450 | fprintf(stderr, "Warning: Unable to write cache file '%s': %s\n", | ||
| 451 | buf_ptr(ch->manifest_file_path), err_str(err)); | ||
| 452 | } | ||
| 453 | } | ||
| 454 | // We don't close the manifest file yet, because we want to | ||
| 455 | // keep it locked until the API user is done using it. | ||
| 456 | |||
| 457 | uint8_t bin_digest[48]; | ||
| 458 | int rc = blake2b_final(&ch->blake, bin_digest, 48); | ||
| 459 | assert(rc == 0); | ||
| 460 | buf_resize(out_digest, 64); | ||
| 461 | base64_encode(buf_to_slice(out_digest), {bin_digest, 48}); | ||
| 462 | |||
| 463 | return ErrorNone; | ||
| 464 | } | ||
| 465 | |||
| 466 | void cache_release(CacheHash *ch) { | ||
| 467 | assert(ch->manifest_file_path != nullptr); | ||
| 468 | os_file_close(ch->manifest_file); | ||
| 469 | } | ||
src/cache_hash.hpp created+71| ... | @@ -0,0 +1,71 @@ | ||
| 1 | /* | ||
| 2 | * Copyright (c) 2018 Andrew Kelley | ||
| 3 | * | ||
| 4 | * This file is part of zig, which is MIT licensed. | ||
| 5 | * See http://opensource.org/licenses/MIT | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef ZIG_CACHE_HASH_HPP | ||
| 9 | #define ZIG_CACHE_HASH_HPP | ||
| 10 | |||
| 11 | #include "blake2.h" | ||
| 12 | #include "os.hpp" | ||
| 13 | |||
| 14 | struct LinkLib; | ||
| 15 | |||
| 16 | struct CacheHashFile { | ||
| 17 | Buf *path; | ||
| 18 | OsTimeStamp mtime; | ||
| 19 | uint8_t bin_digest[48]; | ||
| 20 | Buf *contents; | ||
| 21 | }; | ||
| 22 | |||
| 23 | struct CacheHash { | ||
| 24 | blake2b_state blake; | ||
| 25 | ZigList<CacheHashFile> files; | ||
| 26 | Buf *manifest_dir; | ||
| 27 | Buf *manifest_file_path; | ||
| 28 | OsFile manifest_file; | ||
| 29 | bool manifest_dirty; | ||
| 30 | }; | ||
| 31 | |||
| 32 | // Always call this first to set up. | ||
| 33 | void cache_init(CacheHash *ch, Buf *manifest_dir); | ||
| 34 | |||
| 35 | // Next, use the hash population functions to add the initial parameters. | ||
| 36 | void cache_str(CacheHash *ch, const char *ptr); | ||
| 37 | void cache_int(CacheHash *ch, int x); | ||
| 38 | void cache_bool(CacheHash *ch, bool x); | ||
| 39 | void cache_usize(CacheHash *ch, size_t x); | ||
| 40 | void cache_buf(CacheHash *ch, Buf *buf); | ||
| 41 | void cache_buf_opt(CacheHash *ch, Buf *buf); | ||
| 42 | void cache_list_of_link_lib(CacheHash *ch, LinkLib **ptr, size_t len); | ||
| 43 | void cache_list_of_buf(CacheHash *ch, Buf **ptr, size_t len); | ||
| 44 | void cache_list_of_file(CacheHash *ch, Buf **ptr, size_t len); | ||
| 45 | void cache_list_of_str(CacheHash *ch, const char **ptr, size_t len); | ||
| 46 | void cache_file(CacheHash *ch, Buf *path); | ||
| 47 | void cache_file_opt(CacheHash *ch, Buf *path); | ||
| 48 | |||
| 49 | // Then call cache_hit when you're ready to see if you can skip the next step. | ||
| 50 | // out_b64_digest will be left unchanged if it was a cache miss. | ||
| 51 | // If you got a cache hit, the next step is cache_release. | ||
| 52 | // From this point on, there is a lock on the input params. Release | ||
| 53 | // the lock with cache_release. | ||
| 54 | Error ATTRIBUTE_MUST_USE cache_hit(CacheHash *ch, Buf *out_b64_digest); | ||
| 55 | |||
| 56 | // If you did not get a cache hit, call this function for every file | ||
| 57 | // that is depended on, and then finish with cache_final. | ||
| 58 | Error ATTRIBUTE_MUST_USE cache_add_file(CacheHash *ch, Buf *path); | ||
| 59 | |||
| 60 | // This variant of cache_add_file returns the file contents. | ||
| 61 | // Also the file path argument must be already resolved. | ||
| 62 | Error ATTRIBUTE_MUST_USE cache_add_file_fetch(CacheHash *ch, Buf *resolved_path, Buf *contents); | ||
| 63 | |||
| 64 | // out_b64_digest will be the same thing that cache_hit returns if you got a cache hit | ||
| 65 | Error ATTRIBUTE_MUST_USE cache_final(CacheHash *ch, Buf *out_b64_digest); | ||
| 66 | |||
| 67 | // Until this function is called, no one will be able to get a lock on your input params. | ||
| 68 | void cache_release(CacheHash *ch); | ||
| 69 | |||
| 70 | |||
| 71 | #endif | ||
src/codegen.cpp+328-96| ... | @@ -8,12 +8,12 @@ | ... | @@ -8,12 +8,12 @@ |
| 8 | #include "analyze.hpp" | 8 | #include "analyze.hpp" |
| 9 | #include "ast_render.hpp" | 9 | #include "ast_render.hpp" |
| 10 | #include "codegen.hpp" | 10 | #include "codegen.hpp" |
| 11 | #include "compiler.hpp" | ||
| 11 | #include "config.h" | 12 | #include "config.h" |
| 12 | #include "errmsg.hpp" | 13 | #include "errmsg.hpp" |
| 13 | #include "error.hpp" | 14 | #include "error.hpp" |
| 14 | #include "hash_map.hpp" | 15 | #include "hash_map.hpp" |
| 15 | #include "ir.hpp" | 16 | #include "ir.hpp" |
| 16 | #include "link.hpp" | ||
| 17 | #include "os.hpp" | 17 | #include "os.hpp" |
| 18 | #include "translate_c.hpp" | 18 | #include "translate_c.hpp" |
| 19 | #include "target.hpp" | 19 | #include "target.hpp" |
| ... | @@ -183,14 +183,14 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out | ... | @@ -183,14 +183,14 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out |
| 183 | return g; | 183 | return g; |
| 184 | } | 184 | } |
| 185 | 185 | ||
| 186 | void codegen_destroy(CodeGen *codegen) { | ||
| 187 | LLVMDisposeTargetMachine(codegen->target_machine); | ||
| 188 | } | ||
| 189 | |||
| 190 | void codegen_set_output_h_path(CodeGen *g, Buf *h_path) { | 186 | void codegen_set_output_h_path(CodeGen *g, Buf *h_path) { |
| 191 | g->out_h_path = h_path; | 187 | g->out_h_path = h_path; |
| 192 | } | 188 | } |
| 193 | 189 | ||
| 190 | void codegen_set_output_path(CodeGen *g, Buf *path) { | ||
| 191 | g->wanted_output_file_path = path; | ||
| 192 | } | ||
| 193 | |||
| 194 | void codegen_set_clang_argv(CodeGen *g, const char **args, size_t len) { | 194 | void codegen_set_clang_argv(CodeGen *g, const char **args, size_t len) { |
| 195 | g->clang_argv = args; | 195 | g->clang_argv = args; |
| 196 | g->clang_argv_len = len; | 196 | g->clang_argv_len = len; |
| ... | @@ -243,10 +243,6 @@ void codegen_set_out_name(CodeGen *g, Buf *out_name) { | ... | @@ -243,10 +243,6 @@ void codegen_set_out_name(CodeGen *g, Buf *out_name) { |
| 243 | g->root_out_name = out_name; | 243 | g->root_out_name = out_name; |
| 244 | } | 244 | } |
| 245 | 245 | ||
| 246 | void codegen_set_cache_dir(CodeGen *g, Buf cache_dir) { | ||
| 247 | g->cache_dir = cache_dir; | ||
| 248 | } | ||
| 249 | |||
| 250 | void codegen_set_libc_lib_dir(CodeGen *g, Buf *libc_lib_dir) { | 246 | void codegen_set_libc_lib_dir(CodeGen *g, Buf *libc_lib_dir) { |
| 251 | g->libc_lib_dir = libc_lib_dir; | 247 | g->libc_lib_dir = libc_lib_dir; |
| 252 | } | 248 | } |
| ... | @@ -6076,13 +6072,6 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val, | ... | @@ -6076,13 +6072,6 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val, |
| 6076 | // TODO ^^ make an actual global variable | 6072 | // TODO ^^ make an actual global variable |
| 6077 | } | 6073 | } |
| 6078 | 6074 | ||
| 6079 | static void ensure_cache_dir(CodeGen *g) { | ||
| 6080 | int err; | ||
| 6081 | if ((err = os_make_path(&g->cache_dir))) { | ||
| 6082 | zig_panic("unable to make cache dir: %s", err_str(err)); | ||
| 6083 | } | ||
| 6084 | } | ||
| 6085 | |||
| 6086 | static void validate_inline_fns(CodeGen *g) { | 6075 | static void validate_inline_fns(CodeGen *g) { |
| 6087 | for (size_t i = 0; i < g->inline_fns.length; i += 1) { | 6076 | for (size_t i = 0; i < g->inline_fns.length; i += 1) { |
| 6088 | ZigFn *fn_entry = g->inline_fns.at(i); | 6077 | ZigFn *fn_entry = g->inline_fns.at(i); |
| ... | @@ -6097,8 +6086,6 @@ static void validate_inline_fns(CodeGen *g) { | ... | @@ -6097,8 +6086,6 @@ static void validate_inline_fns(CodeGen *g) { |
| 6097 | static void do_code_gen(CodeGen *g) { | 6086 | static void do_code_gen(CodeGen *g) { |
| 6098 | assert(!g->errors.length); | 6087 | assert(!g->errors.length); |
| 6099 | 6088 | ||
| 6100 | codegen_add_time_event(g, "Code Generation"); | ||
| 6101 | |||
| 6102 | { | 6089 | { |
| 6103 | // create debug type for error sets | 6090 | // create debug type for error sets |
| 6104 | assert(g->err_enumerators.length == g->errors_by_index.length); | 6091 | assert(g->err_enumerators.length == g->errors_by_index.length); |
| ... | @@ -6401,45 +6388,18 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -6401,45 +6388,18 @@ static void do_code_gen(CodeGen *g) { |
| 6401 | char *error = nullptr; | 6388 | char *error = nullptr; |
| 6402 | LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error); | 6389 | LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error); |
| 6403 | #endif | 6390 | #endif |
| 6391 | } | ||
| 6404 | 6392 | ||
| 6405 | codegen_add_time_event(g, "LLVM Emit Output"); | 6393 | static void zig_llvm_emit_output(CodeGen *g) { |
| 6406 | |||
| 6407 | char *err_msg = nullptr; | ||
| 6408 | Buf *o_basename = buf_create_from_buf(g->root_out_name); | ||
| 6409 | |||
| 6410 | switch (g->emit_file_type) { | ||
| 6411 | case EmitFileTypeBinary: | ||
| 6412 | { | ||
| 6413 | const char *o_ext = target_o_file_ext(&g->zig_target); | ||
| 6414 | buf_append_str(o_basename, o_ext); | ||
| 6415 | break; | ||
| 6416 | } | ||
| 6417 | case EmitFileTypeAssembly: | ||
| 6418 | { | ||
| 6419 | const char *asm_ext = target_asm_file_ext(&g->zig_target); | ||
| 6420 | buf_append_str(o_basename, asm_ext); | ||
| 6421 | break; | ||
| 6422 | } | ||
| 6423 | case EmitFileTypeLLVMIr: | ||
| 6424 | { | ||
| 6425 | const char *llvm_ir_ext = target_llvm_ir_file_ext(&g->zig_target); | ||
| 6426 | buf_append_str(o_basename, llvm_ir_ext); | ||
| 6427 | break; | ||
| 6428 | } | ||
| 6429 | default: | ||
| 6430 | zig_unreachable(); | ||
| 6431 | } | ||
| 6432 | |||
| 6433 | Buf *output_path = buf_alloc(); | ||
| 6434 | os_path_join(&g->cache_dir, o_basename, output_path); | ||
| 6435 | ensure_cache_dir(g); | ||
| 6436 | |||
| 6437 | bool is_small = g->build_mode == BuildModeSmallRelease; | 6394 | bool is_small = g->build_mode == BuildModeSmallRelease; |
| 6438 | 6395 | ||
| 6396 | Buf *output_path = &g->o_file_output_path; | ||
| 6397 | char *err_msg = nullptr; | ||
| 6439 | switch (g->emit_file_type) { | 6398 | switch (g->emit_file_type) { |
| 6440 | case EmitFileTypeBinary: | 6399 | case EmitFileTypeBinary: |
| 6441 | if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), | 6400 | if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), |
| 6442 | ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug, is_small)) | 6401 | ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug, is_small, |
| 6402 | g->enable_time_report)) | ||
| 6443 | { | 6403 | { |
| 6444 | zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg); | 6404 | zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg); |
| 6445 | } | 6405 | } |
| ... | @@ -6449,22 +6409,22 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -6449,22 +6409,22 @@ static void do_code_gen(CodeGen *g) { |
| 6449 | 6409 | ||
| 6450 | case EmitFileTypeAssembly: | 6410 | case EmitFileTypeAssembly: |
| 6451 | if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), | 6411 | if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), |
| 6452 | ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug, is_small)) | 6412 | ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug, is_small, |
| 6413 | g->enable_time_report)) | ||
| 6453 | { | 6414 | { |
| 6454 | zig_panic("unable to write assembly file %s: %s", buf_ptr(output_path), err_msg); | 6415 | zig_panic("unable to write assembly file %s: %s", buf_ptr(output_path), err_msg); |
| 6455 | } | 6416 | } |
| 6456 | validate_inline_fns(g); | 6417 | validate_inline_fns(g); |
| 6457 | g->link_objects.append(output_path); | ||
| 6458 | break; | 6418 | break; |
| 6459 | 6419 | ||
| 6460 | case EmitFileTypeLLVMIr: | 6420 | case EmitFileTypeLLVMIr: |
| 6461 | if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), | 6421 | if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), |
| 6462 | ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug, is_small)) | 6422 | ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug, is_small, |
| 6423 | g->enable_time_report)) | ||
| 6463 | { | 6424 | { |
| 6464 | zig_panic("unable to write llvm-ir file %s: %s", buf_ptr(output_path), err_msg); | 6425 | zig_panic("unable to write llvm-ir file %s: %s", buf_ptr(output_path), err_msg); |
| 6465 | } | 6426 | } |
| 6466 | validate_inline_fns(g); | 6427 | validate_inline_fns(g); |
| 6467 | g->link_objects.append(output_path); | ||
| 6468 | break; | 6428 | break; |
| 6469 | 6429 | ||
| 6470 | default: | 6430 | default: |
| ... | @@ -7189,36 +7149,84 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { | ... | @@ -7189,36 +7149,84 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { |
| 7189 | return contents; | 7149 | return contents; |
| 7190 | } | 7150 | } |
| 7191 | 7151 | ||
| 7192 | static void define_builtin_compile_vars(CodeGen *g) { | 7152 | static Error define_builtin_compile_vars(CodeGen *g) { |
| 7193 | if (g->std_package == nullptr) | 7153 | if (g->std_package == nullptr) |
| 7194 | return; | 7154 | return ErrorNone; |
| 7195 | 7155 | ||
| 7196 | const char *builtin_zig_basename = "builtin.zig"; | 7156 | Error err; |
| 7197 | Buf *builtin_zig_path = buf_alloc(); | ||
| 7198 | os_path_join(&g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path); | ||
| 7199 | 7157 | ||
| 7200 | Buf *contents = codegen_generate_builtin_source(g); | 7158 | Buf *manifest_dir = buf_alloc(); |
| 7201 | ensure_cache_dir(g); | 7159 | os_path_join(get_stage1_cache_path(), buf_create_from_str("builtin"), manifest_dir); |
| 7202 | os_write_file(builtin_zig_path, contents); | ||
| 7203 | 7160 | ||
| 7204 | Buf *resolved_path = buf_alloc(); | 7161 | CacheHash cache_hash; |
| 7205 | Buf *resolve_paths[] = {builtin_zig_path}; | 7162 | cache_init(&cache_hash, manifest_dir); |
| 7206 | *resolved_path = os_path_resolve(resolve_paths, 1); | 7163 | |
| 7164 | Buf *compiler_id; | ||
| 7165 | if ((err = get_compiler_id(&compiler_id))) | ||
| 7166 | return err; | ||
| 7167 | |||
| 7168 | // Only a few things affect builtin.zig | ||
| 7169 | cache_buf(&cache_hash, compiler_id); | ||
| 7170 | cache_int(&cache_hash, g->build_mode); | ||
| 7171 | cache_bool(&cache_hash, g->is_test_build); | ||
| 7172 | cache_int(&cache_hash, g->zig_target.arch.arch); | ||
| 7173 | cache_int(&cache_hash, g->zig_target.arch.sub_arch); | ||
| 7174 | cache_int(&cache_hash, g->zig_target.vendor); | ||
| 7175 | cache_int(&cache_hash, g->zig_target.os); | ||
| 7176 | cache_int(&cache_hash, g->zig_target.env_type); | ||
| 7177 | cache_int(&cache_hash, g->zig_target.oformat); | ||
| 7178 | cache_bool(&cache_hash, g->have_err_ret_tracing); | ||
| 7179 | cache_bool(&cache_hash, g->libc_link_lib != nullptr); | ||
| 7180 | |||
| 7181 | Buf digest = BUF_INIT; | ||
| 7182 | buf_resize(&digest, 0); | ||
| 7183 | if ((err = cache_hit(&cache_hash, &digest))) | ||
| 7184 | return err; | ||
| 7185 | |||
| 7186 | // We should always get a cache hit because there are no | ||
| 7187 | // files in the input hash. | ||
| 7188 | assert(buf_len(&digest) != 0); | ||
| 7189 | |||
| 7190 | Buf *this_dir = buf_alloc(); | ||
| 7191 | os_path_join(manifest_dir, &digest, this_dir); | ||
| 7192 | |||
| 7193 | if ((err = os_make_path(this_dir))) | ||
| 7194 | return err; | ||
| 7195 | |||
| 7196 | const char *builtin_zig_basename = "builtin.zig"; | ||
| 7197 | Buf *builtin_zig_path = buf_alloc(); | ||
| 7198 | os_path_join(this_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path); | ||
| 7199 | |||
| 7200 | bool hit; | ||
| 7201 | if ((err = os_file_exists(builtin_zig_path, &hit))) | ||
| 7202 | return err; | ||
| 7203 | Buf *contents; | ||
| 7204 | if (hit) { | ||
| 7205 | contents = buf_alloc(); | ||
| 7206 | if ((err = os_fetch_file_path(builtin_zig_path, contents, false))) { | ||
| 7207 | fprintf(stderr, "Unable to open '%s': %s\n", buf_ptr(builtin_zig_path), err_str(err)); | ||
| 7208 | exit(1); | ||
| 7209 | } | ||
| 7210 | } else { | ||
| 7211 | contents = codegen_generate_builtin_source(g); | ||
| 7212 | os_write_file(builtin_zig_path, contents); | ||
| 7213 | } | ||
| 7207 | 7214 | ||
| 7208 | assert(g->root_package); | 7215 | assert(g->root_package); |
| 7209 | assert(g->std_package); | 7216 | assert(g->std_package); |
| 7210 | g->compile_var_package = new_package(buf_ptr(&g->cache_dir), builtin_zig_basename); | 7217 | g->compile_var_package = new_package(buf_ptr(this_dir), builtin_zig_basename); |
| 7211 | g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); | 7218 | g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); |
| 7212 | g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); | 7219 | g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); |
| 7213 | g->compile_var_import = add_source_file(g, g->compile_var_package, resolved_path, contents); | 7220 | g->compile_var_import = add_source_file(g, g->compile_var_package, builtin_zig_path, contents); |
| 7214 | scan_import(g, g->compile_var_import); | 7221 | scan_import(g, g->compile_var_import); |
| 7222 | |||
| 7223 | return ErrorNone; | ||
| 7215 | } | 7224 | } |
| 7216 | 7225 | ||
| 7217 | static void init(CodeGen *g) { | 7226 | static void init(CodeGen *g) { |
| 7218 | if (g->module) | 7227 | if (g->module) |
| 7219 | return; | 7228 | return; |
| 7220 | 7229 | ||
| 7221 | |||
| 7222 | if (g->llvm_argv_len > 0) { | 7230 | if (g->llvm_argv_len > 0) { |
| 7223 | const char **args = allocate_nonzero<const char *>(g->llvm_argv_len + 2); | 7231 | const char **args = allocate_nonzero<const char *>(g->llvm_argv_len + 2); |
| 7224 | args[0] = "zig (LLVM option parsing)"; | 7232 | args[0] = "zig (LLVM option parsing)"; |
| ... | @@ -7325,7 +7333,11 @@ static void init(CodeGen *g) { | ... | @@ -7325,7 +7333,11 @@ static void init(CodeGen *g) { |
| 7325 | g->have_err_ret_tracing = g->build_mode != BuildModeFastRelease && g->build_mode != BuildModeSmallRelease; | 7333 | g->have_err_ret_tracing = g->build_mode != BuildModeFastRelease && g->build_mode != BuildModeSmallRelease; |
| 7326 | 7334 | ||
| 7327 | define_builtin_fns(g); | 7335 | define_builtin_fns(g); |
| 7328 | define_builtin_compile_vars(g); | 7336 | Error err; |
| 7337 | if ((err = define_builtin_compile_vars(g))) { | ||
| 7338 | fprintf(stderr, "Unable to create builtin.zig: %s\n", err_str(err)); | ||
| 7339 | exit(1); | ||
| 7340 | } | ||
| 7329 | } | 7341 | } |
| 7330 | 7342 | ||
| 7331 | void codegen_translate_c(CodeGen *g, Buf *full_path) { | 7343 | void codegen_translate_c(CodeGen *g, Buf *full_path) { |
| ... | @@ -7371,8 +7383,8 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package | ... | @@ -7371,8 +7383,8 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package |
| 7371 | Buf *resolved_path = buf_alloc(); | 7383 | Buf *resolved_path = buf_alloc(); |
| 7372 | *resolved_path = os_path_resolve(resolve_paths, 1); | 7384 | *resolved_path = os_path_resolve(resolve_paths, 1); |
| 7373 | Buf *import_code = buf_alloc(); | 7385 | Buf *import_code = buf_alloc(); |
| 7374 | int err; | 7386 | Error err; |
| 7375 | if ((err = os_fetch_file_path(resolved_path, import_code, false))) { | 7387 | if ((err = file_fetch(g, resolved_path, import_code))) { |
| 7376 | zig_panic("unable to open '%s': %s\n", buf_ptr(&path_to_code_src), err_str(err)); | 7388 | zig_panic("unable to open '%s': %s\n", buf_ptr(&path_to_code_src), err_str(err)); |
| 7377 | } | 7389 | } |
| 7378 | 7390 | ||
| ... | @@ -7445,23 +7457,32 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) { | ... | @@ -7445,23 +7457,32 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) { |
| 7445 | g->test_runner_import = add_special_code(g, g->test_runner_package, "test_runner.zig"); | 7457 | g->test_runner_import = add_special_code(g, g->test_runner_package, "test_runner.zig"); |
| 7446 | } | 7458 | } |
| 7447 | 7459 | ||
| 7448 | static void gen_root_source(CodeGen *g) { | 7460 | static Buf *get_resolved_root_src_path(CodeGen *g) { |
| 7461 | // TODO memoize | ||
| 7449 | if (buf_len(&g->root_package->root_src_path) == 0) | 7462 | if (buf_len(&g->root_package->root_src_path) == 0) |
| 7450 | return; | 7463 | return nullptr; |
| 7451 | |||
| 7452 | codegen_add_time_event(g, "Semantic Analysis"); | ||
| 7453 | 7464 | ||
| 7454 | Buf *rel_full_path = buf_alloc(); | 7465 | Buf rel_full_path = BUF_INIT; |
| 7455 | os_path_join(&g->root_package->root_src_dir, &g->root_package->root_src_path, rel_full_path); | 7466 | os_path_join(&g->root_package->root_src_dir, &g->root_package->root_src_path, &rel_full_path); |
| 7456 | 7467 | ||
| 7457 | Buf *resolved_path = buf_alloc(); | 7468 | Buf *resolved_path = buf_alloc(); |
| 7458 | Buf *resolve_paths[] = {rel_full_path}; | 7469 | Buf *resolve_paths[] = {&rel_full_path}; |
| 7459 | *resolved_path = os_path_resolve(resolve_paths, 1); | 7470 | *resolved_path = os_path_resolve(resolve_paths, 1); |
| 7460 | 7471 | ||
| 7472 | return resolved_path; | ||
| 7473 | } | ||
| 7474 | |||
| 7475 | static void gen_root_source(CodeGen *g) { | ||
| 7476 | Buf *resolved_path = get_resolved_root_src_path(g); | ||
| 7477 | if (resolved_path == nullptr) | ||
| 7478 | return; | ||
| 7479 | |||
| 7461 | Buf *source_code = buf_alloc(); | 7480 | Buf *source_code = buf_alloc(); |
| 7462 | int err; | 7481 | int err; |
| 7463 | if ((err = os_fetch_file_path(rel_full_path, source_code, true))) { | 7482 | // No need for using the caching system for this file fetch because it is handled |
| 7464 | fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(rel_full_path), err_str(err)); | 7483 | // separately. |
| 7484 | if ((err = os_fetch_file_path(resolved_path, source_code, true))) { | ||
| 7485 | fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(resolved_path), err_str(err)); | ||
| 7465 | exit(1); | 7486 | exit(1); |
| 7466 | } | 7487 | } |
| 7467 | 7488 | ||
| ... | @@ -7526,6 +7547,8 @@ static void gen_global_asm(CodeGen *g) { | ... | @@ -7526,6 +7547,8 @@ static void gen_global_asm(CodeGen *g) { |
| 7526 | int err; | 7547 | int err; |
| 7527 | for (size_t i = 0; i < g->assembly_files.length; i += 1) { | 7548 | for (size_t i = 0; i < g->assembly_files.length; i += 1) { |
| 7528 | Buf *asm_file = g->assembly_files.at(i); | 7549 | Buf *asm_file = g->assembly_files.at(i); |
| 7550 | // No need to use the caching system for these fetches because they | ||
| 7551 | // are handled separately. | ||
| 7529 | if ((err = os_fetch_file_path(asm_file, &contents, false))) { | 7552 | if ((err = os_fetch_file_path(asm_file, &contents, false))) { |
| 7530 | zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err)); | 7553 | zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err)); |
| 7531 | } | 7554 | } |
| ... | @@ -7789,19 +7812,11 @@ static Buf *preprocessor_mangle(Buf *src) { | ... | @@ -7789,19 +7812,11 @@ static Buf *preprocessor_mangle(Buf *src) { |
| 7789 | } | 7812 | } |
| 7790 | 7813 | ||
| 7791 | static void gen_h_file(CodeGen *g) { | 7814 | static void gen_h_file(CodeGen *g) { |
| 7792 | if (!g->want_h_file) | ||
| 7793 | return; | ||
| 7794 | |||
| 7795 | GenH gen_h_data = {0}; | 7815 | GenH gen_h_data = {0}; |
| 7796 | GenH *gen_h = &gen_h_data; | 7816 | GenH *gen_h = &gen_h_data; |
| 7797 | 7817 | ||
| 7798 | codegen_add_time_event(g, "Generate .h"); | ||
| 7799 | |||
| 7800 | assert(!g->is_test_build); | 7818 | assert(!g->is_test_build); |
| 7801 | 7819 | assert(g->out_h_path != nullptr); | |
| 7802 | if (!g->out_h_path) { | ||
| 7803 | g->out_h_path = buf_sprintf("%s.h", buf_ptr(g->root_out_name)); | ||
| 7804 | } | ||
| 7805 | 7820 | ||
| 7806 | FILE *out_h = fopen(buf_ptr(g->out_h_path), "wb"); | 7821 | FILE *out_h = fopen(buf_ptr(g->out_h_path), "wb"); |
| 7807 | if (!out_h) | 7822 | if (!out_h) |
| ... | @@ -8004,14 +8019,231 @@ void codegen_add_time_event(CodeGen *g, const char *name) { | ... | @@ -8004,14 +8019,231 @@ void codegen_add_time_event(CodeGen *g, const char *name) { |
| 8004 | g->timing_events.append({os_get_time(), name}); | 8019 | g->timing_events.append({os_get_time(), name}); |
| 8005 | } | 8020 | } |
| 8006 | 8021 | ||
| 8007 | void codegen_build(CodeGen *g) { | 8022 | static void add_cache_pkg(CodeGen *g, CacheHash *ch, PackageTableEntry *pkg) { |
| 8023 | if (buf_len(&pkg->root_src_path) == 0) | ||
| 8024 | return; | ||
| 8025 | |||
| 8026 | Buf *rel_full_path = buf_alloc(); | ||
| 8027 | os_path_join(&pkg->root_src_dir, &pkg->root_src_path, rel_full_path); | ||
| 8028 | cache_file(ch, rel_full_path); | ||
| 8029 | |||
| 8030 | auto it = pkg->package_table.entry_iterator(); | ||
| 8031 | for (;;) { | ||
| 8032 | auto *entry = it.next(); | ||
| 8033 | if (!entry) | ||
| 8034 | break; | ||
| 8035 | |||
| 8036 | cache_buf(ch, entry->key); | ||
| 8037 | add_cache_pkg(g, ch, entry->value); | ||
| 8038 | } | ||
| 8039 | } | ||
| 8040 | |||
| 8041 | // Called before init() | ||
| 8042 | static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { | ||
| 8043 | Error err; | ||
| 8044 | |||
| 8045 | Buf *compiler_id; | ||
| 8046 | if ((err = get_compiler_id(&compiler_id))) | ||
| 8047 | return err; | ||
| 8048 | |||
| 8049 | CacheHash *ch = &g->cache_hash; | ||
| 8050 | cache_init(ch, manifest_dir); | ||
| 8051 | |||
| 8052 | add_cache_pkg(g, ch, g->root_package); | ||
| 8053 | if (g->linker_script != nullptr) { | ||
| 8054 | cache_file(ch, buf_create_from_str(g->linker_script)); | ||
| 8055 | } | ||
| 8056 | cache_buf(ch, compiler_id); | ||
| 8057 | cache_buf(ch, g->root_out_name); | ||
| 8058 | cache_list_of_link_lib(ch, g->link_libs_list.items, g->link_libs_list.length); | ||
| 8059 | cache_list_of_buf(ch, g->darwin_frameworks.items, g->darwin_frameworks.length); | ||
| 8060 | cache_list_of_buf(ch, g->rpath_list.items, g->rpath_list.length); | ||
| 8061 | cache_list_of_buf(ch, g->forbidden_libs.items, g->forbidden_libs.length); | ||
| 8062 | cache_list_of_file(ch, g->link_objects.items, g->link_objects.length); | ||
| 8063 | cache_list_of_file(ch, g->assembly_files.items, g->assembly_files.length); | ||
| 8064 | cache_int(ch, g->emit_file_type); | ||
| 8065 | cache_int(ch, g->build_mode); | ||
| 8066 | cache_int(ch, g->out_type); | ||
| 8067 | cache_int(ch, g->zig_target.arch.arch); | ||
| 8068 | cache_int(ch, g->zig_target.arch.sub_arch); | ||
| 8069 | cache_int(ch, g->zig_target.vendor); | ||
| 8070 | cache_int(ch, g->zig_target.os); | ||
| 8071 | cache_int(ch, g->zig_target.env_type); | ||
| 8072 | cache_int(ch, g->zig_target.oformat); | ||
| 8073 | cache_bool(ch, g->is_static); | ||
| 8074 | cache_bool(ch, g->strip_debug_symbols); | ||
| 8075 | cache_bool(ch, g->is_test_build); | ||
| 8076 | cache_bool(ch, g->is_native_target); | ||
| 8077 | cache_bool(ch, g->windows_subsystem_windows); | ||
| 8078 | cache_bool(ch, g->windows_subsystem_console); | ||
| 8079 | cache_bool(ch, g->linker_rdynamic); | ||
| 8080 | cache_bool(ch, g->no_rosegment_workaround); | ||
| 8081 | cache_bool(ch, g->each_lib_rpath); | ||
| 8082 | cache_buf_opt(ch, g->mmacosx_version_min); | ||
| 8083 | cache_buf_opt(ch, g->mios_version_min); | ||
| 8084 | cache_usize(ch, g->version_major); | ||
| 8085 | cache_usize(ch, g->version_minor); | ||
| 8086 | cache_usize(ch, g->version_patch); | ||
| 8087 | cache_buf_opt(ch, g->test_filter); | ||
| 8088 | cache_buf_opt(ch, g->test_name_prefix); | ||
| 8089 | cache_list_of_str(ch, g->llvm_argv, g->llvm_argv_len); | ||
| 8090 | cache_list_of_str(ch, g->clang_argv, g->clang_argv_len); | ||
| 8091 | cache_list_of_str(ch, g->lib_dirs.items, g->lib_dirs.length); | ||
| 8092 | |||
| 8093 | buf_resize(digest, 0); | ||
| 8094 | if ((err = cache_hit(ch, digest))) | ||
| 8095 | return err; | ||
| 8096 | |||
| 8097 | return ErrorNone; | ||
| 8098 | } | ||
| 8099 | |||
| 8100 | static void resolve_out_paths(CodeGen *g) { | ||
| 8101 | Buf *o_basename = buf_create_from_buf(g->root_out_name); | ||
| 8102 | |||
| 8103 | switch (g->emit_file_type) { | ||
| 8104 | case EmitFileTypeBinary: | ||
| 8105 | { | ||
| 8106 | const char *o_ext = target_o_file_ext(&g->zig_target); | ||
| 8107 | buf_append_str(o_basename, o_ext); | ||
| 8108 | break; | ||
| 8109 | } | ||
| 8110 | case EmitFileTypeAssembly: | ||
| 8111 | { | ||
| 8112 | const char *asm_ext = target_asm_file_ext(&g->zig_target); | ||
| 8113 | buf_append_str(o_basename, asm_ext); | ||
| 8114 | break; | ||
| 8115 | } | ||
| 8116 | case EmitFileTypeLLVMIr: | ||
| 8117 | { | ||
| 8118 | const char *llvm_ir_ext = target_llvm_ir_file_ext(&g->zig_target); | ||
| 8119 | buf_append_str(o_basename, llvm_ir_ext); | ||
| 8120 | break; | ||
| 8121 | } | ||
| 8122 | default: | ||
| 8123 | zig_unreachable(); | ||
| 8124 | } | ||
| 8125 | |||
| 8126 | if (g->enable_cache || g->out_type != OutTypeObj) { | ||
| 8127 | os_path_join(&g->artifact_dir, o_basename, &g->o_file_output_path); | ||
| 8128 | } else if (g->wanted_output_file_path != nullptr && g->out_type == OutTypeObj) { | ||
| 8129 | buf_init_from_buf(&g->o_file_output_path, g->wanted_output_file_path); | ||
| 8130 | } else { | ||
| 8131 | buf_init_from_buf(&g->o_file_output_path, o_basename); | ||
| 8132 | } | ||
| 8133 | |||
| 8134 | if (g->out_type == OutTypeObj) { | ||
| 8135 | buf_init_from_buf(&g->output_file_path, &g->o_file_output_path); | ||
| 8136 | } else if (g->out_type == OutTypeExe) { | ||
| 8137 | if (!g->enable_cache && g->wanted_output_file_path != nullptr) { | ||
| 8138 | buf_init_from_buf(&g->output_file_path, g->wanted_output_file_path); | ||
| 8139 | } else { | ||
| 8140 | assert(g->root_out_name); | ||
| 8141 | |||
| 8142 | Buf basename = BUF_INIT; | ||
| 8143 | buf_init_from_buf(&basename, g->root_out_name); | ||
| 8144 | buf_append_str(&basename, target_exe_file_ext(&g->zig_target)); | ||
| 8145 | if (g->enable_cache) { | ||
| 8146 | os_path_join(&g->artifact_dir, &basename, &g->output_file_path); | ||
| 8147 | } else { | ||
| 8148 | buf_init_from_buf(&g->output_file_path, &basename); | ||
| 8149 | } | ||
| 8150 | } | ||
| 8151 | } else if (g->out_type == OutTypeLib) { | ||
| 8152 | if (!g->enable_cache && g->wanted_output_file_path != nullptr) { | ||
| 8153 | buf_init_from_buf(&g->output_file_path, g->wanted_output_file_path); | ||
| 8154 | } else { | ||
| 8155 | Buf basename = BUF_INIT; | ||
| 8156 | buf_init_from_buf(&basename, g->root_out_name); | ||
| 8157 | buf_append_str(&basename, target_lib_file_ext(&g->zig_target, g->is_static, | ||
| 8158 | g->version_major, g->version_minor, g->version_patch)); | ||
| 8159 | if (g->enable_cache) { | ||
| 8160 | os_path_join(&g->artifact_dir, &basename, &g->output_file_path); | ||
| 8161 | } else { | ||
| 8162 | buf_init_from_buf(&g->output_file_path, &basename); | ||
| 8163 | } | ||
| 8164 | } | ||
| 8165 | } else { | ||
| 8166 | zig_unreachable(); | ||
| 8167 | } | ||
| 8168 | |||
| 8169 | if (g->want_h_file && !g->out_h_path) { | ||
| 8170 | assert(g->root_out_name); | ||
| 8171 | Buf *h_basename = buf_sprintf("%s.h", buf_ptr(g->root_out_name)); | ||
| 8172 | if (g->enable_cache) { | ||
| 8173 | g->out_h_path = buf_alloc(); | ||
| 8174 | os_path_join(&g->artifact_dir, h_basename, g->out_h_path); | ||
| 8175 | } else { | ||
| 8176 | g->out_h_path = h_basename; | ||
| 8177 | } | ||
| 8178 | } | ||
| 8179 | } | ||
| 8180 | |||
| 8181 | |||
| 8182 | void codegen_build_and_link(CodeGen *g) { | ||
| 8183 | Error err; | ||
| 8008 | assert(g->out_type != OutTypeUnknown); | 8184 | assert(g->out_type != OutTypeUnknown); |
| 8009 | init(g); | ||
| 8010 | 8185 | ||
| 8011 | gen_global_asm(g); | 8186 | Buf *stage1_dir = get_stage1_cache_path(); |
| 8012 | gen_root_source(g); | 8187 | Buf *artifact_dir = buf_alloc(); |
| 8013 | do_code_gen(g); | 8188 | Buf digest = BUF_INIT; |
| 8014 | gen_h_file(g); | 8189 | if (g->enable_cache) { |
| 8190 | codegen_add_time_event(g, "Check Cache"); | ||
| 8191 | |||
| 8192 | Buf *manifest_dir = buf_alloc(); | ||
| 8193 | os_path_join(stage1_dir, buf_create_from_str("build"), manifest_dir); | ||
| 8194 | |||
| 8195 | if ((err = check_cache(g, manifest_dir, &digest))) { | ||
| 8196 | fprintf(stderr, "Unable to check cache: %s\n", err_str(err)); | ||
| 8197 | exit(1); | ||
| 8198 | } | ||
| 8199 | |||
| 8200 | os_path_join(stage1_dir, buf_create_from_str("artifact"), artifact_dir); | ||
| 8201 | } | ||
| 8202 | |||
| 8203 | if (g->enable_cache && buf_len(&digest) != 0) { | ||
| 8204 | os_path_join(artifact_dir, &digest, &g->artifact_dir); | ||
| 8205 | resolve_out_paths(g); | ||
| 8206 | } else { | ||
| 8207 | init(g); | ||
| 8208 | |||
| 8209 | codegen_add_time_event(g, "Semantic Analysis"); | ||
| 8210 | |||
| 8211 | gen_global_asm(g); | ||
| 8212 | gen_root_source(g); | ||
| 8213 | |||
| 8214 | if (g->enable_cache) { | ||
| 8215 | if ((err = cache_final(&g->cache_hash, &digest))) { | ||
| 8216 | fprintf(stderr, "Unable to finalize cache hash: %s\n", err_str(err)); | ||
| 8217 | exit(1); | ||
| 8218 | } | ||
| 8219 | os_path_join(artifact_dir, &digest, &g->artifact_dir); | ||
| 8220 | } else { | ||
| 8221 | buf_init_from_buf(&g->artifact_dir, &g->cache_dir); | ||
| 8222 | } | ||
| 8223 | if ((err = os_make_path(&g->artifact_dir))) { | ||
| 8224 | fprintf(stderr, "Unable to create artifact directory: %s\n", err_str(err)); | ||
| 8225 | exit(1); | ||
| 8226 | } | ||
| 8227 | resolve_out_paths(g); | ||
| 8228 | |||
| 8229 | codegen_add_time_event(g, "Code Generation"); | ||
| 8230 | do_code_gen(g); | ||
| 8231 | codegen_add_time_event(g, "LLVM Emit Output"); | ||
| 8232 | zig_llvm_emit_output(g); | ||
| 8233 | |||
| 8234 | if (g->want_h_file) { | ||
| 8235 | codegen_add_time_event(g, "Generate .h"); | ||
| 8236 | gen_h_file(g); | ||
| 8237 | } | ||
| 8238 | if (g->out_type != OutTypeObj) { | ||
| 8239 | codegen_link(g); | ||
| 8240 | } | ||
| 8241 | } | ||
| 8242 | |||
| 8243 | if (g->enable_cache) { | ||
| 8244 | cache_release(&g->cache_hash); | ||
| 8245 | } | ||
| 8246 | codegen_add_time_event(g, "Done"); | ||
| 8015 | } | 8247 | } |
| 8016 | 8248 | ||
| 8017 | PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path) { | 8249 | PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path) { |
src/codegen.hpp+3-3| ... | @@ -16,7 +16,6 @@ | ... | @@ -16,7 +16,6 @@ |
| 16 | 16 | ||
| 17 | CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode, | 17 | CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode, |
| 18 | Buf *zig_lib_dir); | 18 | Buf *zig_lib_dir); |
| 19 | void codegen_destroy(CodeGen *codegen); | ||
| 20 | 19 | ||
| 21 | void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len); | 20 | void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len); |
| 22 | void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len); | 21 | void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len); |
| ... | @@ -47,11 +46,12 @@ void codegen_set_linker_script(CodeGen *g, const char *linker_script); | ... | @@ -47,11 +46,12 @@ void codegen_set_linker_script(CodeGen *g, const char *linker_script); |
| 47 | void codegen_set_test_filter(CodeGen *g, Buf *filter); | 46 | void codegen_set_test_filter(CodeGen *g, Buf *filter); |
| 48 | void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix); | 47 | void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix); |
| 49 | void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch); | 48 | void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch); |
| 50 | void codegen_set_cache_dir(CodeGen *g, Buf cache_dir); | ||
| 51 | void codegen_set_output_h_path(CodeGen *g, Buf *h_path); | 49 | void codegen_set_output_h_path(CodeGen *g, Buf *h_path); |
| 50 | void codegen_set_output_path(CodeGen *g, Buf *path); | ||
| 52 | void codegen_add_time_event(CodeGen *g, const char *name); | 51 | void codegen_add_time_event(CodeGen *g, const char *name); |
| 53 | void codegen_print_timing_report(CodeGen *g, FILE *f); | 52 | void codegen_print_timing_report(CodeGen *g, FILE *f); |
| 54 | void codegen_build(CodeGen *g); | 53 | void codegen_link(CodeGen *g); |
| 54 | void codegen_build_and_link(CodeGen *g); | ||
| 55 | 55 | ||
| 56 | PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path); | 56 | PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path); |
| 57 | void codegen_add_assembly(CodeGen *g, Buf *path); | 57 | void codegen_add_assembly(CodeGen *g, Buf *path); |
src/compiler.cpp created+66| ... | @@ -0,0 +1,66 @@ | ||
| 1 | #include "cache_hash.hpp" | ||
| 2 | |||
| 3 | #include <stdio.h> | ||
| 4 | |||
| 5 | static Buf saved_compiler_id = BUF_INIT; | ||
| 6 | static Buf saved_app_data_dir = BUF_INIT; | ||
| 7 | static Buf saved_stage1_path = BUF_INIT; | ||
| 8 | |||
| 9 | Buf *get_stage1_cache_path() { | ||
| 10 | if (saved_stage1_path.list.length != 0) { | ||
| 11 | return &saved_stage1_path; | ||
| 12 | } | ||
| 13 | Error err; | ||
| 14 | if ((err = os_get_app_data_dir(&saved_app_data_dir, "zig"))) { | ||
| 15 | fprintf(stderr, "Unable to get app data dir: %s\n", err_str(err)); | ||
| 16 | exit(1); | ||
| 17 | } | ||
| 18 | os_path_join(&saved_app_data_dir, buf_create_from_str("stage1"), &saved_stage1_path); | ||
| 19 | return &saved_stage1_path; | ||
| 20 | } | ||
| 21 | |||
| 22 | Error get_compiler_id(Buf **result) { | ||
| 23 | if (saved_compiler_id.list.length != 0) { | ||
| 24 | *result = &saved_compiler_id; | ||
| 25 | return ErrorNone; | ||
| 26 | } | ||
| 27 | |||
| 28 | Error err; | ||
| 29 | Buf *stage1_dir = get_stage1_cache_path(); | ||
| 30 | Buf *manifest_dir = buf_alloc(); | ||
| 31 | os_path_join(stage1_dir, buf_create_from_str("exe"), manifest_dir); | ||
| 32 | |||
| 33 | CacheHash cache_hash; | ||
| 34 | CacheHash *ch = &cache_hash; | ||
| 35 | cache_init(ch, manifest_dir); | ||
| 36 | Buf self_exe_path = BUF_INIT; | ||
| 37 | if ((err = os_self_exe_path(&self_exe_path))) | ||
| 38 | return err; | ||
| 39 | |||
| 40 | cache_file(ch, &self_exe_path); | ||
| 41 | |||
| 42 | buf_resize(&saved_compiler_id, 0); | ||
| 43 | if ((err = cache_hit(ch, &saved_compiler_id))) | ||
| 44 | return err; | ||
| 45 | if (buf_len(&saved_compiler_id) != 0) { | ||
| 46 | cache_release(ch); | ||
| 47 | *result = &saved_compiler_id; | ||
| 48 | return ErrorNone; | ||
| 49 | } | ||
| 50 | ZigList<Buf *> lib_paths = {}; | ||
| 51 | if ((err = os_self_exe_shared_libs(lib_paths))) | ||
| 52 | return err; | ||
| 53 | for (size_t i = 0; i < lib_paths.length; i += 1) { | ||
| 54 | Buf *lib_path = lib_paths.at(i); | ||
| 55 | if ((err = cache_add_file(ch, lib_path))) | ||
| 56 | return err; | ||
| 57 | } | ||
| 58 | if ((err = cache_final(ch, &saved_compiler_id))) | ||
| 59 | return err; | ||
| 60 | |||
| 61 | cache_release(ch); | ||
| 62 | |||
| 63 | *result = &saved_compiler_id; | ||
| 64 | return ErrorNone; | ||
| 65 | } | ||
| 66 | |||
src/compiler.hpp created+17| ... | @@ -0,0 +1,17 @@ | ||
| 1 | /* | ||
| 2 | * Copyright (c) 2018 Andrew Kelley | ||
| 3 | * | ||
| 4 | * This file is part of zig, which is MIT licensed. | ||
| 5 | * See http://opensource.org/licenses/MIT | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef ZIG_COMPILER_HPP | ||
| 9 | #define ZIG_COMPILER_HPP | ||
| 10 | |||
| 11 | #include "buffer.hpp" | ||
| 12 | #include "error.hpp" | ||
| 13 | |||
| 14 | Buf *get_stage1_cache_path(); | ||
| 15 | Error get_compiler_id(Buf **result); | ||
| 16 | |||
| 17 | #endif | ||
src/error.cpp+5| ... | @@ -27,6 +27,11 @@ const char *err_str(int err) { | ... | @@ -27,6 +27,11 @@ const char *err_str(int err) { |
| 27 | case ErrorNegativeDenominator: return "negative denominator"; | 27 | case ErrorNegativeDenominator: return "negative denominator"; |
| 28 | case ErrorShiftedOutOneBits: return "exact shift shifted out one bits"; | 28 | case ErrorShiftedOutOneBits: return "exact shift shifted out one bits"; |
| 29 | case ErrorCCompileErrors: return "C compile errors"; | 29 | case ErrorCCompileErrors: return "C compile errors"; |
| 30 | case ErrorEndOfFile: return "end of file"; | ||
| 31 | case ErrorIsDir: return "is directory"; | ||
| 32 | case ErrorUnsupportedOperatingSystem: return "unsupported operating system"; | ||
| 33 | case ErrorSharingViolation: return "sharing violation"; | ||
| 34 | case ErrorPipeBusy: return "pipe busy"; | ||
| 30 | } | 35 | } |
| 31 | return "(invalid error)"; | 36 | return "(invalid error)"; |
| 32 | } | 37 | } |
src/error.hpp+5| ... | @@ -27,6 +27,11 @@ enum Error { | ... | @@ -27,6 +27,11 @@ enum Error { |
| 27 | ErrorNegativeDenominator, | 27 | ErrorNegativeDenominator, |
| 28 | ErrorShiftedOutOneBits, | 28 | ErrorShiftedOutOneBits, |
| 29 | ErrorCCompileErrors, | 29 | ErrorCCompileErrors, |
| 30 | ErrorEndOfFile, | ||
| 31 | ErrorIsDir, | ||
| 32 | ErrorUnsupportedOperatingSystem, | ||
| 33 | ErrorSharingViolation, | ||
| 34 | ErrorPipeBusy, | ||
| 30 | }; | 35 | }; |
| 31 | 36 | ||
| 32 | const char *err_str(int err); | 37 | const char *err_str(int err); |
src/ir.cpp+11-6| ... | @@ -16231,6 +16231,8 @@ static ZigType *ir_analyze_instruction_union_tag(IrAnalyze *ira, IrInstructionUn | ... | @@ -16231,6 +16231,8 @@ static ZigType *ir_analyze_instruction_union_tag(IrAnalyze *ira, IrInstructionUn |
| 16231 | } | 16231 | } |
| 16232 | 16232 | ||
| 16233 | static ZigType *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructionImport *import_instruction) { | 16233 | static ZigType *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructionImport *import_instruction) { |
| 16234 | Error err; | ||
| 16235 | |||
| 16234 | IrInstruction *name_value = import_instruction->name->other; | 16236 | IrInstruction *name_value = import_instruction->name->other; |
| 16235 | Buf *import_target_str = ir_resolve_str(ira, name_value); | 16237 | Buf *import_target_str = ir_resolve_str(ira, name_value); |
| 16236 | if (!import_target_str) | 16238 | if (!import_target_str) |
| ... | @@ -16274,8 +16276,7 @@ static ZigType *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructionImpor | ... | @@ -16274,8 +16276,7 @@ static ZigType *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructionImpor |
| 16274 | return ira->codegen->builtin_types.entry_namespace; | 16276 | return ira->codegen->builtin_types.entry_namespace; |
| 16275 | } | 16277 | } |
| 16276 | 16278 | ||
| 16277 | int err; | 16279 | if ((err = file_fetch(ira->codegen, resolved_path, import_code))) { |
| 16278 | if ((err = os_fetch_file_path(resolved_path, import_code, true))) { | ||
| 16279 | if (err == ErrorFileNotFound) { | 16280 | if (err == ErrorFileNotFound) { |
| 16280 | ir_add_error_node(ira, source_node, | 16281 | ir_add_error_node(ira, source_node, |
| 16281 | buf_sprintf("unable to find '%s'", buf_ptr(import_target_path))); | 16282 | buf_sprintf("unable to find '%s'", buf_ptr(import_target_path))); |
| ... | @@ -16286,6 +16287,7 @@ static ZigType *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructionImpor | ... | @@ -16286,6 +16287,7 @@ static ZigType *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructionImpor |
| 16286 | return ira->codegen->builtin_types.entry_invalid; | 16287 | return ira->codegen->builtin_types.entry_invalid; |
| 16287 | } | 16288 | } |
| 16288 | } | 16289 | } |
| 16290 | |||
| 16289 | ImportTableEntry *target_import = add_source_file(ira->codegen, target_package, resolved_path, import_code); | 16291 | ImportTableEntry *target_import = add_source_file(ira->codegen, target_package, resolved_path, import_code); |
| 16290 | 16292 | ||
| 16291 | scan_import(ira->codegen, target_import); | 16293 | scan_import(ira->codegen, target_import); |
| ... | @@ -17959,6 +17961,12 @@ static ZigType *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTy | ... | @@ -17959,6 +17961,12 @@ static ZigType *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTy |
| 17959 | } | 17961 | } |
| 17960 | 17962 | ||
| 17961 | static ZigType *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstructionCImport *instruction) { | 17963 | static ZigType *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstructionCImport *instruction) { |
| 17964 | if (ira->codegen->enable_cache) { | ||
| 17965 | ir_add_error(ira, &instruction->base, | ||
| 17966 | buf_sprintf("TODO @cImport is incompatible with --cache on. The cache system currently is unable to detect subsequent changes in .h files.")); | ||
| 17967 | return ira->codegen->builtin_types.entry_invalid; | ||
| 17968 | } | ||
| 17969 | |||
| 17962 | AstNode *node = instruction->base.source_node; | 17970 | AstNode *node = instruction->base.source_node; |
| 17963 | assert(node->type == NodeTypeFnCallExpr); | 17971 | assert(node->type == NodeTypeFnCallExpr); |
| 17964 | AstNode *block_node = node->data.fn_call_expr.params.at(0); | 17972 | AstNode *block_node = node->data.fn_call_expr.params.at(0); |
| ... | @@ -18105,7 +18113,7 @@ static ZigType *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstructionE | ... | @@ -18105,7 +18113,7 @@ static ZigType *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstructionE |
| 18105 | // load from file system into const expr | 18113 | // load from file system into const expr |
| 18106 | Buf *file_contents = buf_alloc(); | 18114 | Buf *file_contents = buf_alloc(); |
| 18107 | int err; | 18115 | int err; |
| 18108 | if ((err = os_fetch_file_path(&file_path, file_contents, false))) { | 18116 | if ((err = file_fetch(ira->codegen, &file_path, file_contents))) { |
| 18109 | if (err == ErrorFileNotFound) { | 18117 | if (err == ErrorFileNotFound) { |
| 18110 | ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path))); | 18118 | ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path))); |
| 18111 | return ira->codegen->builtin_types.entry_invalid; | 18119 | return ira->codegen->builtin_types.entry_invalid; |
| ... | @@ -18115,9 +18123,6 @@ static ZigType *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstructionE | ... | @@ -18115,9 +18123,6 @@ static ZigType *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstructionE |
| 18115 | } | 18123 | } |
| 18116 | } | 18124 | } |
| 18117 | 18125 | ||
| 18118 | // TODO add dependency on the file we embedded so that we know if it changes | ||
| 18119 | // we'll have to invalidate the cache | ||
| 18120 | |||
| 18121 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | 18126 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 18122 | init_const_str_lit(ira->codegen, out_val, file_contents); | 18127 | init_const_str_lit(ira->codegen, out_val, file_contents); |
| 18123 | 18128 |
src/link.cpp+18-61| ... | @@ -5,7 +5,6 @@ | ... | @@ -5,7 +5,6 @@ |
| 5 | * See http://opensource.org/licenses/MIT | 5 | * See http://opensource.org/licenses/MIT |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include "link.hpp" | ||
| 9 | #include "os.hpp" | 8 | #include "os.hpp" |
| 10 | #include "config.h" | 9 | #include "config.h" |
| 11 | #include "codegen.hpp" | 10 | #include "codegen.hpp" |
| ... | @@ -13,7 +12,6 @@ | ... | @@ -13,7 +12,6 @@ |
| 13 | 12 | ||
| 14 | struct LinkJob { | 13 | struct LinkJob { |
| 15 | CodeGen *codegen; | 14 | CodeGen *codegen; |
| 16 | Buf out_file; | ||
| 17 | ZigList<const char *> args; | 15 | ZigList<const char *> args; |
| 18 | bool link_in_crt; | 16 | bool link_in_crt; |
| 19 | HashMap<Buf *, bool, buf_hash, buf_eql_buf> rpath_table; | 17 | HashMap<Buf *, bool, buf_hash, buf_eql_buf> rpath_table; |
| ... | @@ -44,8 +42,6 @@ static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path) | ... | @@ -44,8 +42,6 @@ static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path) |
| 44 | child_gen->verbose_llvm_ir = parent_gen->verbose_llvm_ir; | 42 | child_gen->verbose_llvm_ir = parent_gen->verbose_llvm_ir; |
| 45 | child_gen->verbose_cimport = parent_gen->verbose_cimport; | 43 | child_gen->verbose_cimport = parent_gen->verbose_cimport; |
| 46 | 44 | ||
| 47 | codegen_set_cache_dir(child_gen, parent_gen->cache_dir); | ||
| 48 | |||
| 49 | codegen_set_strip(child_gen, parent_gen->strip_debug_symbols); | 45 | codegen_set_strip(child_gen, parent_gen->strip_debug_symbols); |
| 50 | codegen_set_is_static(child_gen, parent_gen->is_static); | 46 | codegen_set_is_static(child_gen, parent_gen->is_static); |
| 51 | 47 | ||
| ... | @@ -62,16 +58,9 @@ static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path) | ... | @@ -62,16 +58,9 @@ static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path) |
| 62 | new_link_lib->provided_explicitly = link_lib->provided_explicitly; | 58 | new_link_lib->provided_explicitly = link_lib->provided_explicitly; |
| 63 | } | 59 | } |
| 64 | 60 | ||
| 65 | codegen_build(child_gen); | 61 | child_gen->enable_cache = true; |
| 66 | const char *o_ext = target_o_file_ext(&child_gen->zig_target); | 62 | codegen_build_and_link(child_gen); |
| 67 | Buf *o_out_name = buf_sprintf("%s%s", oname, o_ext); | 63 | return &child_gen->output_file_path; |
| 68 | Buf *output_path = buf_alloc(); | ||
| 69 | os_path_join(&parent_gen->cache_dir, o_out_name, output_path); | ||
| 70 | codegen_link(child_gen, buf_ptr(output_path)); | ||
| 71 | |||
| 72 | codegen_destroy(child_gen); | ||
| 73 | |||
| 74 | return output_path; | ||
| 75 | } | 64 | } |
| 76 | 65 | ||
| 77 | static Buf *build_o(CodeGen *parent_gen, const char *oname) { | 66 | static Buf *build_o(CodeGen *parent_gen, const char *oname) { |
| ... | @@ -239,15 +228,15 @@ static void construct_linker_job_elf(LinkJob *lj) { | ... | @@ -239,15 +228,15 @@ static void construct_linker_job_elf(LinkJob *lj) { |
| 239 | } else if (shared) { | 228 | } else if (shared) { |
| 240 | lj->args.append("-shared"); | 229 | lj->args.append("-shared"); |
| 241 | 230 | ||
| 242 | if (buf_len(&lj->out_file) == 0) { | 231 | if (buf_len(&g->output_file_path) == 0) { |
| 243 | buf_appendf(&lj->out_file, "lib%s.so.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize "", | 232 | buf_appendf(&g->output_file_path, "lib%s.so.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize "", |
| 244 | buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch); | 233 | buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch); |
| 245 | } | 234 | } |
| 246 | soname = buf_sprintf("lib%s.so.%" ZIG_PRI_usize "", buf_ptr(g->root_out_name), g->version_major); | 235 | soname = buf_sprintf("lib%s.so.%" ZIG_PRI_usize "", buf_ptr(g->root_out_name), g->version_major); |
| 247 | } | 236 | } |
| 248 | 237 | ||
| 249 | lj->args.append("-o"); | 238 | lj->args.append("-o"); |
| 250 | lj->args.append(buf_ptr(&lj->out_file)); | 239 | lj->args.append(buf_ptr(&g->output_file_path)); |
| 251 | 240 | ||
| 252 | if (lj->link_in_crt) { | 241 | if (lj->link_in_crt) { |
| 253 | const char *crt1o; | 242 | const char *crt1o; |
| ... | @@ -399,7 +388,7 @@ static void construct_linker_job_wasm(LinkJob *lj) { | ... | @@ -399,7 +388,7 @@ static void construct_linker_job_wasm(LinkJob *lj) { |
| 399 | 388 | ||
| 400 | lj->args.append("--relocatable"); // So lld doesn't look for _start. | 389 | lj->args.append("--relocatable"); // So lld doesn't look for _start. |
| 401 | lj->args.append("-o"); | 390 | lj->args.append("-o"); |
| 402 | lj->args.append(buf_ptr(&lj->out_file)); | 391 | lj->args.append(buf_ptr(&g->output_file_path)); |
| 403 | 392 | ||
| 404 | // .o files | 393 | // .o files |
| 405 | for (size_t i = 0; i < g->link_objects.length; i += 1) { | 394 | for (size_t i = 0; i < g->link_objects.length; i += 1) { |
| ... | @@ -480,7 +469,7 @@ static void construct_linker_job_coff(LinkJob *lj) { | ... | @@ -480,7 +469,7 @@ static void construct_linker_job_coff(LinkJob *lj) { |
| 480 | // } | 469 | // } |
| 481 | //} | 470 | //} |
| 482 | 471 | ||
| 483 | lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&lj->out_file)))); | 472 | lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path)))); |
| 484 | 473 | ||
| 485 | if (g->libc_link_lib != nullptr) { | 474 | if (g->libc_link_lib != nullptr) { |
| 486 | lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->msvc_lib_dir)))); | 475 | lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->msvc_lib_dir)))); |
| ... | @@ -587,11 +576,11 @@ static void construct_linker_job_coff(LinkJob *lj) { | ... | @@ -587,11 +576,11 @@ static void construct_linker_job_coff(LinkJob *lj) { |
| 587 | buf_appendf(def_contents, "\n"); | 576 | buf_appendf(def_contents, "\n"); |
| 588 | 577 | ||
| 589 | Buf *def_path = buf_alloc(); | 578 | Buf *def_path = buf_alloc(); |
| 590 | os_path_join(&g->cache_dir, buf_sprintf("%s.def", buf_ptr(link_lib->name)), def_path); | 579 | os_path_join(&g->artifact_dir, buf_sprintf("%s.def", buf_ptr(link_lib->name)), def_path); |
| 591 | os_write_file(def_path, def_contents); | 580 | os_write_file(def_path, def_contents); |
| 592 | 581 | ||
| 593 | Buf *generated_lib_path = buf_alloc(); | 582 | Buf *generated_lib_path = buf_alloc(); |
| 594 | os_path_join(&g->cache_dir, buf_sprintf("%s.lib", buf_ptr(link_lib->name)), generated_lib_path); | 583 | os_path_join(&g->artifact_dir, buf_sprintf("%s.lib", buf_ptr(link_lib->name)), generated_lib_path); |
| 595 | 584 | ||
| 596 | gen_lib_args.resize(0); | 585 | gen_lib_args.resize(0); |
| 597 | gen_lib_args.append("link"); | 586 | gen_lib_args.append("link"); |
| ... | @@ -799,8 +788,8 @@ static void construct_linker_job_macho(LinkJob *lj) { | ... | @@ -799,8 +788,8 @@ static void construct_linker_job_macho(LinkJob *lj) { |
| 799 | //lj->args.append("-install_name"); | 788 | //lj->args.append("-install_name"); |
| 800 | //lj->args.append(buf_ptr(dylib_install_name)); | 789 | //lj->args.append(buf_ptr(dylib_install_name)); |
| 801 | 790 | ||
| 802 | if (buf_len(&lj->out_file) == 0) { | 791 | if (buf_len(&g->output_file_path) == 0) { |
| 803 | buf_appendf(&lj->out_file, "lib%s.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".dylib", | 792 | buf_appendf(&g->output_file_path, "lib%s.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".dylib", |
| 804 | buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch); | 793 | buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch); |
| 805 | } | 794 | } |
| 806 | } | 795 | } |
| ... | @@ -834,13 +823,13 @@ static void construct_linker_job_macho(LinkJob *lj) { | ... | @@ -834,13 +823,13 @@ static void construct_linker_job_macho(LinkJob *lj) { |
| 834 | } | 823 | } |
| 835 | 824 | ||
| 836 | lj->args.append("-o"); | 825 | lj->args.append("-o"); |
| 837 | lj->args.append(buf_ptr(&lj->out_file)); | 826 | lj->args.append(buf_ptr(&g->output_file_path)); |
| 838 | 827 | ||
| 839 | for (size_t i = 0; i < g->rpath_list.length; i += 1) { | 828 | for (size_t i = 0; i < g->rpath_list.length; i += 1) { |
| 840 | Buf *rpath = g->rpath_list.at(i); | 829 | Buf *rpath = g->rpath_list.at(i); |
| 841 | add_rpath(lj, rpath); | 830 | add_rpath(lj, rpath); |
| 842 | } | 831 | } |
| 843 | add_rpath(lj, &lj->out_file); | 832 | add_rpath(lj, &g->output_file_path); |
| 844 | 833 | ||
| 845 | if (shared) { | 834 | if (shared) { |
| 846 | lj->args.append("-headerpad_max_install_names"); | 835 | lj->args.append("-headerpad_max_install_names"); |
| ... | @@ -944,7 +933,8 @@ static void construct_linker_job(LinkJob *lj) { | ... | @@ -944,7 +933,8 @@ static void construct_linker_job(LinkJob *lj) { |
| 944 | } | 933 | } |
| 945 | } | 934 | } |
| 946 | 935 | ||
| 947 | void codegen_link(CodeGen *g, const char *out_file) { | 936 | void codegen_link(CodeGen *g) { |
| 937 | assert(g->out_type != OutTypeObj); | ||
| 948 | codegen_add_time_event(g, "Build Dependencies"); | 938 | codegen_add_time_event(g, "Build Dependencies"); |
| 949 | 939 | ||
| 950 | LinkJob lj = {0}; | 940 | LinkJob lj = {0}; |
| ... | @@ -955,11 +945,6 @@ void codegen_link(CodeGen *g, const char *out_file) { | ... | @@ -955,11 +945,6 @@ void codegen_link(CodeGen *g, const char *out_file) { |
| 955 | 945 | ||
| 956 | lj.rpath_table.init(4); | 946 | lj.rpath_table.init(4); |
| 957 | lj.codegen = g; | 947 | lj.codegen = g; |
| 958 | if (out_file) { | ||
| 959 | buf_init_from_str(&lj.out_file, out_file); | ||
| 960 | } else { | ||
| 961 | buf_resize(&lj.out_file, 0); | ||
| 962 | } | ||
| 963 | 948 | ||
| 964 | if (g->verbose_llvm_ir) { | 949 | if (g->verbose_llvm_ir) { |
| 965 | fprintf(stderr, "\nOptimization:\n"); | 950 | fprintf(stderr, "\nOptimization:\n"); |
| ... | @@ -968,35 +953,9 @@ void codegen_link(CodeGen *g, const char *out_file) { | ... | @@ -968,35 +953,9 @@ void codegen_link(CodeGen *g, const char *out_file) { |
| 968 | LLVMDumpModule(g->module); | 953 | LLVMDumpModule(g->module); |
| 969 | } | 954 | } |
| 970 | 955 | ||
| 971 | bool override_out_file = (buf_len(&lj.out_file) != 0); | ||
| 972 | if (!override_out_file) { | ||
| 973 | assert(g->root_out_name); | ||
| 974 | |||
| 975 | buf_init_from_buf(&lj.out_file, g->root_out_name); | ||
| 976 | if (g->out_type == OutTypeExe) { | ||
| 977 | buf_append_str(&lj.out_file, target_exe_file_ext(&g->zig_target)); | ||
| 978 | } | ||
| 979 | } | ||
| 980 | |||
| 981 | if (g->out_type == OutTypeObj) { | ||
| 982 | if (override_out_file) { | ||
| 983 | assert(g->link_objects.length == 1); | ||
| 984 | Buf *o_file_path = g->link_objects.at(0); | ||
| 985 | int err; | ||
| 986 | if ((err = os_rename(o_file_path, &lj.out_file))) { | ||
| 987 | zig_panic("unable to rename object file %s into final output %s: %s", buf_ptr(o_file_path), buf_ptr(&lj.out_file), err_str(err)); | ||
| 988 | } | ||
| 989 | } | ||
| 990 | return; | ||
| 991 | } | ||
| 992 | |||
| 993 | if (g->out_type == OutTypeLib && g->is_static) { | 956 | if (g->out_type == OutTypeLib && g->is_static) { |
| 994 | // invoke `ar` | 957 | fprintf(stderr, "Zig does not yet support creating static libraries\nSee https://github.com/ziglang/zig/issues/1493\n"); |
| 995 | // example: | 958 | exit(1); |
| 996 | // # static link into libfoo.a | ||
| 997 | // ar rcs libfoo.a foo1.o foo2.o | ||
| 998 | zig_panic("TODO invoke ar"); | ||
| 999 | return; | ||
| 1000 | } | 959 | } |
| 1001 | 960 | ||
| 1002 | lj.link_in_crt = (g->libc_link_lib != nullptr && g->out_type == OutTypeExe); | 961 | lj.link_in_crt = (g->libc_link_lib != nullptr && g->out_type == OutTypeExe); |
| ... | @@ -1019,6 +978,4 @@ void codegen_link(CodeGen *g, const char *out_file) { | ... | @@ -1019,6 +978,4 @@ void codegen_link(CodeGen *g, const char *out_file) { |
| 1019 | fprintf(stderr, "%s\n", buf_ptr(&diag)); | 978 | fprintf(stderr, "%s\n", buf_ptr(&diag)); |
| 1020 | exit(1); | 979 | exit(1); |
| 1021 | } | 980 | } |
| 1022 | |||
| 1023 | codegen_add_time_event(g, "Done"); | ||
| 1024 | } | 981 | } |
src/link.hpp deleted-17| ... | @@ -1,17 +0,0 @@ | ||
| 1 | /* | ||
| 2 | * Copyright (c) 2015 Andrew Kelley | ||
| 3 | * | ||
| 4 | * This file is part of zig, which is MIT licensed. | ||
| 5 | * See http://opensource.org/licenses/MIT | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef ZIG_LINK_HPP | ||
| 9 | #define ZIG_LINK_HPP | ||
| 10 | |||
| 11 | #include "all_types.hpp" | ||
| 12 | |||
| 13 | void codegen_link(CodeGen *g, const char *out_file); | ||
| 14 | |||
| 15 | |||
| 16 | #endif | ||
| 17 | |||
src/main.cpp+93-52| ... | @@ -8,9 +8,9 @@ | ... | @@ -8,9 +8,9 @@ |
| 8 | #include "ast_render.hpp" | 8 | #include "ast_render.hpp" |
| 9 | #include "buffer.hpp" | 9 | #include "buffer.hpp" |
| 10 | #include "codegen.hpp" | 10 | #include "codegen.hpp" |
| 11 | #include "compiler.hpp" | ||
| 11 | #include "config.h" | 12 | #include "config.h" |
| 12 | #include "error.hpp" | 13 | #include "error.hpp" |
| 13 | #include "link.hpp" | ||
| 14 | #include "os.hpp" | 14 | #include "os.hpp" |
| 15 | #include "target.hpp" | 15 | #include "target.hpp" |
| 16 | 16 | ||
| ... | @@ -24,6 +24,7 @@ static int usage(const char *arg0) { | ... | @@ -24,6 +24,7 @@ static int usage(const char *arg0) { |
| 24 | " build-lib [source] create library from source or object files\n" | 24 | " build-lib [source] create library from source or object files\n" |
| 25 | " build-obj [source] create object from source or assembly\n" | 25 | " build-obj [source] create object from source or assembly\n" |
| 26 | " builtin show the source code of that @import(\"builtin\")\n" | 26 | " builtin show the source code of that @import(\"builtin\")\n" |
| 27 | " id print the base64-encoded compiler id\n" | ||
| 27 | " run [source] create executable and run immediately\n" | 28 | " run [source] create executable and run immediately\n" |
| 28 | " translate-c [source] convert c code to zig code\n" | 29 | " translate-c [source] convert c code to zig code\n" |
| 29 | " targets list available compilation targets\n" | 30 | " targets list available compilation targets\n" |
| ... | @@ -33,9 +34,10 @@ static int usage(const char *arg0) { | ... | @@ -33,9 +34,10 @@ static int usage(const char *arg0) { |
| 33 | "Compile Options:\n" | 34 | "Compile Options:\n" |
| 34 | " --assembly [source] add assembly file to build\n" | 35 | " --assembly [source] add assembly file to build\n" |
| 35 | " --cache-dir [path] override the cache directory\n" | 36 | " --cache-dir [path] override the cache directory\n" |
| 37 | " --cache [auto|off|on] build to the global cache and print output path to stdout\n" | ||
| 36 | " --color [auto|off|on] enable or disable colored error messages\n" | 38 | " --color [auto|off|on] enable or disable colored error messages\n" |
| 37 | " --emit [asm|bin|llvm-ir] emit a specific file format as compilation output\n" | 39 | " --emit [asm|bin|llvm-ir] emit a specific file format as compilation output\n" |
| 38 | " --enable-timing-info print timing diagnostics\n" | 40 | " -ftime-report print timing diagnostics\n" |
| 39 | " --libc-include-dir [path] directory where libc stdlib.h resides\n" | 41 | " --libc-include-dir [path] directory where libc stdlib.h resides\n" |
| 40 | " --name [name] override output name\n" | 42 | " --name [name] override output name\n" |
| 41 | " --output [file] override destination path\n" | 43 | " --output [file] override destination path\n" |
| ... | @@ -256,6 +258,24 @@ static void add_package(CodeGen *g, CliPkg *cli_pkg, PackageTableEntry *pkg) { | ... | @@ -256,6 +258,24 @@ static void add_package(CodeGen *g, CliPkg *cli_pkg, PackageTableEntry *pkg) { |
| 256 | } | 258 | } |
| 257 | } | 259 | } |
| 258 | 260 | ||
| 261 | enum CacheOpt { | ||
| 262 | CacheOptAuto, | ||
| 263 | CacheOptOn, | ||
| 264 | CacheOptOff, | ||
| 265 | }; | ||
| 266 | |||
| 267 | static bool get_cache_opt(CacheOpt opt, bool default_value) { | ||
| 268 | switch (opt) { | ||
| 269 | case CacheOptAuto: | ||
| 270 | return default_value; | ||
| 271 | case CacheOptOn: | ||
| 272 | return true; | ||
| 273 | case CacheOptOff: | ||
| 274 | return false; | ||
| 275 | } | ||
| 276 | zig_unreachable(); | ||
| 277 | } | ||
| 278 | |||
| 259 | int main(int argc, char **argv) { | 279 | int main(int argc, char **argv) { |
| 260 | if (argc == 2 && strcmp(argv[1], "BUILD_INFO") == 0) { | 280 | if (argc == 2 && strcmp(argv[1], "BUILD_INFO") == 0) { |
| 261 | printf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", | 281 | printf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", |
| ... | @@ -270,6 +290,17 @@ int main(int argc, char **argv) { | ... | @@ -270,6 +290,17 @@ int main(int argc, char **argv) { |
| 270 | return 0; | 290 | return 0; |
| 271 | } | 291 | } |
| 272 | 292 | ||
| 293 | if (argc == 2 && strcmp(argv[1], "id") == 0) { | ||
| 294 | Error err; | ||
| 295 | Buf *compiler_id; | ||
| 296 | if ((err = get_compiler_id(&compiler_id))) { | ||
| 297 | fprintf(stderr, "Unable to determine compiler id: %s\n", err_str(err)); | ||
| 298 | return EXIT_FAILURE; | ||
| 299 | } | ||
| 300 | printf("%s\n", buf_ptr(compiler_id)); | ||
| 301 | return EXIT_SUCCESS; | ||
| 302 | } | ||
| 303 | |||
| 273 | os_init(); | 304 | os_init(); |
| 274 | 305 | ||
| 275 | char *arg0 = argv[0]; | 306 | char *arg0 = argv[0]; |
| ... | @@ -289,6 +320,7 @@ int main(int argc, char **argv) { | ... | @@ -289,6 +320,7 @@ int main(int argc, char **argv) { |
| 289 | bool verbose_llvm_ir = false; | 320 | bool verbose_llvm_ir = false; |
| 290 | bool verbose_cimport = false; | 321 | bool verbose_cimport = false; |
| 291 | ErrColor color = ErrColorAuto; | 322 | ErrColor color = ErrColorAuto; |
| 323 | CacheOpt enable_cache = CacheOptAuto; | ||
| 292 | const char *libc_lib_dir = nullptr; | 324 | const char *libc_lib_dir = nullptr; |
| 293 | const char *libc_static_lib_dir = nullptr; | 325 | const char *libc_static_lib_dir = nullptr; |
| 294 | const char *libc_include_dir = nullptr; | 326 | const char *libc_include_dir = nullptr; |
| ... | @@ -325,8 +357,7 @@ int main(int argc, char **argv) { | ... | @@ -325,8 +357,7 @@ int main(int argc, char **argv) { |
| 325 | CliPkg *cur_pkg = allocate<CliPkg>(1); | 357 | CliPkg *cur_pkg = allocate<CliPkg>(1); |
| 326 | BuildMode build_mode = BuildModeDebug; | 358 | BuildMode build_mode = BuildModeDebug; |
| 327 | ZigList<const char *> test_exec_args = {0}; | 359 | ZigList<const char *> test_exec_args = {0}; |
| 328 | int comptime_args_end = 0; | 360 | int runtime_args_start = -1; |
| 329 | int runtime_args_start = argc; | ||
| 330 | bool no_rosegment_workaround = false; | 361 | bool no_rosegment_workaround = false; |
| 331 | 362 | ||
| 332 | if (argc >= 2 && strcmp(argv[1], "build") == 0) { | 363 | if (argc >= 2 && strcmp(argv[1], "build") == 0) { |
| ... | @@ -370,8 +401,9 @@ int main(int argc, char **argv) { | ... | @@ -370,8 +401,9 @@ int main(int argc, char **argv) { |
| 370 | Buf *build_runner_path = buf_alloc(); | 401 | Buf *build_runner_path = buf_alloc(); |
| 371 | os_path_join(special_dir, buf_create_from_str("build_runner.zig"), build_runner_path); | 402 | os_path_join(special_dir, buf_create_from_str("build_runner.zig"), build_runner_path); |
| 372 | 403 | ||
| 373 | |||
| 374 | CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, zig_lib_dir_buf); | 404 | CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, zig_lib_dir_buf); |
| 405 | g->enable_time_report = timing_info; | ||
| 406 | buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name); | ||
| 375 | codegen_set_out_name(g, buf_create_from_str("build")); | 407 | codegen_set_out_name(g, buf_create_from_str("build")); |
| 376 | 408 | ||
| 377 | Buf *build_file_buf = buf_create_from_str(build_file); | 409 | Buf *build_file_buf = buf_create_from_str(build_file); |
| ... | @@ -380,6 +412,7 @@ int main(int argc, char **argv) { | ... | @@ -380,6 +412,7 @@ int main(int argc, char **argv) { |
| 380 | Buf build_file_dirname = BUF_INIT; | 412 | Buf build_file_dirname = BUF_INIT; |
| 381 | os_path_split(&build_file_abs, &build_file_dirname, &build_file_basename); | 413 | os_path_split(&build_file_abs, &build_file_dirname, &build_file_basename); |
| 382 | 414 | ||
| 415 | |||
| 383 | Buf full_cache_dir = BUF_INIT; | 416 | Buf full_cache_dir = BUF_INIT; |
| 384 | if (cache_dir == nullptr) { | 417 | if (cache_dir == nullptr) { |
| 385 | os_path_join(&build_file_dirname, buf_create_from_str(default_zig_cache_name), &full_cache_dir); | 418 | os_path_join(&build_file_dirname, buf_create_from_str(default_zig_cache_name), &full_cache_dir); |
| ... | @@ -388,10 +421,6 @@ int main(int argc, char **argv) { | ... | @@ -388,10 +421,6 @@ int main(int argc, char **argv) { |
| 388 | full_cache_dir = os_path_resolve(&cache_dir_buf, 1); | 421 | full_cache_dir = os_path_resolve(&cache_dir_buf, 1); |
| 389 | } | 422 | } |
| 390 | 423 | ||
| 391 | Buf *path_to_build_exe = buf_alloc(); | ||
| 392 | os_path_join(&full_cache_dir, buf_create_from_str("build"), path_to_build_exe); | ||
| 393 | codegen_set_cache_dir(g, full_cache_dir); | ||
| 394 | |||
| 395 | args.items[1] = buf_ptr(&build_file_dirname); | 424 | args.items[1] = buf_ptr(&build_file_dirname); |
| 396 | args.items[2] = buf_ptr(&full_cache_dir); | 425 | args.items[2] = buf_ptr(&full_cache_dir); |
| 397 | 426 | ||
| ... | @@ -459,15 +488,14 @@ int main(int argc, char **argv) { | ... | @@ -459,15 +488,14 @@ int main(int argc, char **argv) { |
| 459 | PackageTableEntry *build_pkg = codegen_create_package(g, buf_ptr(&build_file_dirname), | 488 | PackageTableEntry *build_pkg = codegen_create_package(g, buf_ptr(&build_file_dirname), |
| 460 | buf_ptr(&build_file_basename)); | 489 | buf_ptr(&build_file_basename)); |
| 461 | g->root_package->package_table.put(buf_create_from_str("@build"), build_pkg); | 490 | g->root_package->package_table.put(buf_create_from_str("@build"), build_pkg); |
| 462 | codegen_build(g); | 491 | g->enable_cache = get_cache_opt(enable_cache, true); |
| 463 | codegen_link(g, buf_ptr(path_to_build_exe)); | 492 | codegen_build_and_link(g); |
| 464 | codegen_destroy(g); | ||
| 465 | 493 | ||
| 466 | Termination term; | 494 | Termination term; |
| 467 | os_spawn_process(buf_ptr(path_to_build_exe), args, &term); | 495 | os_spawn_process(buf_ptr(&g->output_file_path), args, &term); |
| 468 | if (term.how != TerminationIdClean || term.code != 0) { | 496 | if (term.how != TerminationIdClean || term.code != 0) { |
| 469 | fprintf(stderr, "\nBuild failed. The following command failed:\n"); | 497 | fprintf(stderr, "\nBuild failed. The following command failed:\n"); |
| 470 | fprintf(stderr, "%s", buf_ptr(path_to_build_exe)); | 498 | fprintf(stderr, "%s", buf_ptr(&g->output_file_path)); |
| 471 | for (size_t i = 0; i < args.length; i += 1) { | 499 | for (size_t i = 0; i < args.length; i += 1) { |
| 472 | fprintf(stderr, " %s", args.at(i)); | 500 | fprintf(stderr, " %s", args.at(i)); |
| 473 | } | 501 | } |
| ... | @@ -476,15 +504,11 @@ int main(int argc, char **argv) { | ... | @@ -476,15 +504,11 @@ int main(int argc, char **argv) { |
| 476 | return (term.how == TerminationIdClean) ? term.code : -1; | 504 | return (term.how == TerminationIdClean) ? term.code : -1; |
| 477 | } | 505 | } |
| 478 | 506 | ||
| 479 | for (int i = 1; i < argc; i += 1, comptime_args_end += 1) { | 507 | for (int i = 1; i < argc; i += 1) { |
| 480 | char *arg = argv[i]; | 508 | char *arg = argv[i]; |
| 481 | 509 | ||
| 482 | if (arg[0] == '-') { | 510 | if (arg[0] == '-') { |
| 483 | if (strcmp(arg, "--") == 0) { | 511 | if (strcmp(arg, "--release-fast") == 0) { |
| 484 | // ignore -- from both compile and runtime arg sets | ||
| 485 | runtime_args_start = i + 1; | ||
| 486 | break; | ||
| 487 | } else if (strcmp(arg, "--release-fast") == 0) { | ||
| 488 | build_mode = BuildModeFastRelease; | 512 | build_mode = BuildModeFastRelease; |
| 489 | } else if (strcmp(arg, "--release-safe") == 0) { | 513 | } else if (strcmp(arg, "--release-safe") == 0) { |
| 490 | build_mode = BuildModeSafeRelease; | 514 | build_mode = BuildModeSafeRelease; |
| ... | @@ -516,7 +540,7 @@ int main(int argc, char **argv) { | ... | @@ -516,7 +540,7 @@ int main(int argc, char **argv) { |
| 516 | no_rosegment_workaround = true; | 540 | no_rosegment_workaround = true; |
| 517 | } else if (strcmp(arg, "--each-lib-rpath") == 0) { | 541 | } else if (strcmp(arg, "--each-lib-rpath") == 0) { |
| 518 | each_lib_rpath = true; | 542 | each_lib_rpath = true; |
| 519 | } else if (strcmp(arg, "--enable-timing-info") == 0) { | 543 | } else if (strcmp(arg, "-ftime-report") == 0) { |
| 520 | timing_info = true; | 544 | timing_info = true; |
| 521 | } else if (strcmp(arg, "--test-cmd-bin") == 0) { | 545 | } else if (strcmp(arg, "--test-cmd-bin") == 0) { |
| 522 | test_exec_args.append(nullptr); | 546 | test_exec_args.append(nullptr); |
| ... | @@ -562,6 +586,17 @@ int main(int argc, char **argv) { | ... | @@ -562,6 +586,17 @@ int main(int argc, char **argv) { |
| 562 | fprintf(stderr, "--color options are 'auto', 'on', or 'off'\n"); | 586 | fprintf(stderr, "--color options are 'auto', 'on', or 'off'\n"); |
| 563 | return usage(arg0); | 587 | return usage(arg0); |
| 564 | } | 588 | } |
| 589 | } else if (strcmp(arg, "--cache") == 0) { | ||
| 590 | if (strcmp(argv[i], "auto") == 0) { | ||
| 591 | enable_cache = CacheOptAuto; | ||
| 592 | } else if (strcmp(argv[i], "on") == 0) { | ||
| 593 | enable_cache = CacheOptOn; | ||
| 594 | } else if (strcmp(argv[i], "off") == 0) { | ||
| 595 | enable_cache = CacheOptOff; | ||
| 596 | } else { | ||
| 597 | fprintf(stderr, "--cache options are 'auto', 'on', or 'off'\n"); | ||
| 598 | return usage(arg0); | ||
| 599 | } | ||
| 565 | } else if (strcmp(arg, "--emit") == 0) { | 600 | } else if (strcmp(arg, "--emit") == 0) { |
| 566 | if (strcmp(argv[i], "asm") == 0) { | 601 | if (strcmp(argv[i], "asm") == 0) { |
| 567 | emit_file_type = EmitFileTypeAssembly; | 602 | emit_file_type = EmitFileTypeAssembly; |
| ... | @@ -681,6 +716,10 @@ int main(int argc, char **argv) { | ... | @@ -681,6 +716,10 @@ int main(int argc, char **argv) { |
| 681 | case CmdTest: | 716 | case CmdTest: |
| 682 | if (!in_file) { | 717 | if (!in_file) { |
| 683 | in_file = arg; | 718 | in_file = arg; |
| 719 | if (cmd == CmdRun) { | ||
| 720 | runtime_args_start = i + 1; | ||
| 721 | break; // rest of the args are for the program | ||
| 722 | } | ||
| 684 | } else { | 723 | } else { |
| 685 | fprintf(stderr, "Unexpected extra parameter: %s\n", arg); | 724 | fprintf(stderr, "Unexpected extra parameter: %s\n", arg); |
| 686 | return usage(arg0); | 725 | return usage(arg0); |
| ... | @@ -790,32 +829,18 @@ int main(int argc, char **argv) { | ... | @@ -790,32 +829,18 @@ int main(int argc, char **argv) { |
| 790 | 829 | ||
| 791 | Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf; | 830 | Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf; |
| 792 | 831 | ||
| 793 | Buf full_cache_dir = BUF_INIT; | 832 | if (cmd == CmdRun && buf_out_name == nullptr) { |
| 794 | Buf *run_exec_path = buf_alloc(); | 833 | buf_out_name = buf_create_from_str("run"); |
| 795 | if (cmd == CmdRun) { | ||
| 796 | if (buf_out_name == nullptr) { | ||
| 797 | buf_out_name = buf_create_from_str("run"); | ||
| 798 | } | ||
| 799 | |||
| 800 | Buf *global_cache_dir = buf_alloc(); | ||
| 801 | os_get_global_cache_directory(global_cache_dir); | ||
| 802 | os_path_join(global_cache_dir, buf_out_name, run_exec_path); | ||
| 803 | full_cache_dir = os_path_resolve(&global_cache_dir, 1); | ||
| 804 | |||
| 805 | out_file = buf_ptr(run_exec_path); | ||
| 806 | } else { | ||
| 807 | Buf *resolve_paths = buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir); | ||
| 808 | full_cache_dir = os_path_resolve(&resolve_paths, 1); | ||
| 809 | } | 834 | } |
| 810 | |||
| 811 | Buf *zig_lib_dir_buf = resolve_zig_lib_dir(); | 835 | Buf *zig_lib_dir_buf = resolve_zig_lib_dir(); |
| 812 | 836 | ||
| 813 | CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, zig_lib_dir_buf); | 837 | CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, zig_lib_dir_buf); |
| 838 | g->enable_time_report = timing_info; | ||
| 839 | buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name); | ||
| 814 | codegen_set_out_name(g, buf_out_name); | 840 | codegen_set_out_name(g, buf_out_name); |
| 815 | codegen_set_lib_version(g, ver_major, ver_minor, ver_patch); | 841 | codegen_set_lib_version(g, ver_major, ver_minor, ver_patch); |
| 816 | codegen_set_is_test(g, cmd == CmdTest); | 842 | codegen_set_is_test(g, cmd == CmdTest); |
| 817 | codegen_set_linker_script(g, linker_script); | 843 | codegen_set_linker_script(g, linker_script); |
| 818 | codegen_set_cache_dir(g, full_cache_dir); | ||
| 819 | if (each_lib_rpath) | 844 | if (each_lib_rpath) |
| 820 | codegen_set_each_lib_rpath(g, each_lib_rpath); | 845 | codegen_set_each_lib_rpath(g, each_lib_rpath); |
| 821 | 846 | ||
| ... | @@ -885,6 +910,8 @@ int main(int argc, char **argv) { | ... | @@ -885,6 +910,8 @@ int main(int argc, char **argv) { |
| 885 | codegen_set_test_name_prefix(g, buf_create_from_str(test_name_prefix)); | 910 | codegen_set_test_name_prefix(g, buf_create_from_str(test_name_prefix)); |
| 886 | } | 911 | } |
| 887 | 912 | ||
| 913 | if (out_file) | ||
| 914 | codegen_set_output_path(g, buf_create_from_str(out_file)); | ||
| 888 | if (out_file_h) | 915 | if (out_file_h) |
| 889 | codegen_set_output_h_path(g, buf_create_from_str(out_file_h)); | 916 | codegen_set_output_h_path(g, buf_create_from_str(out_file_h)); |
| 890 | 917 | ||
| ... | @@ -904,8 +931,8 @@ int main(int argc, char **argv) { | ... | @@ -904,8 +931,8 @@ int main(int argc, char **argv) { |
| 904 | if (cmd == CmdBuild || cmd == CmdRun) { | 931 | if (cmd == CmdBuild || cmd == CmdRun) { |
| 905 | codegen_set_emit_file_type(g, emit_file_type); | 932 | codegen_set_emit_file_type(g, emit_file_type); |
| 906 | 933 | ||
| 907 | codegen_build(g); | 934 | g->enable_cache = get_cache_opt(enable_cache, cmd == CmdRun); |
| 908 | codegen_link(g, out_file); | 935 | codegen_build_and_link(g); |
| 909 | if (timing_info) | 936 | if (timing_info) |
| 910 | codegen_print_timing_report(g, stdout); | 937 | codegen_print_timing_report(g, stdout); |
| 911 | 938 | ||
| ... | @@ -915,12 +942,26 @@ int main(int argc, char **argv) { | ... | @@ -915,12 +942,26 @@ int main(int argc, char **argv) { |
| 915 | args.append(argv[i]); | 942 | args.append(argv[i]); |
| 916 | } | 943 | } |
| 917 | 944 | ||
| 945 | const char *exec_path = buf_ptr(&g->output_file_path); | ||
| 946 | args.append(nullptr); | ||
| 947 | |||
| 948 | os_execv(exec_path, args.items); | ||
| 949 | |||
| 950 | args.pop(); | ||
| 918 | Termination term; | 951 | Termination term; |
| 919 | os_spawn_process(buf_ptr(run_exec_path), args, &term); | 952 | os_spawn_process(exec_path, args, &term); |
| 920 | return term.code; | 953 | return term.code; |
| 954 | } else if (cmd == CmdBuild) { | ||
| 955 | if (g->enable_cache) { | ||
| 956 | printf("%s\n", buf_ptr(&g->output_file_path)); | ||
| 957 | if (g->out_h_path != nullptr) { | ||
| 958 | printf("%s\n", buf_ptr(g->out_h_path)); | ||
| 959 | } | ||
| 960 | } | ||
| 961 | return EXIT_SUCCESS; | ||
| 962 | } else { | ||
| 963 | zig_unreachable(); | ||
| 921 | } | 964 | } |
| 922 | |||
| 923 | return EXIT_SUCCESS; | ||
| 924 | } else if (cmd == CmdTranslateC) { | 965 | } else if (cmd == CmdTranslateC) { |
| 925 | codegen_translate_c(g, in_file_buf); | 966 | codegen_translate_c(g, in_file_buf); |
| 926 | ast_render(g, stdout, g->root_import->root, 4); | 967 | ast_render(g, stdout, g->root_import->root, 4); |
| ... | @@ -933,11 +974,16 @@ int main(int argc, char **argv) { | ... | @@ -933,11 +974,16 @@ int main(int argc, char **argv) { |
| 933 | ZigTarget native; | 974 | ZigTarget native; |
| 934 | get_native_target(&native); | 975 | get_native_target(&native); |
| 935 | 976 | ||
| 936 | ZigTarget *non_null_target = target ? target : &native; | 977 | g->enable_cache = get_cache_opt(enable_cache, false); |
| 978 | codegen_build_and_link(g); | ||
| 937 | 979 | ||
| 938 | Buf *test_exe_name = buf_sprintf("test%s", target_exe_file_ext(non_null_target)); | 980 | if (timing_info) { |
| 981 | codegen_print_timing_report(g, stdout); | ||
| 982 | } | ||
| 983 | |||
| 984 | Buf *test_exe_path_unresolved = &g->output_file_path; | ||
| 939 | Buf *test_exe_path = buf_alloc(); | 985 | Buf *test_exe_path = buf_alloc(); |
| 940 | os_path_join(&full_cache_dir, test_exe_name, test_exe_path); | 986 | *test_exe_path = os_path_resolve(&test_exe_path_unresolved, 1); |
| 941 | 987 | ||
| 942 | for (size_t i = 0; i < test_exec_args.length; i += 1) { | 988 | for (size_t i = 0; i < test_exec_args.length; i += 1) { |
| 943 | if (test_exec_args.items[i] == nullptr) { | 989 | if (test_exec_args.items[i] == nullptr) { |
| ... | @@ -945,9 +991,6 @@ int main(int argc, char **argv) { | ... | @@ -945,9 +991,6 @@ int main(int argc, char **argv) { |
| 945 | } | 991 | } |
| 946 | } | 992 | } |
| 947 | 993 | ||
| 948 | codegen_build(g); | ||
| 949 | codegen_link(g, buf_ptr(test_exe_path)); | ||
| 950 | |||
| 951 | if (!target_can_exec(&native, target)) { | 994 | if (!target_can_exec(&native, target)) { |
| 952 | fprintf(stderr, "Created %s but skipping execution because it is non-native.\n", | 995 | fprintf(stderr, "Created %s but skipping execution because it is non-native.\n", |
| 953 | buf_ptr(test_exe_path)); | 996 | buf_ptr(test_exe_path)); |
| ... | @@ -969,8 +1012,6 @@ int main(int argc, char **argv) { | ... | @@ -969,8 +1012,6 @@ int main(int argc, char **argv) { |
| 969 | if (term.how != TerminationIdClean || term.code != 0) { | 1012 | if (term.how != TerminationIdClean || term.code != 0) { |
| 970 | fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n"); | 1013 | fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n"); |
| 971 | fprintf(stderr, "%s\n", buf_ptr(test_exe_path)); | 1014 | fprintf(stderr, "%s\n", buf_ptr(test_exe_path)); |
| 972 | } else if (timing_info) { | ||
| 973 | codegen_print_timing_report(g, stdout); | ||
| 974 | } | 1015 | } |
| 975 | return (term.how == TerminationIdClean) ? term.code : -1; | 1016 | return (term.how == TerminationIdClean) ? term.code : -1; |
| 976 | } else { | 1017 | } else { |
src/os.cpp+479-120| ... | @@ -24,6 +24,7 @@ | ... | @@ -24,6 +24,7 @@ |
| 24 | #endif | 24 | #endif |
| 25 | 25 | ||
| 26 | #include <windows.h> | 26 | #include <windows.h> |
| 27 | #include <shlobj.h> | ||
| 27 | #include <io.h> | 28 | #include <io.h> |
| 28 | #include <fcntl.h> | 29 | #include <fcntl.h> |
| 29 | 30 | ||
| ... | @@ -40,6 +41,10 @@ typedef SSIZE_T ssize_t; | ... | @@ -40,6 +41,10 @@ typedef SSIZE_T ssize_t; |
| 40 | 41 | ||
| 41 | #endif | 42 | #endif |
| 42 | 43 | ||
| 44 | #if defined(ZIG_OS_LINUX) | ||
| 45 | #include <link.h> | ||
| 46 | #endif | ||
| 47 | |||
| 43 | 48 | ||
| 44 | #if defined(__MACH__) | 49 | #if defined(__MACH__) |
| 45 | #include <mach/clock.h> | 50 | #include <mach/clock.h> |
| ... | @@ -57,54 +62,6 @@ static clock_serv_t cclock; | ... | @@ -57,54 +62,6 @@ static clock_serv_t cclock; |
| 57 | #include <errno.h> | 62 | #include <errno.h> |
| 58 | #include <time.h> | 63 | #include <time.h> |
| 59 | 64 | ||
| 60 | // Ported from std/mem.zig. | ||
| 61 | // Coordinate struct fields with memSplit function | ||
| 62 | struct SplitIterator { | ||
| 63 | size_t index; | ||
| 64 | Slice<uint8_t> buffer; | ||
| 65 | Slice<uint8_t> split_bytes; | ||
| 66 | }; | ||
| 67 | |||
| 68 | // Ported from std/mem.zig. | ||
| 69 | static bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte) { | ||
| 70 | for (size_t i = 0; i < self->split_bytes.len; i += 1) { | ||
| 71 | if (byte == self->split_bytes.ptr[i]) { | ||
| 72 | return true; | ||
| 73 | } | ||
| 74 | } | ||
| 75 | return false; | ||
| 76 | } | ||
| 77 | |||
| 78 | // Ported from std/mem.zig. | ||
| 79 | static Optional<Slice<uint8_t>> SplitIterator_next(SplitIterator *self) { | ||
| 80 | // move to beginning of token | ||
| 81 | while (self->index < self->buffer.len && | ||
| 82 | SplitIterator_isSplitByte(self, self->buffer.ptr[self->index])) | ||
| 83 | { | ||
| 84 | self->index += 1; | ||
| 85 | } | ||
| 86 | size_t start = self->index; | ||
| 87 | if (start == self->buffer.len) { | ||
| 88 | return {}; | ||
| 89 | } | ||
| 90 | |||
| 91 | // move to end of token | ||
| 92 | while (self->index < self->buffer.len && | ||
| 93 | !SplitIterator_isSplitByte(self, self->buffer.ptr[self->index])) | ||
| 94 | { | ||
| 95 | self->index += 1; | ||
| 96 | } | ||
| 97 | size_t end = self->index; | ||
| 98 | |||
| 99 | return Optional<Slice<uint8_t>>::some(self->buffer.slice(start, end)); | ||
| 100 | } | ||
| 101 | |||
| 102 | // Ported from std/mem.zig | ||
| 103 | static SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes) { | ||
| 104 | return SplitIterator{0, buffer, split_bytes}; | ||
| 105 | } | ||
| 106 | |||
| 107 | |||
| 108 | #if defined(ZIG_OS_POSIX) | 65 | #if defined(ZIG_OS_POSIX) |
| 109 | static void populate_termination(Termination *term, int status) { | 66 | static void populate_termination(Termination *term, int status) { |
| 110 | if (WIFEXITED(status)) { | 67 | if (WIFEXITED(status)) { |
| ... | @@ -765,7 +722,7 @@ Buf os_path_resolve(Buf **paths_ptr, size_t paths_len) { | ... | @@ -765,7 +722,7 @@ Buf os_path_resolve(Buf **paths_ptr, size_t paths_len) { |
| 765 | #endif | 722 | #endif |
| 766 | } | 723 | } |
| 767 | 724 | ||
| 768 | int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) { | 725 | Error os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) { |
| 769 | static const ssize_t buf_size = 0x2000; | 726 | static const ssize_t buf_size = 0x2000; |
| 770 | buf_resize(out_buf, buf_size); | 727 | buf_resize(out_buf, buf_size); |
| 771 | ssize_t actual_buf_len = 0; | 728 | ssize_t actual_buf_len = 0; |
| ... | @@ -801,7 +758,7 @@ int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) { | ... | @@ -801,7 +758,7 @@ int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) { |
| 801 | if (amt_read != buf_size) { | 758 | if (amt_read != buf_size) { |
| 802 | if (feof(f)) { | 759 | if (feof(f)) { |
| 803 | buf_resize(out_buf, actual_buf_len); | 760 | buf_resize(out_buf, actual_buf_len); |
| 804 | return 0; | 761 | return ErrorNone; |
| 805 | } else { | 762 | } else { |
| 806 | return ErrorFileSystem; | 763 | return ErrorFileSystem; |
| 807 | } | 764 | } |
| ... | @@ -813,13 +770,13 @@ int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) { | ... | @@ -813,13 +770,13 @@ int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) { |
| 813 | zig_unreachable(); | 770 | zig_unreachable(); |
| 814 | } | 771 | } |
| 815 | 772 | ||
| 816 | int os_file_exists(Buf *full_path, bool *result) { | 773 | Error os_file_exists(Buf *full_path, bool *result) { |
| 817 | #if defined(ZIG_OS_WINDOWS) | 774 | #if defined(ZIG_OS_WINDOWS) |
| 818 | *result = GetFileAttributes(buf_ptr(full_path)) != INVALID_FILE_ATTRIBUTES; | 775 | *result = GetFileAttributes(buf_ptr(full_path)) != INVALID_FILE_ATTRIBUTES; |
| 819 | return 0; | 776 | return ErrorNone; |
| 820 | #else | 777 | #else |
| 821 | *result = access(buf_ptr(full_path), F_OK) != -1; | 778 | *result = access(buf_ptr(full_path), F_OK) != -1; |
| 822 | return 0; | 779 | return ErrorNone; |
| 823 | #endif | 780 | #endif |
| 824 | } | 781 | } |
| 825 | 782 | ||
| ... | @@ -878,13 +835,15 @@ static int os_exec_process_posix(const char *exe, ZigList<const char *> &args, | ... | @@ -878,13 +835,15 @@ static int os_exec_process_posix(const char *exe, ZigList<const char *> &args, |
| 878 | 835 | ||
| 879 | FILE *stdout_f = fdopen(stdout_pipe[0], "rb"); | 836 | FILE *stdout_f = fdopen(stdout_pipe[0], "rb"); |
| 880 | FILE *stderr_f = fdopen(stderr_pipe[0], "rb"); | 837 | FILE *stderr_f = fdopen(stderr_pipe[0], "rb"); |
| 881 | os_fetch_file(stdout_f, out_stdout, false); | 838 | Error err1 = os_fetch_file(stdout_f, out_stdout, false); |
| 882 | os_fetch_file(stderr_f, out_stderr, false); | 839 | Error err2 = os_fetch_file(stderr_f, out_stderr, false); |
| 883 | 840 | ||
| 884 | fclose(stdout_f); | 841 | fclose(stdout_f); |
| 885 | fclose(stderr_f); | 842 | fclose(stderr_f); |
| 886 | 843 | ||
| 887 | return 0; | 844 | if (err1) return err1; |
| 845 | if (err2) return err2; | ||
| 846 | return ErrorNone; | ||
| 888 | } | 847 | } |
| 889 | } | 848 | } |
| 890 | #endif | 849 | #endif |
| ... | @@ -1016,6 +975,22 @@ static int os_exec_process_windows(const char *exe, ZigList<const char *> &args, | ... | @@ -1016,6 +975,22 @@ static int os_exec_process_windows(const char *exe, ZigList<const char *> &args, |
| 1016 | } | 975 | } |
| 1017 | #endif | 976 | #endif |
| 1018 | 977 | ||
| 978 | Error os_execv(const char *exe, const char **argv) { | ||
| 979 | #if defined(ZIG_OS_WINDOWS) | ||
| 980 | return ErrorUnsupportedOperatingSystem; | ||
| 981 | #else | ||
| 982 | execv(exe, (char *const *)argv); | ||
| 983 | switch (errno) { | ||
| 984 | case ENOMEM: | ||
| 985 | return ErrorSystemResources; | ||
| 986 | case EIO: | ||
| 987 | return ErrorFileSystem; | ||
| 988 | default: | ||
| 989 | return ErrorUnexpected; | ||
| 990 | } | ||
| 991 | #endif | ||
| 992 | } | ||
| 993 | |||
| 1019 | int os_exec_process(const char *exe, ZigList<const char *> &args, | 994 | int os_exec_process(const char *exe, ZigList<const char *> &args, |
| 1020 | Termination *term, Buf *out_stderr, Buf *out_stdout) | 995 | Termination *term, Buf *out_stderr, Buf *out_stdout) |
| 1021 | { | 996 | { |
| ... | @@ -1092,7 +1067,7 @@ int os_copy_file(Buf *src_path, Buf *dest_path) { | ... | @@ -1092,7 +1067,7 @@ int os_copy_file(Buf *src_path, Buf *dest_path) { |
| 1092 | } | 1067 | } |
| 1093 | } | 1068 | } |
| 1094 | 1069 | ||
| 1095 | int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) { | 1070 | Error os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) { |
| 1096 | FILE *f = fopen(buf_ptr(full_path), "rb"); | 1071 | FILE *f = fopen(buf_ptr(full_path), "rb"); |
| 1097 | if (!f) { | 1072 | if (!f) { |
| 1098 | switch (errno) { | 1073 | switch (errno) { |
| ... | @@ -1111,7 +1086,7 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) { | ... | @@ -1111,7 +1086,7 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) { |
| 1111 | return ErrorFileSystem; | 1086 | return ErrorFileSystem; |
| 1112 | } | 1087 | } |
| 1113 | } | 1088 | } |
| 1114 | int result = os_fetch_file(f, out_contents, skip_shebang); | 1089 | Error result = os_fetch_file(f, out_contents, skip_shebang); |
| 1115 | fclose(f); | 1090 | fclose(f); |
| 1116 | return result; | 1091 | return result; |
| 1117 | } | 1092 | } |
| ... | @@ -1282,44 +1257,6 @@ int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path) { | ... | @@ -1282,44 +1257,6 @@ int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path) { |
| 1282 | #endif | 1257 | #endif |
| 1283 | } | 1258 | } |
| 1284 | 1259 | ||
| 1285 | #if defined(ZIG_OS_POSIX) | ||
| 1286 | int os_get_global_cache_directory(Buf *out_tmp_path) { | ||
| 1287 | const char *tmp_dir = getenv("TMPDIR"); | ||
| 1288 | if (!tmp_dir) { | ||
| 1289 | tmp_dir = P_tmpdir; | ||
| 1290 | } | ||
| 1291 | |||
| 1292 | Buf *tmp_dir_buf = buf_create_from_str(tmp_dir); | ||
| 1293 | Buf *cache_dirname_buf = buf_create_from_str("zig-cache"); | ||
| 1294 | |||
| 1295 | buf_resize(out_tmp_path, 0); | ||
| 1296 | os_path_join(tmp_dir_buf, cache_dirname_buf, out_tmp_path); | ||
| 1297 | |||
| 1298 | buf_deinit(tmp_dir_buf); | ||
| 1299 | buf_deinit(cache_dirname_buf); | ||
| 1300 | return 0; | ||
| 1301 | } | ||
| 1302 | #endif | ||
| 1303 | |||
| 1304 | #if defined(ZIG_OS_WINDOWS) | ||
| 1305 | int os_get_global_cache_directory(Buf *out_tmp_path) { | ||
| 1306 | char tmp_dir[MAX_PATH + 1]; | ||
| 1307 | if (GetTempPath(MAX_PATH, tmp_dir) == 0) { | ||
| 1308 | zig_panic("GetTempPath failed"); | ||
| 1309 | } | ||
| 1310 | |||
| 1311 | Buf *tmp_dir_buf = buf_create_from_str(tmp_dir); | ||
| 1312 | Buf *cache_dirname_buf = buf_create_from_str("zig-cache"); | ||
| 1313 | |||
| 1314 | buf_resize(out_tmp_path, 0); | ||
| 1315 | os_path_join(tmp_dir_buf, cache_dirname_buf, out_tmp_path); | ||
| 1316 | |||
| 1317 | buf_deinit(tmp_dir_buf); | ||
| 1318 | buf_deinit(cache_dirname_buf); | ||
| 1319 | return 0; | ||
| 1320 | } | ||
| 1321 | #endif | ||
| 1322 | |||
| 1323 | int os_delete_file(Buf *path) { | 1260 | int os_delete_file(Buf *path) { |
| 1324 | if (remove(buf_ptr(path))) { | 1261 | if (remove(buf_ptr(path))) { |
| 1325 | return ErrorFileSystem; | 1262 | return ErrorFileSystem; |
| ... | @@ -1368,16 +1305,16 @@ double os_get_time(void) { | ... | @@ -1368,16 +1305,16 @@ double os_get_time(void) { |
| 1368 | #endif | 1305 | #endif |
| 1369 | } | 1306 | } |
| 1370 | 1307 | ||
| 1371 | int os_make_path(Buf *path) { | 1308 | Error os_make_path(Buf *path) { |
| 1372 | Buf resolved_path = os_path_resolve(&path, 1); | 1309 | Buf resolved_path = os_path_resolve(&path, 1); |
| 1373 | 1310 | ||
| 1374 | size_t end_index = buf_len(&resolved_path); | 1311 | size_t end_index = buf_len(&resolved_path); |
| 1375 | int err; | 1312 | Error err; |
| 1376 | while (true) { | 1313 | while (true) { |
| 1377 | if ((err = os_make_dir(buf_slice(&resolved_path, 0, end_index)))) { | 1314 | if ((err = os_make_dir(buf_slice(&resolved_path, 0, end_index)))) { |
| 1378 | if (err == ErrorPathAlreadyExists) { | 1315 | if (err == ErrorPathAlreadyExists) { |
| 1379 | if (end_index == buf_len(&resolved_path)) | 1316 | if (end_index == buf_len(&resolved_path)) |
| 1380 | return 0; | 1317 | return ErrorNone; |
| 1381 | } else if (err == ErrorFileNotFound) { | 1318 | } else if (err == ErrorFileNotFound) { |
| 1382 | // march end_index backward until next path component | 1319 | // march end_index backward until next path component |
| 1383 | while (true) { | 1320 | while (true) { |
| ... | @@ -1391,7 +1328,7 @@ int os_make_path(Buf *path) { | ... | @@ -1391,7 +1328,7 @@ int os_make_path(Buf *path) { |
| 1391 | } | 1328 | } |
| 1392 | } | 1329 | } |
| 1393 | if (end_index == buf_len(&resolved_path)) | 1330 | if (end_index == buf_len(&resolved_path)) |
| 1394 | return 0; | 1331 | return ErrorNone; |
| 1395 | // march end_index forward until next path component | 1332 | // march end_index forward until next path component |
| 1396 | while (true) { | 1333 | while (true) { |
| 1397 | end_index += 1; | 1334 | end_index += 1; |
| ... | @@ -1399,10 +1336,10 @@ int os_make_path(Buf *path) { | ... | @@ -1399,10 +1336,10 @@ int os_make_path(Buf *path) { |
| 1399 | break; | 1336 | break; |
| 1400 | } | 1337 | } |
| 1401 | } | 1338 | } |
| 1402 | return 0; | 1339 | return ErrorNone; |
| 1403 | } | 1340 | } |
| 1404 | 1341 | ||
| 1405 | int os_make_dir(Buf *path) { | 1342 | Error os_make_dir(Buf *path) { |
| 1406 | #if defined(ZIG_OS_WINDOWS) | 1343 | #if defined(ZIG_OS_WINDOWS) |
| 1407 | if (!CreateDirectory(buf_ptr(path), NULL)) { | 1344 | if (!CreateDirectory(buf_ptr(path), NULL)) { |
| 1408 | if (GetLastError() == ERROR_ALREADY_EXISTS) | 1345 | if (GetLastError() == ERROR_ALREADY_EXISTS) |
| ... | @@ -1413,7 +1350,7 @@ int os_make_dir(Buf *path) { | ... | @@ -1413,7 +1350,7 @@ int os_make_dir(Buf *path) { |
| 1413 | return ErrorAccess; | 1350 | return ErrorAccess; |
| 1414 | return ErrorUnexpected; | 1351 | return ErrorUnexpected; |
| 1415 | } | 1352 | } |
| 1416 | return 0; | 1353 | return ErrorNone; |
| 1417 | #else | 1354 | #else |
| 1418 | if (mkdir(buf_ptr(path), 0755) == -1) { | 1355 | if (mkdir(buf_ptr(path), 0755) == -1) { |
| 1419 | if (errno == EEXIST) | 1356 | if (errno == EEXIST) |
| ... | @@ -1424,7 +1361,7 @@ int os_make_dir(Buf *path) { | ... | @@ -1424,7 +1361,7 @@ int os_make_dir(Buf *path) { |
| 1424 | return ErrorAccess; | 1361 | return ErrorAccess; |
| 1425 | return ErrorUnexpected; | 1362 | return ErrorUnexpected; |
| 1426 | } | 1363 | } |
| 1427 | return 0; | 1364 | return ErrorNone; |
| 1428 | #endif | 1365 | #endif |
| 1429 | } | 1366 | } |
| 1430 | 1367 | ||
| ... | @@ -1447,7 +1384,7 @@ int os_init(void) { | ... | @@ -1447,7 +1384,7 @@ int os_init(void) { |
| 1447 | return 0; | 1384 | return 0; |
| 1448 | } | 1385 | } |
| 1449 | 1386 | ||
| 1450 | int os_self_exe_path(Buf *out_path) { | 1387 | Error os_self_exe_path(Buf *out_path) { |
| 1451 | #if defined(ZIG_OS_WINDOWS) | 1388 | #if defined(ZIG_OS_WINDOWS) |
| 1452 | buf_resize(out_path, 256); | 1389 | buf_resize(out_path, 256); |
| 1453 | for (;;) { | 1390 | for (;;) { |
| ... | @@ -1457,7 +1394,7 @@ int os_self_exe_path(Buf *out_path) { | ... | @@ -1457,7 +1394,7 @@ int os_self_exe_path(Buf *out_path) { |
| 1457 | } | 1394 | } |
| 1458 | if (copied_amt < buf_len(out_path)) { | 1395 | if (copied_amt < buf_len(out_path)) { |
| 1459 | buf_resize(out_path, copied_amt); | 1396 | buf_resize(out_path, copied_amt); |
| 1460 | return 0; | 1397 | return ErrorNone; |
| 1461 | } | 1398 | } |
| 1462 | buf_resize(out_path, buf_len(out_path) * 2); | 1399 | buf_resize(out_path, buf_len(out_path) * 2); |
| 1463 | } | 1400 | } |
| ... | @@ -1480,27 +1417,21 @@ int os_self_exe_path(Buf *out_path) { | ... | @@ -1480,27 +1417,21 @@ int os_self_exe_path(Buf *out_path) { |
| 1480 | char *real_path = realpath(buf_ptr(tmp), buf_ptr(out_path)); | 1417 | char *real_path = realpath(buf_ptr(tmp), buf_ptr(out_path)); |
| 1481 | if (!real_path) { | 1418 | if (!real_path) { |
| 1482 | buf_init_from_buf(out_path, tmp); | 1419 | buf_init_from_buf(out_path, tmp); |
| 1483 | return 0; | 1420 | return ErrorNone; |
| 1484 | } | 1421 | } |
| 1485 | 1422 | ||
| 1486 | // Resize out_path for the correct length. | 1423 | // Resize out_path for the correct length. |
| 1487 | buf_resize(out_path, strlen(buf_ptr(out_path))); | 1424 | buf_resize(out_path, strlen(buf_ptr(out_path))); |
| 1488 | 1425 | ||
| 1489 | return 0; | 1426 | return ErrorNone; |
| 1490 | #elif defined(ZIG_OS_LINUX) | 1427 | #elif defined(ZIG_OS_LINUX) |
| 1491 | buf_resize(out_path, 256); | 1428 | buf_resize(out_path, PATH_MAX); |
| 1492 | for (;;) { | 1429 | ssize_t amt = readlink("/proc/self/exe", buf_ptr(out_path), buf_len(out_path)); |
| 1493 | ssize_t amt = readlink("/proc/self/exe", buf_ptr(out_path), buf_len(out_path)); | 1430 | if (amt == -1) { |
| 1494 | if (amt == -1) { | 1431 | return ErrorUnexpected; |
| 1495 | return ErrorUnexpected; | ||
| 1496 | } | ||
| 1497 | if (amt == (ssize_t)buf_len(out_path)) { | ||
| 1498 | buf_resize(out_path, buf_len(out_path) * 2); | ||
| 1499 | continue; | ||
| 1500 | } | ||
| 1501 | buf_resize(out_path, amt); | ||
| 1502 | return 0; | ||
| 1503 | } | 1432 | } |
| 1433 | buf_resize(out_path, amt); | ||
| 1434 | return ErrorNone; | ||
| 1504 | #endif | 1435 | #endif |
| 1505 | return ErrorFileNotFound; | 1436 | return ErrorFileNotFound; |
| 1506 | } | 1437 | } |
| ... | @@ -1685,3 +1616,431 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchTy | ... | @@ -1685,3 +1616,431 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchTy |
| 1685 | return ErrorFileNotFound; | 1616 | return ErrorFileNotFound; |
| 1686 | #endif | 1617 | #endif |
| 1687 | } | 1618 | } |
| 1619 | |||
| 1620 | #if defined(ZIG_OS_WINDOWS) | ||
| 1621 | // Ported from std/unicode.zig | ||
| 1622 | struct Utf16LeIterator { | ||
| 1623 | uint8_t *bytes; | ||
| 1624 | size_t i; | ||
| 1625 | }; | ||
| 1626 | |||
| 1627 | // Ported from std/unicode.zig | ||
| 1628 | static Utf16LeIterator Utf16LeIterator_init(WCHAR *ptr) { | ||
| 1629 | return {(uint8_t*)ptr, 0}; | ||
| 1630 | } | ||
| 1631 | |||
| 1632 | // Ported from std/unicode.zig | ||
| 1633 | static Optional<uint32_t> Utf16LeIterator_nextCodepoint(Utf16LeIterator *it) { | ||
| 1634 | if (it->bytes[it->i] == 0 && it->bytes[it->i + 1] == 0) | ||
| 1635 | return {}; | ||
| 1636 | uint32_t c0 = ((uint32_t)it->bytes[it->i]) | (((uint32_t)it->bytes[it->i + 1]) << 8); | ||
| 1637 | if (c0 & ~((uint32_t)0x03ff) == 0xd800) { | ||
| 1638 | // surrogate pair | ||
| 1639 | it->i += 2; | ||
| 1640 | assert(it->bytes[it->i] != 0 || it->bytes[it->i + 1] != 0); | ||
| 1641 | uint32_t c1 = ((uint32_t)it->bytes[it->i]) | (((uint32_t)it->bytes[it->i + 1]) << 8); | ||
| 1642 | assert(c1 & ~((uint32_t)0x03ff) == 0xdc00); | ||
| 1643 | it->i += 2; | ||
| 1644 | return Optional<uint32_t>::some(0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff))); | ||
| 1645 | } else { | ||
| 1646 | assert(c0 & ~((uint32_t)0x03ff) != 0xdc00); | ||
| 1647 | it->i += 2; | ||
| 1648 | return Optional<uint32_t>::some(c0); | ||
| 1649 | } | ||
| 1650 | } | ||
| 1651 | |||
| 1652 | // Ported from std/unicode.zig | ||
| 1653 | static uint8_t utf8CodepointSequenceLength(uint32_t c) { | ||
| 1654 | if (c < 0x80) return 1; | ||
| 1655 | if (c < 0x800) return 2; | ||
| 1656 | if (c < 0x10000) return 3; | ||
| 1657 | if (c < 0x110000) return 4; | ||
| 1658 | zig_unreachable(); | ||
| 1659 | } | ||
| 1660 | |||
| 1661 | // Ported from std/unicode.zig | ||
| 1662 | static size_t utf8Encode(uint32_t c, Slice<uint8_t> out) { | ||
| 1663 | size_t length = utf8CodepointSequenceLength(c); | ||
| 1664 | assert(out.len >= length); | ||
| 1665 | switch (length) { | ||
| 1666 | // The pattern for each is the same | ||
| 1667 | // - Increasing the initial shift by 6 each time | ||
| 1668 | // - Each time after the first shorten the shifted | ||
| 1669 | // value to a max of 0b111111 (63) | ||
| 1670 | case 1: | ||
| 1671 | out.ptr[0] = c; // Can just do 0 + codepoint for initial range | ||
| 1672 | break; | ||
| 1673 | case 2: | ||
| 1674 | out.ptr[0] = 0b11000000 | (c >> 6); | ||
| 1675 | out.ptr[1] = 0b10000000 | (c & 0b111111); | ||
| 1676 | break; | ||
| 1677 | case 3: | ||
| 1678 | assert(!(0xd800 <= c && c <= 0xdfff)); | ||
| 1679 | out.ptr[0] = 0b11100000 | (c >> 12); | ||
| 1680 | out.ptr[1] = 0b10000000 | ((c >> 6) & 0b111111); | ||
| 1681 | out.ptr[2] = 0b10000000 | (c & 0b111111); | ||
| 1682 | break; | ||
| 1683 | case 4: | ||
| 1684 | out.ptr[0] = 0b11110000 | (c >> 18); | ||
| 1685 | out.ptr[1] = 0b10000000 | ((c >> 12) & 0b111111); | ||
| 1686 | out.ptr[2] = 0b10000000 | ((c >> 6) & 0b111111); | ||
| 1687 | out.ptr[3] = 0b10000000 | (c & 0b111111); | ||
| 1688 | break; | ||
| 1689 | default: | ||
| 1690 | zig_unreachable(); | ||
| 1691 | } | ||
| 1692 | return length; | ||
| 1693 | } | ||
| 1694 | |||
| 1695 | // Ported from std.unicode.utf16leToUtf8Alloc | ||
| 1696 | static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) { | ||
| 1697 | // optimistically guess that it will all be ascii. | ||
| 1698 | buf_resize(out, 0); | ||
| 1699 | size_t out_index = 0; | ||
| 1700 | Utf16LeIterator it = Utf16LeIterator_init(utf16le); | ||
| 1701 | for (;;) { | ||
| 1702 | Optional<uint32_t> opt_codepoint = Utf16LeIterator_nextCodepoint(&it); | ||
| 1703 | if (!opt_codepoint.is_some) break; | ||
| 1704 | uint32_t codepoint = opt_codepoint.value; | ||
| 1705 | |||
| 1706 | size_t utf8_len = utf8CodepointSequenceLength(codepoint); | ||
| 1707 | buf_resize(out, buf_len(out) + utf8_len); | ||
| 1708 | utf8Encode(codepoint, {(uint8_t*)buf_ptr(out)+out_index, buf_len(out)-out_index}); | ||
| 1709 | out_index += utf8_len; | ||
| 1710 | } | ||
| 1711 | } | ||
| 1712 | #endif | ||
| 1713 | |||
| 1714 | // Ported from std.os.getAppDataDir | ||
| 1715 | Error os_get_app_data_dir(Buf *out_path, const char *appname) { | ||
| 1716 | #if defined(ZIG_OS_WINDOWS) | ||
| 1717 | Error err; | ||
| 1718 | WCHAR *dir_path_ptr; | ||
| 1719 | switch (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &dir_path_ptr)) { | ||
| 1720 | case S_OK: | ||
| 1721 | // defer os.windows.CoTaskMemFree(@ptrCast(*c_void, dir_path_ptr)); | ||
| 1722 | utf16le_ptr_to_utf8(out_path, dir_path_ptr); | ||
| 1723 | CoTaskMemFree(dir_path_ptr); | ||
| 1724 | buf_appendf(out_path, "\\%s", appname); | ||
| 1725 | return ErrorNone; | ||
| 1726 | case E_OUTOFMEMORY: | ||
| 1727 | return ErrorNoMem; | ||
| 1728 | default: | ||
| 1729 | return ErrorUnexpected; | ||
| 1730 | } | ||
| 1731 | zig_unreachable(); | ||
| 1732 | #elif defined(ZIG_OS_DARWIN) | ||
| 1733 | const char *home_dir = getenv("HOME"); | ||
| 1734 | if (home_dir == nullptr) { | ||
| 1735 | // TODO use /etc/passwd | ||
| 1736 | return ErrorFileNotFound; | ||
| 1737 | } | ||
| 1738 | buf_resize(out_path, 0); | ||
| 1739 | buf_appendf(out_path, "%s/Library/Application Support/%s", home_dir, appname); | ||
| 1740 | return ErrorNone; | ||
| 1741 | #elif defined(ZIG_OS_LINUX) | ||
| 1742 | const char *home_dir = getenv("HOME"); | ||
| 1743 | if (home_dir == nullptr) { | ||
| 1744 | // TODO use /etc/passwd | ||
| 1745 | return ErrorFileNotFound; | ||
| 1746 | } | ||
| 1747 | buf_resize(out_path, 0); | ||
| 1748 | buf_appendf(out_path, "%s/.local/share/%s", home_dir, appname); | ||
| 1749 | return ErrorNone; | ||
| 1750 | #endif | ||
| 1751 | } | ||
| 1752 | |||
| 1753 | |||
| 1754 | #if defined(ZIG_OS_LINUX) | ||
| 1755 | static int self_exe_shared_libs_callback(struct dl_phdr_info *info, size_t size, void *data) { | ||
| 1756 | ZigList<Buf *> *libs = reinterpret_cast< ZigList<Buf *> *>(data); | ||
| 1757 | if (info->dlpi_name[0] == '/') { | ||
| 1758 | libs->append(buf_create_from_str(info->dlpi_name)); | ||
| 1759 | } | ||
| 1760 | return 0; | ||
| 1761 | } | ||
| 1762 | #endif | ||
| 1763 | |||
| 1764 | Error os_self_exe_shared_libs(ZigList<Buf *> &paths) { | ||
| 1765 | #if defined(ZIG_OS_LINUX) | ||
| 1766 | paths.resize(0); | ||
| 1767 | dl_iterate_phdr(self_exe_shared_libs_callback, &paths); | ||
| 1768 | return ErrorNone; | ||
| 1769 | #elif defined(ZIG_OS_DARWIN) | ||
| 1770 | paths.resize(0); | ||
| 1771 | uint32_t img_count = _dyld_image_count(); | ||
| 1772 | for (uint32_t i = 0; i != img_count; i += 1) { | ||
| 1773 | const char *name = _dyld_get_image_name(i); | ||
| 1774 | paths.append(buf_create_from_str(name)); | ||
| 1775 | } | ||
| 1776 | return ErrorNone; | ||
| 1777 | #elif defined(ZIG_OS_WINDOWS) | ||
| 1778 | // zig is built statically on windows, so we can return an empty list | ||
| 1779 | paths.resize(0); | ||
| 1780 | return ErrorNone; | ||
| 1781 | #else | ||
| 1782 | #error unimplemented | ||
| 1783 | #endif | ||
| 1784 | } | ||
| 1785 | |||
| 1786 | Error os_file_open_r(Buf *full_path, OsFile *out_file) { | ||
| 1787 | #if defined(ZIG_OS_WINDOWS) | ||
| 1788 | // TODO use CreateFileW | ||
| 1789 | HANDLE result = CreateFileA(buf_ptr(full_path), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); | ||
| 1790 | |||
| 1791 | if (result == INVALID_HANDLE_VALUE) { | ||
| 1792 | DWORD err = GetLastError(); | ||
| 1793 | switch (err) { | ||
| 1794 | case ERROR_SHARING_VIOLATION: | ||
| 1795 | return ErrorSharingViolation; | ||
| 1796 | case ERROR_ALREADY_EXISTS: | ||
| 1797 | return ErrorPathAlreadyExists; | ||
| 1798 | case ERROR_FILE_EXISTS: | ||
| 1799 | return ErrorPathAlreadyExists; | ||
| 1800 | case ERROR_FILE_NOT_FOUND: | ||
| 1801 | return ErrorFileNotFound; | ||
| 1802 | case ERROR_PATH_NOT_FOUND: | ||
| 1803 | return ErrorFileNotFound; | ||
| 1804 | case ERROR_ACCESS_DENIED: | ||
| 1805 | return ErrorAccess; | ||
| 1806 | case ERROR_PIPE_BUSY: | ||
| 1807 | return ErrorPipeBusy; | ||
| 1808 | default: | ||
| 1809 | return ErrorUnexpected; | ||
| 1810 | } | ||
| 1811 | } | ||
| 1812 | |||
| 1813 | *out_file = result; | ||
| 1814 | return ErrorNone; | ||
| 1815 | #else | ||
| 1816 | for (;;) { | ||
| 1817 | int fd = open(buf_ptr(full_path), O_RDONLY|O_CLOEXEC); | ||
| 1818 | if (fd == -1) { | ||
| 1819 | switch (errno) { | ||
| 1820 | case EINTR: | ||
| 1821 | continue; | ||
| 1822 | case EINVAL: | ||
| 1823 | zig_unreachable(); | ||
| 1824 | case EFAULT: | ||
| 1825 | zig_unreachable(); | ||
| 1826 | case EACCES: | ||
| 1827 | return ErrorAccess; | ||
| 1828 | case EISDIR: | ||
| 1829 | return ErrorIsDir; | ||
| 1830 | case ENOENT: | ||
| 1831 | return ErrorFileNotFound; | ||
| 1832 | default: | ||
| 1833 | return ErrorFileSystem; | ||
| 1834 | } | ||
| 1835 | } | ||
| 1836 | *out_file = fd; | ||
| 1837 | return ErrorNone; | ||
| 1838 | } | ||
| 1839 | #endif | ||
| 1840 | } | ||
| 1841 | |||
| 1842 | Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) { | ||
| 1843 | #if defined(ZIG_OS_WINDOWS) | ||
| 1844 | for (;;) { | ||
| 1845 | HANDLE result = CreateFileA(buf_ptr(full_path), GENERIC_READ | GENERIC_WRITE, | ||
| 1846 | 0, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); | ||
| 1847 | |||
| 1848 | if (result == INVALID_HANDLE_VALUE) { | ||
| 1849 | DWORD err = GetLastError(); | ||
| 1850 | switch (err) { | ||
| 1851 | case ERROR_SHARING_VIOLATION: | ||
| 1852 | // TODO wait for the lock instead of sleeping | ||
| 1853 | Sleep(10); | ||
| 1854 | continue; | ||
| 1855 | case ERROR_ALREADY_EXISTS: | ||
| 1856 | return ErrorPathAlreadyExists; | ||
| 1857 | case ERROR_FILE_EXISTS: | ||
| 1858 | return ErrorPathAlreadyExists; | ||
| 1859 | case ERROR_FILE_NOT_FOUND: | ||
| 1860 | return ErrorFileNotFound; | ||
| 1861 | case ERROR_PATH_NOT_FOUND: | ||
| 1862 | return ErrorFileNotFound; | ||
| 1863 | case ERROR_ACCESS_DENIED: | ||
| 1864 | return ErrorAccess; | ||
| 1865 | case ERROR_PIPE_BUSY: | ||
| 1866 | return ErrorPipeBusy; | ||
| 1867 | default: | ||
| 1868 | return ErrorUnexpected; | ||
| 1869 | } | ||
| 1870 | } | ||
| 1871 | *out_file = result; | ||
| 1872 | return ErrorNone; | ||
| 1873 | } | ||
| 1874 | #else | ||
| 1875 | int fd; | ||
| 1876 | for (;;) { | ||
| 1877 | fd = open(buf_ptr(full_path), O_RDWR|O_CLOEXEC|O_CREAT, 0666); | ||
| 1878 | if (fd == -1) { | ||
| 1879 | switch (errno) { | ||
| 1880 | case EINTR: | ||
| 1881 | continue; | ||
| 1882 | case EINVAL: | ||
| 1883 | zig_unreachable(); | ||
| 1884 | case EFAULT: | ||
| 1885 | zig_unreachable(); | ||
| 1886 | case EACCES: | ||
| 1887 | return ErrorAccess; | ||
| 1888 | case EISDIR: | ||
| 1889 | return ErrorIsDir; | ||
| 1890 | case ENOENT: | ||
| 1891 | return ErrorFileNotFound; | ||
| 1892 | default: | ||
| 1893 | return ErrorFileSystem; | ||
| 1894 | } | ||
| 1895 | } | ||
| 1896 | break; | ||
| 1897 | } | ||
| 1898 | for (;;) { | ||
| 1899 | struct flock lock; | ||
| 1900 | lock.l_type = F_WRLCK; | ||
| 1901 | lock.l_whence = SEEK_SET; | ||
| 1902 | lock.l_start = 0; | ||
| 1903 | lock.l_len = 0; | ||
| 1904 | if (fcntl(fd, F_SETLKW, &lock) == -1) { | ||
| 1905 | switch (errno) { | ||
| 1906 | case EINTR: | ||
| 1907 | continue; | ||
| 1908 | case EBADF: | ||
| 1909 | zig_unreachable(); | ||
| 1910 | case EFAULT: | ||
| 1911 | zig_unreachable(); | ||
| 1912 | case EINVAL: | ||
| 1913 | zig_unreachable(); | ||
| 1914 | default: | ||
| 1915 | close(fd); | ||
| 1916 | return ErrorFileSystem; | ||
| 1917 | } | ||
| 1918 | } | ||
| 1919 | break; | ||
| 1920 | } | ||
| 1921 | *out_file = fd; | ||
| 1922 | return ErrorNone; | ||
| 1923 | #endif | ||
| 1924 | } | ||
| 1925 | |||
| 1926 | Error os_file_mtime(OsFile file, OsTimeStamp *mtime) { | ||
| 1927 | #if defined(ZIG_OS_WINDOWS) | ||
| 1928 | FILETIME last_write_time; | ||
| 1929 | if (!GetFileTime(file, nullptr, nullptr, &last_write_time)) | ||
| 1930 | return ErrorUnexpected; | ||
| 1931 | mtime->sec = last_write_time.dwLowDateTime | (last_write_time.dwHighDateTime << 32); | ||
| 1932 | mtime->nsec = 0; | ||
| 1933 | return ErrorNone; | ||
| 1934 | #elif defined(ZIG_OS_LINUX) | ||
| 1935 | struct stat statbuf; | ||
| 1936 | if (fstat(file, &statbuf) == -1) | ||
| 1937 | return ErrorFileSystem; | ||
| 1938 | |||
| 1939 | mtime->sec = statbuf.st_mtim.tv_sec; | ||
| 1940 | mtime->nsec = statbuf.st_mtim.tv_nsec; | ||
| 1941 | return ErrorNone; | ||
| 1942 | #elif defined(ZIG_OS_DARWIN) | ||
| 1943 | struct stat statbuf; | ||
| 1944 | if (fstat(file, &statbuf) == -1) | ||
| 1945 | return ErrorFileSystem; | ||
| 1946 | |||
| 1947 | mtime->sec = statbuf.st_mtimespec.tv_sec; | ||
| 1948 | mtime->nsec = statbuf.st_mtimespec.tv_nsec; | ||
| 1949 | return ErrorNone; | ||
| 1950 | #else | ||
| 1951 | #error unimplemented | ||
| 1952 | #endif | ||
| 1953 | } | ||
| 1954 | |||
| 1955 | Error os_file_read(OsFile file, void *ptr, size_t *len) { | ||
| 1956 | #if defined(ZIG_OS_WINDOWS) | ||
| 1957 | DWORD amt_read; | ||
| 1958 | if (ReadFile(file, ptr, *len, &amt_read, nullptr) == 0) | ||
| 1959 | return ErrorUnexpected; | ||
| 1960 | *len = amt_read; | ||
| 1961 | return ErrorNone; | ||
| 1962 | #else | ||
| 1963 | for (;;) { | ||
| 1964 | ssize_t rc = read(file, ptr, *len); | ||
| 1965 | if (rc == -1) { | ||
| 1966 | switch (errno) { | ||
| 1967 | case EINTR: | ||
| 1968 | continue; | ||
| 1969 | case EBADF: | ||
| 1970 | zig_unreachable(); | ||
| 1971 | case EFAULT: | ||
| 1972 | zig_unreachable(); | ||
| 1973 | case EISDIR: | ||
| 1974 | zig_unreachable(); | ||
| 1975 | default: | ||
| 1976 | return ErrorFileSystem; | ||
| 1977 | } | ||
| 1978 | } | ||
| 1979 | *len = rc; | ||
| 1980 | return ErrorNone; | ||
| 1981 | } | ||
| 1982 | #endif | ||
| 1983 | } | ||
| 1984 | |||
| 1985 | Error os_file_read_all(OsFile file, Buf *contents) { | ||
| 1986 | Error err; | ||
| 1987 | size_t index = 0; | ||
| 1988 | for (;;) { | ||
| 1989 | size_t amt = buf_len(contents) - index; | ||
| 1990 | |||
| 1991 | if (amt < 4096) { | ||
| 1992 | buf_resize(contents, buf_len(contents) + (4096 - amt)); | ||
| 1993 | amt = buf_len(contents) - index; | ||
| 1994 | } | ||
| 1995 | |||
| 1996 | if ((err = os_file_read(file, buf_ptr(contents) + index, &amt))) | ||
| 1997 | return err; | ||
| 1998 | |||
| 1999 | if (amt == 0) { | ||
| 2000 | buf_resize(contents, index); | ||
| 2001 | return ErrorNone; | ||
| 2002 | } | ||
| 2003 | |||
| 2004 | index += amt; | ||
| 2005 | } | ||
| 2006 | } | ||
| 2007 | |||
| 2008 | Error os_file_overwrite(OsFile file, Buf *contents) { | ||
| 2009 | #if defined(ZIG_OS_WINDOWS) | ||
| 2010 | if (SetFilePointer(file, 0, nullptr, FILE_BEGIN) == INVALID_SET_FILE_POINTER) | ||
| 2011 | return ErrorFileSystem; | ||
| 2012 | if (!SetEndOfFile(file)) | ||
| 2013 | return ErrorFileSystem; | ||
| 2014 | if (!WriteFile(file, buf_ptr(contents), buf_len(contents), nullptr, nullptr)) | ||
| 2015 | return ErrorFileSystem; | ||
| 2016 | return ErrorNone; | ||
| 2017 | #else | ||
| 2018 | if (lseek(file, 0, SEEK_SET) == -1) | ||
| 2019 | return ErrorFileSystem; | ||
| 2020 | if (ftruncate(file, 0) == -1) | ||
| 2021 | return ErrorFileSystem; | ||
| 2022 | for (;;) { | ||
| 2023 | if (write(file, buf_ptr(contents), buf_len(contents)) == -1) { | ||
| 2024 | switch (errno) { | ||
| 2025 | case EINTR: | ||
| 2026 | continue; | ||
| 2027 | case EINVAL: | ||
| 2028 | zig_unreachable(); | ||
| 2029 | case EBADF: | ||
| 2030 | zig_unreachable(); | ||
| 2031 | default: | ||
| 2032 | return ErrorFileSystem; | ||
| 2033 | } | ||
| 2034 | } | ||
| 2035 | return ErrorNone; | ||
| 2036 | } | ||
| 2037 | #endif | ||
| 2038 | } | ||
| 2039 | |||
| 2040 | void os_file_close(OsFile file) { | ||
| 2041 | #if defined(ZIG_OS_WINDOWS) | ||
| 2042 | CloseHandle(file); | ||
| 2043 | #else | ||
| 2044 | close(file); | ||
| 2045 | #endif | ||
| 2046 | } |
src/os.hpp+61-38| ... | @@ -13,10 +13,43 @@ | ... | @@ -13,10 +13,43 @@ |
| 13 | #include "error.hpp" | 13 | #include "error.hpp" |
| 14 | #include "zig_llvm.h" | 14 | #include "zig_llvm.h" |
| 15 | #include "windows_sdk.h" | 15 | #include "windows_sdk.h" |
| 16 | #include "result.hpp" | ||
| 16 | 17 | ||
| 17 | #include <stdio.h> | 18 | #include <stdio.h> |
| 18 | #include <inttypes.h> | 19 | #include <inttypes.h> |
| 19 | 20 | ||
| 21 | #if defined(__APPLE__) | ||
| 22 | #define ZIG_OS_DARWIN | ||
| 23 | #elif defined(_WIN32) | ||
| 24 | #define ZIG_OS_WINDOWS | ||
| 25 | #elif defined(__linux__) | ||
| 26 | #define ZIG_OS_LINUX | ||
| 27 | #else | ||
| 28 | #define ZIG_OS_UNKNOWN | ||
| 29 | #endif | ||
| 30 | |||
| 31 | #if defined(__x86_64__) | ||
| 32 | #define ZIG_ARCH_X86_64 | ||
| 33 | #else | ||
| 34 | #define ZIG_ARCH_UNKNOWN | ||
| 35 | #endif | ||
| 36 | |||
| 37 | #if defined(ZIG_OS_WINDOWS) | ||
| 38 | #define ZIG_PRI_usize "I64u" | ||
| 39 | #define ZIG_PRI_u64 "I64u" | ||
| 40 | #define ZIG_PRI_llu "I64u" | ||
| 41 | #define ZIG_PRI_x64 "I64x" | ||
| 42 | #define OS_SEP "\\" | ||
| 43 | #define ZIG_OS_SEP_CHAR '\\' | ||
| 44 | #else | ||
| 45 | #define ZIG_PRI_usize "zu" | ||
| 46 | #define ZIG_PRI_u64 PRIu64 | ||
| 47 | #define ZIG_PRI_llu "llu" | ||
| 48 | #define ZIG_PRI_x64 PRIx64 | ||
| 49 | #define OS_SEP "/" | ||
| 50 | #define ZIG_OS_SEP_CHAR '/' | ||
| 51 | #endif | ||
| 52 | |||
| 20 | enum TermColor { | 53 | enum TermColor { |
| 21 | TermColorRed, | 54 | TermColorRed, |
| 22 | TermColorGreen, | 55 | TermColorGreen, |
| ... | @@ -38,11 +71,23 @@ struct Termination { | ... | @@ -38,11 +71,23 @@ struct Termination { |
| 38 | int code; | 71 | int code; |
| 39 | }; | 72 | }; |
| 40 | 73 | ||
| 74 | #if defined(ZIG_OS_WINDOWS) | ||
| 75 | #define OsFile void * | ||
| 76 | #else | ||
| 77 | #define OsFile int | ||
| 78 | #endif | ||
| 79 | |||
| 80 | struct OsTimeStamp { | ||
| 81 | uint64_t sec; | ||
| 82 | uint64_t nsec; | ||
| 83 | }; | ||
| 84 | |||
| 41 | int os_init(void); | 85 | int os_init(void); |
| 42 | 86 | ||
| 43 | void os_spawn_process(const char *exe, ZigList<const char *> &args, Termination *term); | 87 | void os_spawn_process(const char *exe, ZigList<const char *> &args, Termination *term); |
| 44 | int os_exec_process(const char *exe, ZigList<const char *> &args, | 88 | int os_exec_process(const char *exe, ZigList<const char *> &args, |
| 45 | Termination *term, Buf *out_stderr, Buf *out_stdout); | 89 | Termination *term, Buf *out_stderr, Buf *out_stdout); |
| 90 | Error os_execv(const char *exe, const char **argv); | ||
| 46 | 91 | ||
| 47 | void os_path_dirname(Buf *full_path, Buf *out_dirname); | 92 | void os_path_dirname(Buf *full_path, Buf *out_dirname); |
| 48 | void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename); | 93 | void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename); |
| ... | @@ -52,16 +97,22 @@ int os_path_real(Buf *rel_path, Buf *out_abs_path); | ... | @@ -52,16 +97,22 @@ int os_path_real(Buf *rel_path, Buf *out_abs_path); |
| 52 | Buf os_path_resolve(Buf **paths_ptr, size_t paths_len); | 97 | Buf os_path_resolve(Buf **paths_ptr, size_t paths_len); |
| 53 | bool os_path_is_absolute(Buf *path); | 98 | bool os_path_is_absolute(Buf *path); |
| 54 | 99 | ||
| 55 | int os_get_global_cache_directory(Buf *out_tmp_path); | 100 | Error ATTRIBUTE_MUST_USE os_make_path(Buf *path); |
| 101 | Error ATTRIBUTE_MUST_USE os_make_dir(Buf *path); | ||
| 56 | 102 | ||
| 57 | int os_make_path(Buf *path); | 103 | Error ATTRIBUTE_MUST_USE os_file_open_r(Buf *full_path, OsFile *out_file); |
| 58 | int os_make_dir(Buf *path); | 104 | Error ATTRIBUTE_MUST_USE os_file_open_lock_rw(Buf *full_path, OsFile *out_file); |
| 105 | Error ATTRIBUTE_MUST_USE os_file_mtime(OsFile file, OsTimeStamp *mtime); | ||
| 106 | Error ATTRIBUTE_MUST_USE os_file_read(OsFile file, void *ptr, size_t *len); | ||
| 107 | Error ATTRIBUTE_MUST_USE os_file_read_all(OsFile file, Buf *contents); | ||
| 108 | Error ATTRIBUTE_MUST_USE os_file_overwrite(OsFile file, Buf *contents); | ||
| 109 | void os_file_close(OsFile file); | ||
| 59 | 110 | ||
| 60 | void os_write_file(Buf *full_path, Buf *contents); | 111 | void os_write_file(Buf *full_path, Buf *contents); |
| 61 | int os_copy_file(Buf *src_path, Buf *dest_path); | 112 | int os_copy_file(Buf *src_path, Buf *dest_path); |
| 62 | 113 | ||
| 63 | int os_fetch_file(FILE *file, Buf *out_contents, bool skip_shebang); | 114 | Error ATTRIBUTE_MUST_USE os_fetch_file(FILE *file, Buf *out_contents, bool skip_shebang); |
| 64 | int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang); | 115 | Error ATTRIBUTE_MUST_USE os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang); |
| 65 | 116 | ||
| 66 | int os_get_cwd(Buf *out_cwd); | 117 | int os_get_cwd(Buf *out_cwd); |
| 67 | 118 | ||
| ... | @@ -71,49 +122,21 @@ void os_stderr_set_color(TermColor color); | ... | @@ -71,49 +122,21 @@ void os_stderr_set_color(TermColor color); |
| 71 | int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path); | 122 | int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path); |
| 72 | int os_delete_file(Buf *path); | 123 | int os_delete_file(Buf *path); |
| 73 | 124 | ||
| 74 | int os_file_exists(Buf *full_path, bool *result); | 125 | Error ATTRIBUTE_MUST_USE os_file_exists(Buf *full_path, bool *result); |
| 75 | 126 | ||
| 76 | int os_rename(Buf *src_path, Buf *dest_path); | 127 | int os_rename(Buf *src_path, Buf *dest_path); |
| 77 | double os_get_time(void); | 128 | double os_get_time(void); |
| 78 | 129 | ||
| 79 | bool os_is_sep(uint8_t c); | 130 | bool os_is_sep(uint8_t c); |
| 80 | 131 | ||
| 81 | int os_self_exe_path(Buf *out_path); | 132 | Error ATTRIBUTE_MUST_USE os_self_exe_path(Buf *out_path); |
| 133 | |||
| 134 | Error ATTRIBUTE_MUST_USE os_get_app_data_dir(Buf *out_path, const char *appname); | ||
| 82 | 135 | ||
| 83 | int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf *output_buf); | 136 | int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf *output_buf); |
| 84 | int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); | 137 | int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); |
| 85 | int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); | 138 | int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); |
| 86 | 139 | ||
| 87 | #if defined(__APPLE__) | 140 | Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths); |
| 88 | #define ZIG_OS_DARWIN | ||
| 89 | #elif defined(_WIN32) | ||
| 90 | #define ZIG_OS_WINDOWS | ||
| 91 | #elif defined(__linux__) | ||
| 92 | #define ZIG_OS_LINUX | ||
| 93 | #else | ||
| 94 | #define ZIG_OS_UNKNOWN | ||
| 95 | #endif | ||
| 96 | |||
| 97 | #if defined(__x86_64__) | ||
| 98 | #define ZIG_ARCH_X86_64 | ||
| 99 | #else | ||
| 100 | #define ZIG_ARCH_UNKNOWN | ||
| 101 | #endif | ||
| 102 | |||
| 103 | #if defined(ZIG_OS_WINDOWS) | ||
| 104 | #define ZIG_PRI_usize "I64u" | ||
| 105 | #define ZIG_PRI_u64 "I64u" | ||
| 106 | #define ZIG_PRI_llu "I64u" | ||
| 107 | #define ZIG_PRI_x64 "I64x" | ||
| 108 | #define OS_SEP "\\" | ||
| 109 | #define ZIG_OS_SEP_CHAR '\\' | ||
| 110 | #else | ||
| 111 | #define ZIG_PRI_usize "zu" | ||
| 112 | #define ZIG_PRI_u64 PRIu64 | ||
| 113 | #define ZIG_PRI_llu "llu" | ||
| 114 | #define ZIG_PRI_x64 PRIx64 | ||
| 115 | #define OS_SEP "/" | ||
| 116 | #define ZIG_OS_SEP_CHAR '/' | ||
| 117 | #endif | ||
| 118 | 141 | ||
| 119 | #endif | 142 | #endif |
src/target.cpp+16| ... | @@ -813,6 +813,22 @@ const char *target_exe_file_ext(ZigTarget *target) { | ... | @@ -813,6 +813,22 @@ const char *target_exe_file_ext(ZigTarget *target) { |
| 813 | } | 813 | } |
| 814 | } | 814 | } |
| 815 | 815 | ||
| 816 | const char *target_lib_file_ext(ZigTarget *target, bool is_static, size_t version_major, size_t version_minor, size_t version_patch) { | ||
| 817 | if (target->os == OsWindows) { | ||
| 818 | if (is_static) { | ||
| 819 | return ".lib"; | ||
| 820 | } else { | ||
| 821 | return ".dll"; | ||
| 822 | } | ||
| 823 | } else { | ||
| 824 | if (is_static) { | ||
| 825 | return ".a"; | ||
| 826 | } else { | ||
| 827 | return buf_ptr(buf_sprintf(".so.%zu", version_major)); | ||
| 828 | } | ||
| 829 | } | ||
| 830 | } | ||
| 831 | |||
| 816 | enum FloatAbi { | 832 | enum FloatAbi { |
| 817 | FloatAbiHard, | 833 | FloatAbiHard, |
| 818 | FloatAbiSoft, | 834 | FloatAbiSoft, |
src/target.hpp+1| ... | @@ -113,6 +113,7 @@ const char *target_o_file_ext(ZigTarget *target); | ... | @@ -113,6 +113,7 @@ const char *target_o_file_ext(ZigTarget *target); |
| 113 | const char *target_asm_file_ext(ZigTarget *target); | 113 | const char *target_asm_file_ext(ZigTarget *target); |
| 114 | const char *target_llvm_ir_file_ext(ZigTarget *target); | 114 | const char *target_llvm_ir_file_ext(ZigTarget *target); |
| 115 | const char *target_exe_file_ext(ZigTarget *target); | 115 | const char *target_exe_file_ext(ZigTarget *target); |
| 116 | const char *target_lib_file_ext(ZigTarget *target, bool is_static, size_t version_major, size_t version_minor, size_t version_patch); | ||
| 116 | 117 | ||
| 117 | Buf *target_dynamic_linker(ZigTarget *target); | 118 | Buf *target_dynamic_linker(ZigTarget *target); |
| 118 | 119 |
src/util.cpp+39| ... | @@ -43,3 +43,42 @@ uint32_t ptr_hash(const void *ptr) { | ... | @@ -43,3 +43,42 @@ uint32_t ptr_hash(const void *ptr) { |
| 43 | bool ptr_eq(const void *a, const void *b) { | 43 | bool ptr_eq(const void *a, const void *b) { |
| 44 | return a == b; | 44 | return a == b; |
| 45 | } | 45 | } |
| 46 | |||
| 47 | // Ported from std/mem.zig. | ||
| 48 | bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte) { | ||
| 49 | for (size_t i = 0; i < self->split_bytes.len; i += 1) { | ||
| 50 | if (byte == self->split_bytes.ptr[i]) { | ||
| 51 | return true; | ||
| 52 | } | ||
| 53 | } | ||
| 54 | return false; | ||
| 55 | } | ||
| 56 | |||
| 57 | // Ported from std/mem.zig. | ||
| 58 | Optional<Slice<uint8_t>> SplitIterator_next(SplitIterator *self) { | ||
| 59 | // move to beginning of token | ||
| 60 | while (self->index < self->buffer.len && | ||
| 61 | SplitIterator_isSplitByte(self, self->buffer.ptr[self->index])) | ||
| 62 | { | ||
| 63 | self->index += 1; | ||
| 64 | } | ||
| 65 | size_t start = self->index; | ||
| 66 | if (start == self->buffer.len) { | ||
| 67 | return {}; | ||
| 68 | } | ||
| 69 | |||
| 70 | // move to end of token | ||
| 71 | while (self->index < self->buffer.len && | ||
| 72 | !SplitIterator_isSplitByte(self, self->buffer.ptr[self->index])) | ||
| 73 | { | ||
| 74 | self->index += 1; | ||
| 75 | } | ||
| 76 | size_t end = self->index; | ||
| 77 | |||
| 78 | return Optional<Slice<uint8_t>>::some(self->buffer.slice(start, end)); | ||
| 79 | } | ||
| 80 | |||
| 81 | // Ported from std/mem.zig | ||
| 82 | SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes) { | ||
| 83 | return SplitIterator{0, buffer, split_bytes}; | ||
| 84 | } |
src/util.hpp+12| ... | @@ -254,4 +254,16 @@ static inline void memCopy(Slice<T> dest, Slice<T> src) { | ... | @@ -254,4 +254,16 @@ static inline void memCopy(Slice<T> dest, Slice<T> src) { |
| 254 | memcpy(dest.ptr, src.ptr, src.len * sizeof(T)); | 254 | memcpy(dest.ptr, src.ptr, src.len * sizeof(T)); |
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | // Ported from std/mem.zig. | ||
| 258 | // Coordinate struct fields with memSplit function | ||
| 259 | struct SplitIterator { | ||
| 260 | size_t index; | ||
| 261 | Slice<uint8_t> buffer; | ||
| 262 | Slice<uint8_t> split_bytes; | ||
| 263 | }; | ||
| 264 | |||
| 265 | bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte); | ||
| 266 | Optional<Slice<uint8_t>> SplitIterator_next(SplitIterator *self); | ||
| 267 | SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes); | ||
| 268 | |||
| 257 | #endif | 269 | #endif |
src/zig_llvm.cpp+8-1| ... | @@ -30,6 +30,7 @@ | ... | @@ -30,6 +30,7 @@ |
| 30 | #include <llvm/PassRegistry.h> | 30 | #include <llvm/PassRegistry.h> |
| 31 | #include <llvm/Support/FileSystem.h> | 31 | #include <llvm/Support/FileSystem.h> |
| 32 | #include <llvm/Support/TargetParser.h> | 32 | #include <llvm/Support/TargetParser.h> |
| 33 | #include <llvm/Support/Timer.h> | ||
| 33 | #include <llvm/Support/raw_ostream.h> | 34 | #include <llvm/Support/raw_ostream.h> |
| 34 | #include <llvm/Target/TargetMachine.h> | 35 | #include <llvm/Target/TargetMachine.h> |
| 35 | #include <llvm/Transforms/Coroutines.h> | 36 | #include <llvm/Transforms/Coroutines.h> |
| ... | @@ -81,8 +82,11 @@ static const bool assertions_on = false; | ... | @@ -81,8 +82,11 @@ static const bool assertions_on = false; |
| 81 | #endif | 82 | #endif |
| 82 | 83 | ||
| 83 | bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, | 84 | bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, |
| 84 | const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug, bool is_small) | 85 | const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug, |
| 86 | bool is_small, bool time_report) | ||
| 85 | { | 87 | { |
| 88 | TimePassesIsEnabled = time_report; | ||
| 89 | |||
| 86 | std::error_code EC; | 90 | std::error_code EC; |
| 87 | raw_fd_ostream dest(filename, EC, sys::fs::F_None); | 91 | raw_fd_ostream dest(filename, EC, sys::fs::F_None); |
| 88 | if (EC) { | 92 | if (EC) { |
| ... | @@ -182,6 +186,9 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM | ... | @@ -182,6 +186,9 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 182 | } | 186 | } |
| 183 | } | 187 | } |
| 184 | 188 | ||
| 189 | if (time_report) { | ||
| 190 | TimerGroup::printAll(errs()); | ||
| 191 | } | ||
| 185 | return false; | 192 | return false; |
| 186 | } | 193 | } |
| 187 | 194 |
src/zig_llvm.h+2-1| ... | @@ -55,7 +55,8 @@ enum ZigLLVM_EmitOutputType { | ... | @@ -55,7 +55,8 @@ enum ZigLLVM_EmitOutputType { |
| 55 | }; | 55 | }; |
| 56 | 56 | ||
| 57 | ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, | 57 | ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, |
| 58 | const char *filename, enum ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug, bool is_small); | 58 | const char *filename, enum ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug, |
| 59 | bool is_small, bool time_report); | ||
| 59 | 60 | ||
| 60 | ZIG_EXTERN_C LLVMTypeRef ZigLLVMTokenTypeInContext(LLVMContextRef context_ref); | 61 | ZIG_EXTERN_C LLVMTypeRef ZigLLVMTokenTypeInContext(LLVMContextRef context_ref); |
| 61 | 62 |
std/build.zig+26| ... | @@ -232,6 +232,8 @@ pub const Builder = struct { | ... | @@ -232,6 +232,8 @@ pub const Builder = struct { |
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | pub fn make(self: *Builder, step_names: []const []const u8) !void { | 234 | pub fn make(self: *Builder, step_names: []const []const u8) !void { |
| 235 | try self.makePath(self.cache_root); | ||
| 236 | |||
| 235 | var wanted_steps = ArrayList(*Step).init(self.allocator); | 237 | var wanted_steps = ArrayList(*Step).init(self.allocator); |
| 236 | defer wanted_steps.deinit(); | 238 | defer wanted_steps.deinit(); |
| 237 | 239 | ||
| ... | @@ -1641,6 +1643,7 @@ pub const TestStep = struct { | ... | @@ -1641,6 +1643,7 @@ pub const TestStep = struct { |
| 1641 | lib_paths: ArrayList([]const u8), | 1643 | lib_paths: ArrayList([]const u8), |
| 1642 | object_files: ArrayList([]const u8), | 1644 | object_files: ArrayList([]const u8), |
| 1643 | no_rosegment: bool, | 1645 | no_rosegment: bool, |
| 1646 | output_path: ?[]const u8, | ||
| 1644 | 1647 | ||
| 1645 | pub fn init(builder: *Builder, root_src: []const u8) TestStep { | 1648 | pub fn init(builder: *Builder, root_src: []const u8) TestStep { |
| 1646 | const step_name = builder.fmt("test {}", root_src); | 1649 | const step_name = builder.fmt("test {}", root_src); |
| ... | @@ -1659,6 +1662,7 @@ pub const TestStep = struct { | ... | @@ -1659,6 +1662,7 @@ pub const TestStep = struct { |
| 1659 | .lib_paths = ArrayList([]const u8).init(builder.allocator), | 1662 | .lib_paths = ArrayList([]const u8).init(builder.allocator), |
| 1660 | .object_files = ArrayList([]const u8).init(builder.allocator), | 1663 | .object_files = ArrayList([]const u8).init(builder.allocator), |
| 1661 | .no_rosegment = false, | 1664 | .no_rosegment = false, |
| 1665 | .output_path = null, | ||
| 1662 | }; | 1666 | }; |
| 1663 | } | 1667 | } |
| 1664 | 1668 | ||
| ... | @@ -1682,6 +1686,24 @@ pub const TestStep = struct { | ... | @@ -1682,6 +1686,24 @@ pub const TestStep = struct { |
| 1682 | self.build_mode = mode; | 1686 | self.build_mode = mode; |
| 1683 | } | 1687 | } |
| 1684 | 1688 | ||
| 1689 | pub fn setOutputPath(self: *TestStep, file_path: []const u8) void { | ||
| 1690 | self.output_path = file_path; | ||
| 1691 | |||
| 1692 | // catch a common mistake | ||
| 1693 | if (mem.eql(u8, self.builder.pathFromRoot(file_path), self.builder.pathFromRoot("."))) { | ||
| 1694 | debug.panic("setOutputPath wants a file path, not a directory\n"); | ||
| 1695 | } | ||
| 1696 | } | ||
| 1697 | |||
| 1698 | pub fn getOutputPath(self: *TestStep) []const u8 { | ||
| 1699 | if (self.output_path) |output_path| { | ||
| 1700 | return output_path; | ||
| 1701 | } else { | ||
| 1702 | const basename = self.builder.fmt("test{}", self.target.exeFileExt()); | ||
| 1703 | return os.path.join(self.builder.allocator, self.builder.cache_root, basename) catch unreachable; | ||
| 1704 | } | ||
| 1705 | } | ||
| 1706 | |||
| 1685 | pub fn linkSystemLibrary(self: *TestStep, name: []const u8) void { | 1707 | pub fn linkSystemLibrary(self: *TestStep, name: []const u8) void { |
| 1686 | self.link_libs.put(name) catch unreachable; | 1708 | self.link_libs.put(name) catch unreachable; |
| 1687 | } | 1709 | } |
| ... | @@ -1746,6 +1768,10 @@ pub const TestStep = struct { | ... | @@ -1746,6 +1768,10 @@ pub const TestStep = struct { |
| 1746 | builtin.Mode.ReleaseSmall => try zig_args.append("--release-small"), | 1768 | builtin.Mode.ReleaseSmall => try zig_args.append("--release-small"), |
| 1747 | } | 1769 | } |
| 1748 | 1770 | ||
| 1771 | const output_path = builder.pathFromRoot(self.getOutputPath()); | ||
| 1772 | try zig_args.append("--output"); | ||
| 1773 | try zig_args.append(output_path); | ||
| 1774 | |||
| 1749 | switch (self.target) { | 1775 | switch (self.target) { |
| 1750 | Target.Native => {}, | 1776 | Target.Native => {}, |
| 1751 | Target.Cross => |cross_target| { | 1777 | Target.Cross => |cross_target| { |