authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-12 12:40:16-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2018-09-12 12:40:16-04:00
log0cfd019377c4e91924d8f57a4c7400a2d62f8751
tree9c62a0569648d505233743409fade82e0f36b172
parent7bd8a2695b5fe0b1993003c0c6e02cb99de5ab33
parent3a49d115cf38154f0094d9615334529890059006
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #1494 from ziglang/stage1-caching

stage1 caching

30 files changed, 2644 insertions(+), 535 deletions(-)

CMakeLists.txt+13-1
......@@ -390,7 +390,7 @@ if(MSVC)
390390 )
391391else()
392392 set_target_properties(embedded_softfloat PROPERTIES
393 COMPILE_FLAGS "-std=c99"
393 COMPILE_FLAGS "-std=c99 -O3"
394394 )
395395endif()
396396target_include_directories(embedded_softfloat PUBLIC
......@@ -409,7 +409,9 @@ set(ZIG_SOURCES
409409 "${CMAKE_SOURCE_DIR}/src/bigint.cpp"
410410 "${CMAKE_SOURCE_DIR}/src/buffer.cpp"
411411 "${CMAKE_SOURCE_DIR}/src/c_tokenizer.cpp"
412 "${CMAKE_SOURCE_DIR}/src/cache_hash.cpp"
412413 "${CMAKE_SOURCE_DIR}/src/codegen.cpp"
414 "${CMAKE_SOURCE_DIR}/src/compiler.cpp"
413415 "${CMAKE_SOURCE_DIR}/src/errmsg.cpp"
414416 "${CMAKE_SOURCE_DIR}/src/error.cpp"
415417 "${CMAKE_SOURCE_DIR}/src/ir.cpp"
......@@ -424,6 +426,9 @@ set(ZIG_SOURCES
424426 "${CMAKE_SOURCE_DIR}/src/util.cpp"
425427 "${CMAKE_SOURCE_DIR}/src/translate_c.cpp"
426428)
429set(BLAKE_SOURCES
430 "${CMAKE_SOURCE_DIR}/src/blake2b.c"
431)
427432set(ZIG_CPP_SOURCES
428433 "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
429434 "${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp"
......@@ -790,6 +795,7 @@ else()
790795 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")
791796endif()
792797
798set(BLAKE_CFLAGS "-std=c99")
793799
794800set(EXE_LDFLAGS " ")
795801if(MINGW)
......@@ -811,6 +817,11 @@ set_target_properties(zig_cpp PROPERTIES
811817 COMPILE_FLAGS ${EXE_CFLAGS}
812818)
813819
820add_library(embedded_blake STATIC ${BLAKE_SOURCES})
821set_target_properties(embedded_blake PROPERTIES
822 COMPILE_FLAGS "${BLAKE_CFLAGS} -O3"
823)
824
814825add_executable(zig ${ZIG_SOURCES})
815826set_target_properties(zig PROPERTIES
816827 COMPILE_FLAGS ${EXE_CFLAGS}
......@@ -819,6 +830,7 @@ set_target_properties(zig PROPERTIES
819830
820831target_link_libraries(zig LINK_PUBLIC
821832 zig_cpp
833 embedded_blake
822834 ${SOFTFLOAT_LIBRARIES}
823835 ${CLANG_LIBRARIES}
824836 ${LLD_LIBRARIES}
build.zig+2-1
......@@ -16,11 +16,12 @@ pub fn build(b: *Builder) !void {
1616 var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
1717
1818 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;
1920 var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8{
2021 docgen_exe.getOutputPath(),
2122 rel_zig_exe,
2223 "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,
2425 });
2526 docgen_cmd.step.dependOn(&docgen_exe.step);
2627
doc/docgen.zig+7
......@@ -11,6 +11,7 @@ const max_doc_file_size = 10 * 1024 * 1024;
1111const exe_ext = std.build.Target(std.build.Target.Native).exeFileExt();
1212const obj_ext = std.build.Target(std.build.Target.Native).oFileExt();
1313const tmp_dir_name = "docgen_tmp";
14const test_out_path = tmp_dir_name ++ os.path.sep_str ++ "test" ++ exe_ext;
1415
1516pub fn main() !void {
1617 var direct_allocator = std.heap.DirectAllocator.init();
......@@ -821,6 +822,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
821822 zig_exe,
822823 "test",
823824 tmp_source_file_name,
825 "--output",
826 test_out_path,
824827 });
825828 try out.print("<pre><code class=\"shell\">$ zig test {}.zig", code.name);
826829 switch (code.mode) {
......@@ -863,6 +866,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
863866 "--color",
864867 "on",
865868 tmp_source_file_name,
869 "--output",
870 test_out_path,
866871 });
867872 try out.print("<pre><code class=\"shell\">$ zig test {}.zig", code.name);
868873 switch (code.mode) {
......@@ -918,6 +923,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
918923 zig_exe,
919924 "test",
920925 tmp_source_file_name,
926 "--output",
927 test_out_path,
921928 });
922929 switch (code.mode) {
923930 builtin.Mode.Debug => {},
src/all_types.hpp+137-137
......@@ -10,6 +10,7 @@
1010
1111#include "list.hpp"
1212#include "buffer.hpp"
13#include "cache_hash.hpp"
1314#include "zig_llvm.h"
1415#include "hash_map.hpp"
1516#include "errmsg.hpp"
......@@ -1550,22 +1551,50 @@ struct LinkLib {
15501551 bool provided_explicitly;
15511552};
15521553
1554// When adding fields, check if they should be added to the hash computation in build_with_cache
15531555struct CodeGen {
1556 //////////////////////////// Runtime State
15541557 LLVMModuleRef module;
15551558 ZigList<ErrorMsg*> errors;
15561559 LLVMBuilderRef builder;
15571560 ZigLLVMDIBuilder *dbuilder;
15581561 ZigLLVMDICompileUnit *compile_unit;
15591562 ZigLLVMDIFile *compile_unit_file;
1560
1561 ZigList<LinkLib *> link_libs_list;
15621563 LinkLib *libc_link_lib;
1563
1564 // add -framework [name] args to linker
1565 ZigList<Buf *> darwin_frameworks;
1566 // add -rpath [name] args to linker
1567 ZigList<Buf *> rpath_list;
1568
1564 LLVMTargetDataRef target_data_ref;
1565 LLVMTargetMachineRef target_machine;
1566 ZigLLVMDIFile *dummy_di_file;
1567 LLVMValueRef cur_ret_ptr;
1568 LLVMValueRef cur_fn_val;
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;
15691598
15701599 // reminder: hash tables must be initialized before use
15711600 HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table;
......@@ -1582,15 +1611,29 @@ struct CodeGen {
15821611 HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table;
15831612 HashMap<const ZigType *, ConstExprValue *, type_ptr_hash, type_ptr_eql> type_info_cache;
15841613
1585
15861614 ZigList<ImportTableEntry *> import_queue;
15871615 size_t import_queue_index;
15881616 ZigList<Tld *> resolve_queue;
15891617 size_t resolve_queue_index;
15901618 ZigList<AstNode *> use_queue;
15911619 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;
15921628
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;
15941637
15951638 struct {
15961639 ZigType *entry_bool;
......@@ -1626,165 +1669,122 @@ struct CodeGen {
16261669 ZigType *entry_arg_tuple;
16271670 ZigType *entry_promise;
16281671 } 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;
16291677
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;
16561678 Buf triple_str;
1657 BuildMode build_mode;
1658 bool is_test_build;
1659 bool have_err_ret_tracing;
1660 uint32_t target_os_index;
1661 uint32_t target_arch_index;
1662 uint32_t target_environ_index;
1663 uint32_t target_oformat_index;
1664 LLVMTargetMachineRef target_machine;
1665 ZigLLVMDIFile *dummy_di_file;
1666 bool is_native_target;
1667 PackageTableEntry *root_package;
1668 PackageTableEntry *std_package;
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;
1679 Buf global_asm;
1680 Buf *out_h_path;
1681 Buf artifact_dir;
1682 Buf output_file_path;
1683 Buf o_file_output_path;
1684 Buf *wanted_output_file_path;
1685 Buf cache_dir;
1686
1687 IrInstruction *invalid_instruction;
1688
1689 ConstExprValue const_void_val;
1690 ConstExprValue panic_msg_vals[PanicMsgIdCount];
16801691
16811692 // The function definitions this module includes.
16821693 ZigList<ZigFn *> fn_defs;
16831694 size_t fn_defs_index;
16841695 ZigList<TldVar *> global_vars;
16851696
1686 OutType out_type;
16871697 ZigFn *cur_fn;
16881698 ZigFn *main_fn;
16891699 ZigFn *panic_fn;
1690 LLVMValueRef cur_ret_ptr;
1691 LLVMValueRef cur_fn_val;
1692 LLVMValueRef cur_err_ret_trace_val_arg;
1693 LLVMValueRef cur_err_ret_trace_val_stack;
1700 AstNode *root_export_decl;
1701
1702 CacheHash cache_hash;
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;
16941719 bool c_want_stdint;
16951720 bool c_want_stdbool;
1696 AstNode *root_export_decl;
1697 size_t version_major;
1698 size_t version_minor;
1699 size_t version_patch;
17001721 bool verbose_tokenize;
17011722 bool verbose_ast;
17021723 bool verbose_link;
17031724 bool verbose_ir;
17041725 bool verbose_llvm_ir;
17051726 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;
17331727 bool error_during_imports;
1728 bool generate_error_name_table;
1729 bool enable_cache;
1730 bool enable_time_report;
17341731
1735 LLVMValueRef sp_md_node;
1736
1737 const char **clang_argv;
1738 size_t clang_argv_len;
1732 //////////////////////////// Participates in Input Parameter Cache Hash
1733 ZigList<LinkLib *> link_libs_list;
1734 // add -framework [name] args to linker
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;
17391741 ZigList<const char *> lib_dirs;
17401742
1741 const char **llvm_argv;
1742 size_t llvm_argv_len;
1743
1744 ZigList<ZigFn *> test_fns;
1745 ZigType *test_fn_type;
1743 size_t version_major;
1744 size_t version_minor;
1745 size_t version_patch;
1746 const char *linker_script;
17461747
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;
17471760 bool each_lib_rpath;
17481761
1749 ZigType *err_tag_type;
1750 ZigList<ZigLLVMDIEnumerator *> err_enumerators;
1751 ZigList<ErrorTableEntry *> errors_by_index;
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
1762 Buf *mmacosx_version_min;
1763 Buf *mios_version_min;
1764 Buf *root_out_name;
17681765 Buf *test_filter;
17691766 Buf *test_name_prefix;
1767 PackageTableEntry *root_package;
17701768
1771 ZigList<TimeEvent> timing_events;
1772
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;
1769 const char **llvm_argv;
1770 size_t llvm_argv_len;
17821771
1783 ZigList<ZigLLVMDIType **> error_di_types;
1772 const char **clang_argv;
1773 size_t clang_argv_len;
17841774
1785 ZigList<Buf *> forbidden_libs;
1775 //////////////////////////// Unsorted
17861776
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;
17881788};
17891789
17901790enum VarLinkage {
src/analyze.cpp+14-1
......@@ -6289,6 +6289,12 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) {
62896289 if (is_libc && g->libc_link_lib != nullptr)
62906290 return g->libc_link_lib;
62916291
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
62926298 for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
62936299 LinkLib *existing_lib = g->link_libs_list.at(i);
62946300 if (buf_eql_buf(existing_lib->name, name)) {
......@@ -6398,6 +6404,14 @@ not_integer:
63986404 return nullptr;
63996405}
64006406
6407Error 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
64016415X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) {
64026416 size_t ty_size = type_size(g, ty);
64036417 if (get_codegen_ptr_type(ty) != nullptr)
......@@ -6478,4 +6492,3 @@ bool type_is_c_abi_int(CodeGen *g, ZigType *ty) {
64786492 ty->id == ZigTypeIdUnreachable ||
64796493 get_codegen_ptr_type(ty) != nullptr);
64806494}
6481
src/analyze.hpp+2
......@@ -209,6 +209,8 @@ ZigType *get_primitive_type(CodeGen *g, Buf *name);
209209bool calling_convention_allows_zig_types(CallingConvention cc);
210210const char *calling_convention_name(CallingConvention cc);
211211
212Error ATTRIBUTE_MUST_USE file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents);
213
212214void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk);
213215X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty);
214216bool 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)
28extern "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
53static 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
68static 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
87static 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
100static 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
111static 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
124static 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
141static 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
152static 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
163static BLAKE2_INLINE uint32_t rotr32( const uint32_t w, const unsigned c )
164{
165 return ( w >> c ) | ( w << ( 32 - c ) );
166}
167
168static 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() */
174static 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
182static const uint64_t blake2b_IV[8] =
183{
184 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
185 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
186 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
187 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
188};
189
190static 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
207static void blake2b_set_lastnode( blake2b_state *S )
208{
209 S->f[1] = (uint64_t)-1;
210}
211
212/* Some helper functions, not necessarily useful */
213static int blake2b_is_lastblock( const blake2b_state *S )
214{
215 return S->f[0] != 0;
216}
217
218static 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
225static 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
231static 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 */
240int 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
257int 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
279int 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
336static 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
380int 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
407int 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. */
432int 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
461int 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)
466int 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"
475int 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;
534fail:
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) {
7878 return buf;
7979}
8080
81static inline Buf *buf_create_from_slice(Slice<uint8_t> slice) {
82 return buf_create_from_mem((const char *)slice.ptr, slice.len);
83}
84
8185static inline Buf *buf_create_from_str(const char *str) {
8286 return buf_create_from_mem(str, strlen(str));
8387}
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
15void 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
24void 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
31void 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
40void 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
49void cache_bool(CacheHash *ch, bool x) {
50 assert(ch->manifest_file_path == nullptr);
51 blake2b_update(&ch->blake, &x, 1);
52}
53
54void 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
61void 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
71void 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
82void 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
91void 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
101void 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
111void 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
121void 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
132static uint8_t base64_fs_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
133static 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
158static 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
191static 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
219static 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
244Error 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
405Error 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
419Error 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
425static 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
443Error 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
466void 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
14struct LinkLib;
15
16struct CacheHashFile {
17 Buf *path;
18 OsTimeStamp mtime;
19 uint8_t bin_digest[48];
20 Buf *contents;
21};
22
23struct 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.
33void cache_init(CacheHash *ch, Buf *manifest_dir);
34
35// Next, use the hash population functions to add the initial parameters.
36void cache_str(CacheHash *ch, const char *ptr);
37void cache_int(CacheHash *ch, int x);
38void cache_bool(CacheHash *ch, bool x);
39void cache_usize(CacheHash *ch, size_t x);
40void cache_buf(CacheHash *ch, Buf *buf);
41void cache_buf_opt(CacheHash *ch, Buf *buf);
42void cache_list_of_link_lib(CacheHash *ch, LinkLib **ptr, size_t len);
43void cache_list_of_buf(CacheHash *ch, Buf **ptr, size_t len);
44void cache_list_of_file(CacheHash *ch, Buf **ptr, size_t len);
45void cache_list_of_str(CacheHash *ch, const char **ptr, size_t len);
46void cache_file(CacheHash *ch, Buf *path);
47void 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.
54Error 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.
58Error 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.
62Error 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
65Error 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.
68void cache_release(CacheHash *ch);
69
70
71#endif
src/codegen.cpp+328-96
......@@ -8,12 +8,12 @@
88#include "analyze.hpp"
99#include "ast_render.hpp"
1010#include "codegen.hpp"
11#include "compiler.hpp"
1112#include "config.h"
1213#include "errmsg.hpp"
1314#include "error.hpp"
1415#include "hash_map.hpp"
1516#include "ir.hpp"
16#include "link.hpp"
1717#include "os.hpp"
1818#include "translate_c.hpp"
1919#include "target.hpp"
......@@ -183,14 +183,14 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
183183 return g;
184184}
185185
186void codegen_destroy(CodeGen *codegen) {
187 LLVMDisposeTargetMachine(codegen->target_machine);
188}
189
190186void codegen_set_output_h_path(CodeGen *g, Buf *h_path) {
191187 g->out_h_path = h_path;
192188}
193189
190void codegen_set_output_path(CodeGen *g, Buf *path) {
191 g->wanted_output_file_path = path;
192}
193
194194void codegen_set_clang_argv(CodeGen *g, const char **args, size_t len) {
195195 g->clang_argv = args;
196196 g->clang_argv_len = len;
......@@ -243,10 +243,6 @@ void codegen_set_out_name(CodeGen *g, Buf *out_name) {
243243 g->root_out_name = out_name;
244244}
245245
246void codegen_set_cache_dir(CodeGen *g, Buf cache_dir) {
247 g->cache_dir = cache_dir;
248}
249
250246void codegen_set_libc_lib_dir(CodeGen *g, Buf *libc_lib_dir) {
251247 g->libc_lib_dir = libc_lib_dir;
252248}
......@@ -6076,13 +6072,6 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val,
60766072 // TODO ^^ make an actual global variable
60776073}
60786074
6079static 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
60866075static void validate_inline_fns(CodeGen *g) {
60876076 for (size_t i = 0; i < g->inline_fns.length; i += 1) {
60886077 ZigFn *fn_entry = g->inline_fns.at(i);
......@@ -6097,8 +6086,6 @@ static void validate_inline_fns(CodeGen *g) {
60976086static void do_code_gen(CodeGen *g) {
60986087 assert(!g->errors.length);
60996088
6100 codegen_add_time_event(g, "Code Generation");
6101
61026089 {
61036090 // create debug type for error sets
61046091 assert(g->err_enumerators.length == g->errors_by_index.length);
......@@ -6401,45 +6388,18 @@ static void do_code_gen(CodeGen *g) {
64016388 char *error = nullptr;
64026389 LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error);
64036390#endif
6391}
64046392
6405 codegen_add_time_event(g, "LLVM Emit Output");
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
6393static void zig_llvm_emit_output(CodeGen *g) {
64376394 bool is_small = g->build_mode == BuildModeSmallRelease;
64386395
6396 Buf *output_path = &g->o_file_output_path;
6397 char *err_msg = nullptr;
64396398 switch (g->emit_file_type) {
64406399 case EmitFileTypeBinary:
64416400 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))
64436403 {
64446404 zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg);
64456405 }
......@@ -6449,22 +6409,22 @@ static void do_code_gen(CodeGen *g) {
64496409
64506410 case EmitFileTypeAssembly:
64516411 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))
64536414 {
64546415 zig_panic("unable to write assembly file %s: %s", buf_ptr(output_path), err_msg);
64556416 }
64566417 validate_inline_fns(g);
6457 g->link_objects.append(output_path);
64586418 break;
64596419
64606420 case EmitFileTypeLLVMIr:
64616421 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))
64636424 {
64646425 zig_panic("unable to write llvm-ir file %s: %s", buf_ptr(output_path), err_msg);
64656426 }
64666427 validate_inline_fns(g);
6467 g->link_objects.append(output_path);
64686428 break;
64696429
64706430 default:
......@@ -7189,36 +7149,84 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
71897149 return contents;
71907150}
71917151
7192static void define_builtin_compile_vars(CodeGen *g) {
7152static Error define_builtin_compile_vars(CodeGen *g) {
71937153 if (g->std_package == nullptr)
7194 return;
7154 return ErrorNone;
71957155
7196 const char *builtin_zig_basename = "builtin.zig";
7197 Buf *builtin_zig_path = buf_alloc();
7198 os_path_join(&g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
7156 Error err;
71997157
7200 Buf *contents = codegen_generate_builtin_source(g);
7201 ensure_cache_dir(g);
7202 os_write_file(builtin_zig_path, contents);
7158 Buf *manifest_dir = buf_alloc();
7159 os_path_join(get_stage1_cache_path(), buf_create_from_str("builtin"), manifest_dir);
72037160
7204 Buf *resolved_path = buf_alloc();
7205 Buf *resolve_paths[] = {builtin_zig_path};
7206 *resolved_path = os_path_resolve(resolve_paths, 1);
7161 CacheHash cache_hash;
7162 cache_init(&cache_hash, manifest_dir);
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 }
72077214
72087215 assert(g->root_package);
72097216 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);
72117218 g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
72127219 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);
72147221 scan_import(g, g->compile_var_import);
7222
7223 return ErrorNone;
72157224}
72167225
72177226static void init(CodeGen *g) {
72187227 if (g->module)
72197228 return;
72207229
7221
72227230 if (g->llvm_argv_len > 0) {
72237231 const char **args = allocate_nonzero<const char *>(g->llvm_argv_len + 2);
72247232 args[0] = "zig (LLVM option parsing)";
......@@ -7325,7 +7333,11 @@ static void init(CodeGen *g) {
73257333 g->have_err_ret_tracing = g->build_mode != BuildModeFastRelease && g->build_mode != BuildModeSmallRelease;
73267334
73277335 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 }
73297341}
73307342
73317343void codegen_translate_c(CodeGen *g, Buf *full_path) {
......@@ -7371,8 +7383,8 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package
73717383 Buf *resolved_path = buf_alloc();
73727384 *resolved_path = os_path_resolve(resolve_paths, 1);
73737385 Buf *import_code = buf_alloc();
7374 int err;
7375 if ((err = os_fetch_file_path(resolved_path, import_code, false))) {
7386 Error err;
7387 if ((err = file_fetch(g, resolved_path, import_code))) {
73767388 zig_panic("unable to open '%s': %s\n", buf_ptr(&path_to_code_src), err_str(err));
73777389 }
73787390
......@@ -7445,23 +7457,32 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
74457457 g->test_runner_import = add_special_code(g, g->test_runner_package, "test_runner.zig");
74467458}
74477459
7448static void gen_root_source(CodeGen *g) {
7460static Buf *get_resolved_root_src_path(CodeGen *g) {
7461 // TODO memoize
74497462 if (buf_len(&g->root_package->root_src_path) == 0)
7450 return;
7451
7452 codegen_add_time_event(g, "Semantic Analysis");
7463 return nullptr;
74537464
7454 Buf *rel_full_path = buf_alloc();
7455 os_path_join(&g->root_package->root_src_dir, &g->root_package->root_src_path, rel_full_path);
7465 Buf rel_full_path = BUF_INIT;
7466 os_path_join(&g->root_package->root_src_dir, &g->root_package->root_src_path, &rel_full_path);
74567467
74577468 Buf *resolved_path = buf_alloc();
7458 Buf *resolve_paths[] = {rel_full_path};
7469 Buf *resolve_paths[] = {&rel_full_path};
74597470 *resolved_path = os_path_resolve(resolve_paths, 1);
74607471
7472 return resolved_path;
7473}
7474
7475static void gen_root_source(CodeGen *g) {
7476 Buf *resolved_path = get_resolved_root_src_path(g);
7477 if (resolved_path == nullptr)
7478 return;
7479
74617480 Buf *source_code = buf_alloc();
74627481 int err;
7463 if ((err = os_fetch_file_path(rel_full_path, source_code, true))) {
7464 fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(rel_full_path), err_str(err));
7482 // No need for using the caching system for this file fetch because it is handled
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));
74657486 exit(1);
74667487 }
74677488
......@@ -7526,6 +7547,8 @@ static void gen_global_asm(CodeGen *g) {
75267547 int err;
75277548 for (size_t i = 0; i < g->assembly_files.length; i += 1) {
75287549 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.
75297552 if ((err = os_fetch_file_path(asm_file, &contents, false))) {
75307553 zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err));
75317554 }
......@@ -7789,19 +7812,11 @@ static Buf *preprocessor_mangle(Buf *src) {
77897812}
77907813
77917814static void gen_h_file(CodeGen *g) {
7792 if (!g->want_h_file)
7793 return;
7794
77957815 GenH gen_h_data = {0};
77967816 GenH *gen_h = &gen_h_data;
77977817
7798 codegen_add_time_event(g, "Generate .h");
7799
78007818 assert(!g->is_test_build);
7801
7802 if (!g->out_h_path) {
7803 g->out_h_path = buf_sprintf("%s.h", buf_ptr(g->root_out_name));
7804 }
7819 assert(g->out_h_path != nullptr);
78057820
78067821 FILE *out_h = fopen(buf_ptr(g->out_h_path), "wb");
78077822 if (!out_h)
......@@ -8004,14 +8019,231 @@ void codegen_add_time_event(CodeGen *g, const char *name) {
80048019 g->timing_events.append({os_get_time(), name});
80058020}
80068021
8007void codegen_build(CodeGen *g) {
8022static 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()
8042static 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
8100static 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
8182void codegen_build_and_link(CodeGen *g) {
8183 Error err;
80088184 assert(g->out_type != OutTypeUnknown);
8009 init(g);
80108185
8011 gen_global_asm(g);
8012 gen_root_source(g);
8013 do_code_gen(g);
8014 gen_h_file(g);
8186 Buf *stage1_dir = get_stage1_cache_path();
8187 Buf *artifact_dir = buf_alloc();
8188 Buf digest = BUF_INIT;
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");
80158247}
80168248
80178249PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path) {
src/codegen.hpp+3-3
......@@ -16,7 +16,6 @@
1616
1717CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode,
1818 Buf *zig_lib_dir);
19void codegen_destroy(CodeGen *codegen);
2019
2120void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len);
2221void 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);
4746void codegen_set_test_filter(CodeGen *g, Buf *filter);
4847void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);
4948void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch);
50void codegen_set_cache_dir(CodeGen *g, Buf cache_dir);
5149void codegen_set_output_h_path(CodeGen *g, Buf *h_path);
50void codegen_set_output_path(CodeGen *g, Buf *path);
5251void codegen_add_time_event(CodeGen *g, const char *name);
5352void codegen_print_timing_report(CodeGen *g, FILE *f);
54void codegen_build(CodeGen *g);
53void codegen_link(CodeGen *g);
54void codegen_build_and_link(CodeGen *g);
5555
5656PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path);
5757void 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
5static Buf saved_compiler_id = BUF_INIT;
6static Buf saved_app_data_dir = BUF_INIT;
7static Buf saved_stage1_path = BUF_INIT;
8
9Buf *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
22Error 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
14Buf *get_stage1_cache_path();
15Error get_compiler_id(Buf **result);
16
17#endif
src/error.cpp+5
......@@ -27,6 +27,11 @@ const char *err_str(int err) {
2727 case ErrorNegativeDenominator: return "negative denominator";
2828 case ErrorShiftedOutOneBits: return "exact shift shifted out one bits";
2929 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";
3035 }
3136 return "(invalid error)";
3237}
src/error.hpp+5
......@@ -27,6 +27,11 @@ enum Error {
2727 ErrorNegativeDenominator,
2828 ErrorShiftedOutOneBits,
2929 ErrorCCompileErrors,
30 ErrorEndOfFile,
31 ErrorIsDir,
32 ErrorUnsupportedOperatingSystem,
33 ErrorSharingViolation,
34 ErrorPipeBusy,
3035};
3136
3237const char *err_str(int err);
src/ir.cpp+11-6
......@@ -16231,6 +16231,8 @@ static ZigType *ir_analyze_instruction_union_tag(IrAnalyze *ira, IrInstructionUn
1623116231}
1623216232
1623316233static ZigType *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructionImport *import_instruction) {
16234 Error err;
16235
1623416236 IrInstruction *name_value = import_instruction->name->other;
1623516237 Buf *import_target_str = ir_resolve_str(ira, name_value);
1623616238 if (!import_target_str)
......@@ -16274,8 +16276,7 @@ static ZigType *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructionImpor
1627416276 return ira->codegen->builtin_types.entry_namespace;
1627516277 }
1627616278
16277 int err;
16278 if ((err = os_fetch_file_path(resolved_path, import_code, true))) {
16279 if ((err = file_fetch(ira->codegen, resolved_path, import_code))) {
1627916280 if (err == ErrorFileNotFound) {
1628016281 ir_add_error_node(ira, source_node,
1628116282 buf_sprintf("unable to find '%s'", buf_ptr(import_target_path)));
......@@ -16286,6 +16287,7 @@ static ZigType *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructionImpor
1628616287 return ira->codegen->builtin_types.entry_invalid;
1628716288 }
1628816289 }
16290
1628916291 ImportTableEntry *target_import = add_source_file(ira->codegen, target_package, resolved_path, import_code);
1629016292
1629116293 scan_import(ira->codegen, target_import);
......@@ -17959,6 +17961,12 @@ static ZigType *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTy
1795917961}
1796017962
1796117963static 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
1796217970 AstNode *node = instruction->base.source_node;
1796317971 assert(node->type == NodeTypeFnCallExpr);
1796417972 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
1810518113 // load from file system into const expr
1810618114 Buf *file_contents = buf_alloc();
1810718115 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))) {
1810918117 if (err == ErrorFileNotFound) {
1811018118 ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path)));
1811118119 return ira->codegen->builtin_types.entry_invalid;
......@@ -18115,9 +18123,6 @@ static ZigType *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstructionE
1811518123 }
1811618124 }
1811718125
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
1812118126 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
1812218127 init_const_str_lit(ira->codegen, out_val, file_contents);
1812318128
src/link.cpp+18-61
......@@ -5,7 +5,6 @@
55 * See http://opensource.org/licenses/MIT
66 */
77
8#include "link.hpp"
98#include "os.hpp"
109#include "config.h"
1110#include "codegen.hpp"
......@@ -13,7 +12,6 @@
1312
1413struct LinkJob {
1514 CodeGen *codegen;
16 Buf out_file;
1715 ZigList<const char *> args;
1816 bool link_in_crt;
1917 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)
4442 child_gen->verbose_llvm_ir = parent_gen->verbose_llvm_ir;
4543 child_gen->verbose_cimport = parent_gen->verbose_cimport;
4644
47 codegen_set_cache_dir(child_gen, parent_gen->cache_dir);
48
4945 codegen_set_strip(child_gen, parent_gen->strip_debug_symbols);
5046 codegen_set_is_static(child_gen, parent_gen->is_static);
5147
......@@ -62,16 +58,9 @@ static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path)
6258 new_link_lib->provided_explicitly = link_lib->provided_explicitly;
6359 }
6460
65 codegen_build(child_gen);
66 const char *o_ext = target_o_file_ext(&child_gen->zig_target);
67 Buf *o_out_name = buf_sprintf("%s%s", oname, o_ext);
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;
61 child_gen->enable_cache = true;
62 codegen_build_and_link(child_gen);
63 return &child_gen->output_file_path;
7564}
7665
7766static Buf *build_o(CodeGen *parent_gen, const char *oname) {
......@@ -239,15 +228,15 @@ static void construct_linker_job_elf(LinkJob *lj) {
239228 } else if (shared) {
240229 lj->args.append("-shared");
241230
242 if (buf_len(&lj->out_file) == 0) {
243 buf_appendf(&lj->out_file, "lib%s.so.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize "",
231 if (buf_len(&g->output_file_path) == 0) {
232 buf_appendf(&g->output_file_path, "lib%s.so.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize "",
244233 buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch);
245234 }
246235 soname = buf_sprintf("lib%s.so.%" ZIG_PRI_usize "", buf_ptr(g->root_out_name), g->version_major);
247236 }
248237
249238 lj->args.append("-o");
250 lj->args.append(buf_ptr(&lj->out_file));
239 lj->args.append(buf_ptr(&g->output_file_path));
251240
252241 if (lj->link_in_crt) {
253242 const char *crt1o;
......@@ -399,7 +388,7 @@ static void construct_linker_job_wasm(LinkJob *lj) {
399388
400389 lj->args.append("--relocatable"); // So lld doesn't look for _start.
401390 lj->args.append("-o");
402 lj->args.append(buf_ptr(&lj->out_file));
391 lj->args.append(buf_ptr(&g->output_file_path));
403392
404393 // .o files
405394 for (size_t i = 0; i < g->link_objects.length; i += 1) {
......@@ -480,7 +469,7 @@ static void construct_linker_job_coff(LinkJob *lj) {
480469 // }
481470 //}
482471
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))));
484473
485474 if (g->libc_link_lib != nullptr) {
486475 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) {
587576 buf_appendf(def_contents, "\n");
588577
589578 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);
591580 os_write_file(def_path, def_contents);
592581
593582 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);
595584
596585 gen_lib_args.resize(0);
597586 gen_lib_args.append("link");
......@@ -799,8 +788,8 @@ static void construct_linker_job_macho(LinkJob *lj) {
799788 //lj->args.append("-install_name");
800789 //lj->args.append(buf_ptr(dylib_install_name));
801790
802 if (buf_len(&lj->out_file) == 0) {
803 buf_appendf(&lj->out_file, "lib%s.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".dylib",
791 if (buf_len(&g->output_file_path) == 0) {
792 buf_appendf(&g->output_file_path, "lib%s.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".dylib",
804793 buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch);
805794 }
806795 }
......@@ -834,13 +823,13 @@ static void construct_linker_job_macho(LinkJob *lj) {
834823 }
835824
836825 lj->args.append("-o");
837 lj->args.append(buf_ptr(&lj->out_file));
826 lj->args.append(buf_ptr(&g->output_file_path));
838827
839828 for (size_t i = 0; i < g->rpath_list.length; i += 1) {
840829 Buf *rpath = g->rpath_list.at(i);
841830 add_rpath(lj, rpath);
842831 }
843 add_rpath(lj, &lj->out_file);
832 add_rpath(lj, &g->output_file_path);
844833
845834 if (shared) {
846835 lj->args.append("-headerpad_max_install_names");
......@@ -944,7 +933,8 @@ static void construct_linker_job(LinkJob *lj) {
944933 }
945934}
946935
947void codegen_link(CodeGen *g, const char *out_file) {
936void codegen_link(CodeGen *g) {
937 assert(g->out_type != OutTypeObj);
948938 codegen_add_time_event(g, "Build Dependencies");
949939
950940 LinkJob lj = {0};
......@@ -955,11 +945,6 @@ void codegen_link(CodeGen *g, const char *out_file) {
955945
956946 lj.rpath_table.init(4);
957947 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 }
963948
964949 if (g->verbose_llvm_ir) {
965950 fprintf(stderr, "\nOptimization:\n");
......@@ -968,35 +953,9 @@ void codegen_link(CodeGen *g, const char *out_file) {
968953 LLVMDumpModule(g->module);
969954 }
970955
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
993956 if (g->out_type == OutTypeLib && g->is_static) {
994 // invoke `ar`
995 // example:
996 // # static link into libfoo.a
997 // ar rcs libfoo.a foo1.o foo2.o
998 zig_panic("TODO invoke ar");
999 return;
957 fprintf(stderr, "Zig does not yet support creating static libraries\nSee https://github.com/ziglang/zig/issues/1493\n");
958 exit(1);
1000959 }
1001960
1002961 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) {
1019978 fprintf(stderr, "%s\n", buf_ptr(&diag));
1020979 exit(1);
1021980 }
1022
1023 codegen_add_time_event(g, "Done");
1024981}
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
13void codegen_link(CodeGen *g, const char *out_file);
14
15
16#endif
17
src/main.cpp+93-52
......@@ -8,9 +8,9 @@
88#include "ast_render.hpp"
99#include "buffer.hpp"
1010#include "codegen.hpp"
11#include "compiler.hpp"
1112#include "config.h"
1213#include "error.hpp"
13#include "link.hpp"
1414#include "os.hpp"
1515#include "target.hpp"
1616
......@@ -24,6 +24,7 @@ static int usage(const char *arg0) {
2424 " build-lib [source] create library from source or object files\n"
2525 " build-obj [source] create object from source or assembly\n"
2626 " builtin show the source code of that @import(\"builtin\")\n"
27 " id print the base64-encoded compiler id\n"
2728 " run [source] create executable and run immediately\n"
2829 " translate-c [source] convert c code to zig code\n"
2930 " targets list available compilation targets\n"
......@@ -33,9 +34,10 @@ static int usage(const char *arg0) {
3334 "Compile Options:\n"
3435 " --assembly [source] add assembly file to build\n"
3536 " --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"
3638 " --color [auto|off|on] enable or disable colored error messages\n"
3739 " --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"
3941 " --libc-include-dir [path] directory where libc stdlib.h resides\n"
4042 " --name [name] override output name\n"
4143 " --output [file] override destination path\n"
......@@ -256,6 +258,24 @@ static void add_package(CodeGen *g, CliPkg *cli_pkg, PackageTableEntry *pkg) {
256258 }
257259}
258260
261enum CacheOpt {
262 CacheOptAuto,
263 CacheOptOn,
264 CacheOptOff,
265};
266
267static 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
259279int main(int argc, char **argv) {
260280 if (argc == 2 && strcmp(argv[1], "BUILD_INFO") == 0) {
261281 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) {
270290 return 0;
271291 }
272292
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
273304 os_init();
274305
275306 char *arg0 = argv[0];
......@@ -289,6 +320,7 @@ int main(int argc, char **argv) {
289320 bool verbose_llvm_ir = false;
290321 bool verbose_cimport = false;
291322 ErrColor color = ErrColorAuto;
323 CacheOpt enable_cache = CacheOptAuto;
292324 const char *libc_lib_dir = nullptr;
293325 const char *libc_static_lib_dir = nullptr;
294326 const char *libc_include_dir = nullptr;
......@@ -325,8 +357,7 @@ int main(int argc, char **argv) {
325357 CliPkg *cur_pkg = allocate<CliPkg>(1);
326358 BuildMode build_mode = BuildModeDebug;
327359 ZigList<const char *> test_exec_args = {0};
328 int comptime_args_end = 0;
329 int runtime_args_start = argc;
360 int runtime_args_start = -1;
330361 bool no_rosegment_workaround = false;
331362
332363 if (argc >= 2 && strcmp(argv[1], "build") == 0) {
......@@ -370,8 +401,9 @@ int main(int argc, char **argv) {
370401 Buf *build_runner_path = buf_alloc();
371402 os_path_join(special_dir, buf_create_from_str("build_runner.zig"), build_runner_path);
372403
373
374404 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);
375407 codegen_set_out_name(g, buf_create_from_str("build"));
376408
377409 Buf *build_file_buf = buf_create_from_str(build_file);
......@@ -380,6 +412,7 @@ int main(int argc, char **argv) {
380412 Buf build_file_dirname = BUF_INIT;
381413 os_path_split(&build_file_abs, &build_file_dirname, &build_file_basename);
382414
415
383416 Buf full_cache_dir = BUF_INIT;
384417 if (cache_dir == nullptr) {
385418 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) {
388421 full_cache_dir = os_path_resolve(&cache_dir_buf, 1);
389422 }
390423
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
395424 args.items[1] = buf_ptr(&build_file_dirname);
396425 args.items[2] = buf_ptr(&full_cache_dir);
397426
......@@ -459,15 +488,14 @@ int main(int argc, char **argv) {
459488 PackageTableEntry *build_pkg = codegen_create_package(g, buf_ptr(&build_file_dirname),
460489 buf_ptr(&build_file_basename));
461490 g->root_package->package_table.put(buf_create_from_str("@build"), build_pkg);
462 codegen_build(g);
463 codegen_link(g, buf_ptr(path_to_build_exe));
464 codegen_destroy(g);
491 g->enable_cache = get_cache_opt(enable_cache, true);
492 codegen_build_and_link(g);
465493
466494 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);
468496 if (term.how != TerminationIdClean || term.code != 0) {
469497 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));
471499 for (size_t i = 0; i < args.length; i += 1) {
472500 fprintf(stderr, " %s", args.at(i));
473501 }
......@@ -476,15 +504,11 @@ int main(int argc, char **argv) {
476504 return (term.how == TerminationIdClean) ? term.code : -1;
477505 }
478506
479 for (int i = 1; i < argc; i += 1, comptime_args_end += 1) {
507 for (int i = 1; i < argc; i += 1) {
480508 char *arg = argv[i];
481509
482510 if (arg[0] == '-') {
483 if (strcmp(arg, "--") == 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) {
511 if (strcmp(arg, "--release-fast") == 0) {
488512 build_mode = BuildModeFastRelease;
489513 } else if (strcmp(arg, "--release-safe") == 0) {
490514 build_mode = BuildModeSafeRelease;
......@@ -516,7 +540,7 @@ int main(int argc, char **argv) {
516540 no_rosegment_workaround = true;
517541 } else if (strcmp(arg, "--each-lib-rpath") == 0) {
518542 each_lib_rpath = true;
519 } else if (strcmp(arg, "--enable-timing-info") == 0) {
543 } else if (strcmp(arg, "-ftime-report") == 0) {
520544 timing_info = true;
521545 } else if (strcmp(arg, "--test-cmd-bin") == 0) {
522546 test_exec_args.append(nullptr);
......@@ -562,6 +586,17 @@ int main(int argc, char **argv) {
562586 fprintf(stderr, "--color options are 'auto', 'on', or 'off'\n");
563587 return usage(arg0);
564588 }
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 }
565600 } else if (strcmp(arg, "--emit") == 0) {
566601 if (strcmp(argv[i], "asm") == 0) {
567602 emit_file_type = EmitFileTypeAssembly;
......@@ -681,6 +716,10 @@ int main(int argc, char **argv) {
681716 case CmdTest:
682717 if (!in_file) {
683718 in_file = arg;
719 if (cmd == CmdRun) {
720 runtime_args_start = i + 1;
721 break; // rest of the args are for the program
722 }
684723 } else {
685724 fprintf(stderr, "Unexpected extra parameter: %s\n", arg);
686725 return usage(arg0);
......@@ -790,32 +829,18 @@ int main(int argc, char **argv) {
790829
791830 Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf;
792831
793 Buf full_cache_dir = BUF_INIT;
794 Buf *run_exec_path = buf_alloc();
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);
832 if (cmd == CmdRun && buf_out_name == nullptr) {
833 buf_out_name = buf_create_from_str("run");
809834 }
810
811835 Buf *zig_lib_dir_buf = resolve_zig_lib_dir();
812836
813837 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);
814840 codegen_set_out_name(g, buf_out_name);
815841 codegen_set_lib_version(g, ver_major, ver_minor, ver_patch);
816842 codegen_set_is_test(g, cmd == CmdTest);
817843 codegen_set_linker_script(g, linker_script);
818 codegen_set_cache_dir(g, full_cache_dir);
819844 if (each_lib_rpath)
820845 codegen_set_each_lib_rpath(g, each_lib_rpath);
821846
......@@ -885,6 +910,8 @@ int main(int argc, char **argv) {
885910 codegen_set_test_name_prefix(g, buf_create_from_str(test_name_prefix));
886911 }
887912
913 if (out_file)
914 codegen_set_output_path(g, buf_create_from_str(out_file));
888915 if (out_file_h)
889916 codegen_set_output_h_path(g, buf_create_from_str(out_file_h));
890917
......@@ -904,8 +931,8 @@ int main(int argc, char **argv) {
904931 if (cmd == CmdBuild || cmd == CmdRun) {
905932 codegen_set_emit_file_type(g, emit_file_type);
906933
907 codegen_build(g);
908 codegen_link(g, out_file);
934 g->enable_cache = get_cache_opt(enable_cache, cmd == CmdRun);
935 codegen_build_and_link(g);
909936 if (timing_info)
910937 codegen_print_timing_report(g, stdout);
911938
......@@ -915,12 +942,26 @@ int main(int argc, char **argv) {
915942 args.append(argv[i]);
916943 }
917944
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();
918951 Termination term;
919 os_spawn_process(buf_ptr(run_exec_path), args, &term);
952 os_spawn_process(exec_path, args, &term);
920953 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();
921964 }
922
923 return EXIT_SUCCESS;
924965 } else if (cmd == CmdTranslateC) {
925966 codegen_translate_c(g, in_file_buf);
926967 ast_render(g, stdout, g->root_import->root, 4);
......@@ -933,11 +974,16 @@ int main(int argc, char **argv) {
933974 ZigTarget native;
934975 get_native_target(&native);
935976
936 ZigTarget *non_null_target = target ? target : &native;
977 g->enable_cache = get_cache_opt(enable_cache, false);
978 codegen_build_and_link(g);
937979
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;
939985 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);
941987
942988 for (size_t i = 0; i < test_exec_args.length; i += 1) {
943989 if (test_exec_args.items[i] == nullptr) {
......@@ -945,9 +991,6 @@ int main(int argc, char **argv) {
945991 }
946992 }
947993
948 codegen_build(g);
949 codegen_link(g, buf_ptr(test_exe_path));
950
951994 if (!target_can_exec(&native, target)) {
952995 fprintf(stderr, "Created %s but skipping execution because it is non-native.\n",
953996 buf_ptr(test_exe_path));
......@@ -969,8 +1012,6 @@ int main(int argc, char **argv) {
9691012 if (term.how != TerminationIdClean || term.code != 0) {
9701013 fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n");
9711014 fprintf(stderr, "%s\n", buf_ptr(test_exe_path));
972 } else if (timing_info) {
973 codegen_print_timing_report(g, stdout);
9741015 }
9751016 return (term.how == TerminationIdClean) ? term.code : -1;
9761017 } else {
src/os.cpp+479-120
......@@ -24,6 +24,7 @@
2424#endif
2525
2626#include <windows.h>
27#include <shlobj.h>
2728#include <io.h>
2829#include <fcntl.h>
2930
......@@ -40,6 +41,10 @@ typedef SSIZE_T ssize_t;
4041
4142#endif
4243
44#if defined(ZIG_OS_LINUX)
45#include <link.h>
46#endif
47
4348
4449#if defined(__MACH__)
4550#include <mach/clock.h>
......@@ -57,54 +62,6 @@ static clock_serv_t cclock;
5762#include <errno.h>
5863#include <time.h>
5964
60// Ported from std/mem.zig.
61// Coordinate struct fields with memSplit function
62struct SplitIterator {
63 size_t index;
64 Slice<uint8_t> buffer;
65 Slice<uint8_t> split_bytes;
66};
67
68// Ported from std/mem.zig.
69static 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.
79static 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
103static SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes) {
104 return SplitIterator{0, buffer, split_bytes};
105}
106
107
10865#if defined(ZIG_OS_POSIX)
10966static void populate_termination(Termination *term, int status) {
11067 if (WIFEXITED(status)) {
......@@ -765,7 +722,7 @@ Buf os_path_resolve(Buf **paths_ptr, size_t paths_len) {
765722#endif
766723}
767724
768int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) {
725Error os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) {
769726 static const ssize_t buf_size = 0x2000;
770727 buf_resize(out_buf, buf_size);
771728 ssize_t actual_buf_len = 0;
......@@ -801,7 +758,7 @@ int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) {
801758 if (amt_read != buf_size) {
802759 if (feof(f)) {
803760 buf_resize(out_buf, actual_buf_len);
804 return 0;
761 return ErrorNone;
805762 } else {
806763 return ErrorFileSystem;
807764 }
......@@ -813,13 +770,13 @@ int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) {
813770 zig_unreachable();
814771}
815772
816int os_file_exists(Buf *full_path, bool *result) {
773Error os_file_exists(Buf *full_path, bool *result) {
817774#if defined(ZIG_OS_WINDOWS)
818775 *result = GetFileAttributes(buf_ptr(full_path)) != INVALID_FILE_ATTRIBUTES;
819 return 0;
776 return ErrorNone;
820777#else
821778 *result = access(buf_ptr(full_path), F_OK) != -1;
822 return 0;
779 return ErrorNone;
823780#endif
824781}
825782
......@@ -878,13 +835,15 @@ static int os_exec_process_posix(const char *exe, ZigList<const char *> &args,
878835
879836 FILE *stdout_f = fdopen(stdout_pipe[0], "rb");
880837 FILE *stderr_f = fdopen(stderr_pipe[0], "rb");
881 os_fetch_file(stdout_f, out_stdout, false);
882 os_fetch_file(stderr_f, out_stderr, false);
838 Error err1 = os_fetch_file(stdout_f, out_stdout, false);
839 Error err2 = os_fetch_file(stderr_f, out_stderr, false);
883840
884841 fclose(stdout_f);
885842 fclose(stderr_f);
886843
887 return 0;
844 if (err1) return err1;
845 if (err2) return err2;
846 return ErrorNone;
888847 }
889848}
890849#endif
......@@ -1016,6 +975,22 @@ static int os_exec_process_windows(const char *exe, ZigList<const char *> &args,
1016975}
1017976#endif
1018977
978Error 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
1019994int os_exec_process(const char *exe, ZigList<const char *> &args,
1020995 Termination *term, Buf *out_stderr, Buf *out_stdout)
1021996{
......@@ -1092,7 +1067,7 @@ int os_copy_file(Buf *src_path, Buf *dest_path) {
10921067 }
10931068}
10941069
1095int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) {
1070Error os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) {
10961071 FILE *f = fopen(buf_ptr(full_path), "rb");
10971072 if (!f) {
10981073 switch (errno) {
......@@ -1111,7 +1086,7 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) {
11111086 return ErrorFileSystem;
11121087 }
11131088 }
1114 int result = os_fetch_file(f, out_contents, skip_shebang);
1089 Error result = os_fetch_file(f, out_contents, skip_shebang);
11151090 fclose(f);
11161091 return result;
11171092}
......@@ -1282,44 +1257,6 @@ int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path) {
12821257#endif
12831258}
12841259
1285#if defined(ZIG_OS_POSIX)
1286int 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)
1305int 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
13231260int os_delete_file(Buf *path) {
13241261 if (remove(buf_ptr(path))) {
13251262 return ErrorFileSystem;
......@@ -1368,16 +1305,16 @@ double os_get_time(void) {
13681305#endif
13691306}
13701307
1371int os_make_path(Buf *path) {
1308Error os_make_path(Buf *path) {
13721309 Buf resolved_path = os_path_resolve(&path, 1);
13731310
13741311 size_t end_index = buf_len(&resolved_path);
1375 int err;
1312 Error err;
13761313 while (true) {
13771314 if ((err = os_make_dir(buf_slice(&resolved_path, 0, end_index)))) {
13781315 if (err == ErrorPathAlreadyExists) {
13791316 if (end_index == buf_len(&resolved_path))
1380 return 0;
1317 return ErrorNone;
13811318 } else if (err == ErrorFileNotFound) {
13821319 // march end_index backward until next path component
13831320 while (true) {
......@@ -1391,7 +1328,7 @@ int os_make_path(Buf *path) {
13911328 }
13921329 }
13931330 if (end_index == buf_len(&resolved_path))
1394 return 0;
1331 return ErrorNone;
13951332 // march end_index forward until next path component
13961333 while (true) {
13971334 end_index += 1;
......@@ -1399,10 +1336,10 @@ int os_make_path(Buf *path) {
13991336 break;
14001337 }
14011338 }
1402 return 0;
1339 return ErrorNone;
14031340}
14041341
1405int os_make_dir(Buf *path) {
1342Error os_make_dir(Buf *path) {
14061343#if defined(ZIG_OS_WINDOWS)
14071344 if (!CreateDirectory(buf_ptr(path), NULL)) {
14081345 if (GetLastError() == ERROR_ALREADY_EXISTS)
......@@ -1413,7 +1350,7 @@ int os_make_dir(Buf *path) {
14131350 return ErrorAccess;
14141351 return ErrorUnexpected;
14151352 }
1416 return 0;
1353 return ErrorNone;
14171354#else
14181355 if (mkdir(buf_ptr(path), 0755) == -1) {
14191356 if (errno == EEXIST)
......@@ -1424,7 +1361,7 @@ int os_make_dir(Buf *path) {
14241361 return ErrorAccess;
14251362 return ErrorUnexpected;
14261363 }
1427 return 0;
1364 return ErrorNone;
14281365#endif
14291366}
14301367
......@@ -1447,7 +1384,7 @@ int os_init(void) {
14471384 return 0;
14481385}
14491386
1450int os_self_exe_path(Buf *out_path) {
1387Error os_self_exe_path(Buf *out_path) {
14511388#if defined(ZIG_OS_WINDOWS)
14521389 buf_resize(out_path, 256);
14531390 for (;;) {
......@@ -1457,7 +1394,7 @@ int os_self_exe_path(Buf *out_path) {
14571394 }
14581395 if (copied_amt < buf_len(out_path)) {
14591396 buf_resize(out_path, copied_amt);
1460 return 0;
1397 return ErrorNone;
14611398 }
14621399 buf_resize(out_path, buf_len(out_path) * 2);
14631400 }
......@@ -1480,27 +1417,21 @@ int os_self_exe_path(Buf *out_path) {
14801417 char *real_path = realpath(buf_ptr(tmp), buf_ptr(out_path));
14811418 if (!real_path) {
14821419 buf_init_from_buf(out_path, tmp);
1483 return 0;
1420 return ErrorNone;
14841421 }
14851422
14861423 // Resize out_path for the correct length.
14871424 buf_resize(out_path, strlen(buf_ptr(out_path)));
14881425
1489 return 0;
1426 return ErrorNone;
14901427#elif defined(ZIG_OS_LINUX)
1491 buf_resize(out_path, 256);
1492 for (;;) {
1493 ssize_t amt = readlink("/proc/self/exe", buf_ptr(out_path), buf_len(out_path));
1494 if (amt == -1) {
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;
1428 buf_resize(out_path, PATH_MAX);
1429 ssize_t amt = readlink("/proc/self/exe", buf_ptr(out_path), buf_len(out_path));
1430 if (amt == -1) {
1431 return ErrorUnexpected;
15031432 }
1433 buf_resize(out_path, amt);
1434 return ErrorNone;
15041435#endif
15051436 return ErrorFileNotFound;
15061437}
......@@ -1685,3 +1616,431 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchTy
16851616 return ErrorFileNotFound;
16861617#endif
16871618}
1619
1620#if defined(ZIG_OS_WINDOWS)
1621// Ported from std/unicode.zig
1622struct Utf16LeIterator {
1623 uint8_t *bytes;
1624 size_t i;
1625};
1626
1627// Ported from std/unicode.zig
1628static Utf16LeIterator Utf16LeIterator_init(WCHAR *ptr) {
1629 return {(uint8_t*)ptr, 0};
1630}
1631
1632// Ported from std/unicode.zig
1633static 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
1653static 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
1662static 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
1696static 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
1715Error 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)
1755static 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
1764Error 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
1786Error 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
1842Error 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
1926Error 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
1955Error 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
1985Error 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
2008Error 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
2040void 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 @@
1313#include "error.hpp"
1414#include "zig_llvm.h"
1515#include "windows_sdk.h"
16#include "result.hpp"
1617
1718#include <stdio.h>
1819#include <inttypes.h>
1920
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
2053enum TermColor {
2154 TermColorRed,
2255 TermColorGreen,
......@@ -38,11 +71,23 @@ struct Termination {
3871 int code;
3972};
4073
74#if defined(ZIG_OS_WINDOWS)
75#define OsFile void *
76#else
77#define OsFile int
78#endif
79
80struct OsTimeStamp {
81 uint64_t sec;
82 uint64_t nsec;
83};
84
4185int os_init(void);
4286
4387void os_spawn_process(const char *exe, ZigList<const char *> &args, Termination *term);
4488int os_exec_process(const char *exe, ZigList<const char *> &args,
4589 Termination *term, Buf *out_stderr, Buf *out_stdout);
90Error os_execv(const char *exe, const char **argv);
4691
4792void os_path_dirname(Buf *full_path, Buf *out_dirname);
4893void 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);
5297Buf os_path_resolve(Buf **paths_ptr, size_t paths_len);
5398bool os_path_is_absolute(Buf *path);
5499
55int os_get_global_cache_directory(Buf *out_tmp_path);
100Error ATTRIBUTE_MUST_USE os_make_path(Buf *path);
101Error ATTRIBUTE_MUST_USE os_make_dir(Buf *path);
56102
57int os_make_path(Buf *path);
58int os_make_dir(Buf *path);
103Error ATTRIBUTE_MUST_USE os_file_open_r(Buf *full_path, OsFile *out_file);
104Error ATTRIBUTE_MUST_USE os_file_open_lock_rw(Buf *full_path, OsFile *out_file);
105Error ATTRIBUTE_MUST_USE os_file_mtime(OsFile file, OsTimeStamp *mtime);
106Error ATTRIBUTE_MUST_USE os_file_read(OsFile file, void *ptr, size_t *len);
107Error ATTRIBUTE_MUST_USE os_file_read_all(OsFile file, Buf *contents);
108Error ATTRIBUTE_MUST_USE os_file_overwrite(OsFile file, Buf *contents);
109void os_file_close(OsFile file);
59110
60111void os_write_file(Buf *full_path, Buf *contents);
61112int os_copy_file(Buf *src_path, Buf *dest_path);
62113
63int os_fetch_file(FILE *file, Buf *out_contents, bool skip_shebang);
64int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang);
114Error ATTRIBUTE_MUST_USE os_fetch_file(FILE *file, Buf *out_contents, bool skip_shebang);
115Error ATTRIBUTE_MUST_USE os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang);
65116
66117int os_get_cwd(Buf *out_cwd);
67118
......@@ -71,49 +122,21 @@ void os_stderr_set_color(TermColor color);
71122int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path);
72123int os_delete_file(Buf *path);
73124
74int os_file_exists(Buf *full_path, bool *result);
125Error ATTRIBUTE_MUST_USE os_file_exists(Buf *full_path, bool *result);
75126
76127int os_rename(Buf *src_path, Buf *dest_path);
77128double os_get_time(void);
78129
79130bool os_is_sep(uint8_t c);
80131
81int os_self_exe_path(Buf *out_path);
132Error ATTRIBUTE_MUST_USE os_self_exe_path(Buf *out_path);
133
134Error ATTRIBUTE_MUST_USE os_get_app_data_dir(Buf *out_path, const char *appname);
82135
83136int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf *output_buf);
84137int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
85138int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
86139
87#if defined(__APPLE__)
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
140Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths);
118141
119142#endif
src/target.cpp+16
......@@ -813,6 +813,22 @@ const char *target_exe_file_ext(ZigTarget *target) {
813813 }
814814}
815815
816const 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
816832enum FloatAbi {
817833 FloatAbiHard,
818834 FloatAbiSoft,
src/target.hpp+1
......@@ -113,6 +113,7 @@ const char *target_o_file_ext(ZigTarget *target);
113113const char *target_asm_file_ext(ZigTarget *target);
114114const char *target_llvm_ir_file_ext(ZigTarget *target);
115115const char *target_exe_file_ext(ZigTarget *target);
116const char *target_lib_file_ext(ZigTarget *target, bool is_static, size_t version_major, size_t version_minor, size_t version_patch);
116117
117118Buf *target_dynamic_linker(ZigTarget *target);
118119
src/util.cpp+39
......@@ -43,3 +43,42 @@ uint32_t ptr_hash(const void *ptr) {
4343bool ptr_eq(const void *a, const void *b) {
4444 return a == b;
4545}
46
47// Ported from std/mem.zig.
48bool 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.
58Optional<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
82SplitIterator 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) {
254254 memcpy(dest.ptr, src.ptr, src.len * sizeof(T));
255255}
256256
257// Ported from std/mem.zig.
258// Coordinate struct fields with memSplit function
259struct SplitIterator {
260 size_t index;
261 Slice<uint8_t> buffer;
262 Slice<uint8_t> split_bytes;
263};
264
265bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte);
266Optional<Slice<uint8_t>> SplitIterator_next(SplitIterator *self);
267SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes);
268
257269#endif
src/zig_llvm.cpp+8-1
......@@ -30,6 +30,7 @@
3030#include <llvm/PassRegistry.h>
3131#include <llvm/Support/FileSystem.h>
3232#include <llvm/Support/TargetParser.h>
33#include <llvm/Support/Timer.h>
3334#include <llvm/Support/raw_ostream.h>
3435#include <llvm/Target/TargetMachine.h>
3536#include <llvm/Transforms/Coroutines.h>
......@@ -81,8 +82,11 @@ static const bool assertions_on = false;
8182#endif
8283
8384bool 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)
8587{
88 TimePassesIsEnabled = time_report;
89
8690 std::error_code EC;
8791 raw_fd_ostream dest(filename, EC, sys::fs::F_None);
8892 if (EC) {
......@@ -182,6 +186,9 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
182186 }
183187 }
184188
189 if (time_report) {
190 TimerGroup::printAll(errs());
191 }
185192 return false;
186193}
187194
src/zig_llvm.h+2-1
......@@ -55,7 +55,8 @@ enum ZigLLVM_EmitOutputType {
5555};
5656
5757ZIG_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);
5960
6061ZIG_EXTERN_C LLVMTypeRef ZigLLVMTokenTypeInContext(LLVMContextRef context_ref);
6162
std/build.zig+26
......@@ -232,6 +232,8 @@ pub const Builder = struct {
232232 }
233233
234234 pub fn make(self: *Builder, step_names: []const []const u8) !void {
235 try self.makePath(self.cache_root);
236
235237 var wanted_steps = ArrayList(*Step).init(self.allocator);
236238 defer wanted_steps.deinit();
237239
......@@ -1641,6 +1643,7 @@ pub const TestStep = struct {
16411643 lib_paths: ArrayList([]const u8),
16421644 object_files: ArrayList([]const u8),
16431645 no_rosegment: bool,
1646 output_path: ?[]const u8,
16441647
16451648 pub fn init(builder: *Builder, root_src: []const u8) TestStep {
16461649 const step_name = builder.fmt("test {}", root_src);
......@@ -1659,6 +1662,7 @@ pub const TestStep = struct {
16591662 .lib_paths = ArrayList([]const u8).init(builder.allocator),
16601663 .object_files = ArrayList([]const u8).init(builder.allocator),
16611664 .no_rosegment = false,
1665 .output_path = null,
16621666 };
16631667 }
16641668
......@@ -1682,6 +1686,24 @@ pub const TestStep = struct {
16821686 self.build_mode = mode;
16831687 }
16841688
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
16851707 pub fn linkSystemLibrary(self: *TestStep, name: []const u8) void {
16861708 self.link_libs.put(name) catch unreachable;
16871709 }
......@@ -1746,6 +1768,10 @@ pub const TestStep = struct {
17461768 builtin.Mode.ReleaseSmall => try zig_args.append("--release-small"),
17471769 }
17481770
1771 const output_path = builder.pathFromRoot(self.getOutputPath());
1772 try zig_args.append("--output");
1773 try zig_args.append(output_path);
1774
17491775 switch (self.target) {
17501776 Target.Native => {},
17511777 Target.Cross => |cross_target| {