commit
0cfd019377
|
@ -390,7 +390,7 @@ if(MSVC)
|
|||
)
|
||||
else()
|
||||
set_target_properties(embedded_softfloat PROPERTIES
|
||||
COMPILE_FLAGS "-std=c99"
|
||||
COMPILE_FLAGS "-std=c99 -O3"
|
||||
)
|
||||
endif()
|
||||
target_include_directories(embedded_softfloat PUBLIC
|
||||
|
@ -409,7 +409,9 @@ set(ZIG_SOURCES
|
|||
"${CMAKE_SOURCE_DIR}/src/bigint.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/buffer.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/c_tokenizer.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/cache_hash.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/codegen.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/compiler.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/errmsg.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/error.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/ir.cpp"
|
||||
|
@ -424,6 +426,9 @@ set(ZIG_SOURCES
|
|||
"${CMAKE_SOURCE_DIR}/src/util.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/translate_c.cpp"
|
||||
)
|
||||
set(BLAKE_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/src/blake2b.c"
|
||||
)
|
||||
set(ZIG_CPP_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp"
|
||||
|
@ -790,6 +795,7 @@ else()
|
|||
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")
|
||||
endif()
|
||||
|
||||
set(BLAKE_CFLAGS "-std=c99")
|
||||
|
||||
set(EXE_LDFLAGS " ")
|
||||
if(MINGW)
|
||||
|
@ -811,6 +817,11 @@ set_target_properties(zig_cpp PROPERTIES
|
|||
COMPILE_FLAGS ${EXE_CFLAGS}
|
||||
)
|
||||
|
||||
add_library(embedded_blake STATIC ${BLAKE_SOURCES})
|
||||
set_target_properties(embedded_blake PROPERTIES
|
||||
COMPILE_FLAGS "${BLAKE_CFLAGS} -O3"
|
||||
)
|
||||
|
||||
add_executable(zig ${ZIG_SOURCES})
|
||||
set_target_properties(zig PROPERTIES
|
||||
COMPILE_FLAGS ${EXE_CFLAGS}
|
||||
|
@ -819,6 +830,7 @@ set_target_properties(zig PROPERTIES
|
|||
|
||||
target_link_libraries(zig LINK_PUBLIC
|
||||
zig_cpp
|
||||
embedded_blake
|
||||
${SOFTFLOAT_LIBRARIES}
|
||||
${CLANG_LIBRARIES}
|
||||
${LLD_LIBRARIES}
|
||||
|
|
|
@ -16,11 +16,12 @@ pub fn build(b: *Builder) !void {
|
|||
var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
|
||||
|
||||
const rel_zig_exe = try os.path.relative(b.allocator, b.build_root, b.zig_exe);
|
||||
const langref_out_path = os.path.join(b.allocator, b.cache_root, "langref.html") catch unreachable;
|
||||
var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8{
|
||||
docgen_exe.getOutputPath(),
|
||||
rel_zig_exe,
|
||||
"doc" ++ os.path.sep_str ++ "langref.html.in",
|
||||
os.path.join(b.allocator, b.cache_root, "langref.html") catch unreachable,
|
||||
langref_out_path,
|
||||
});
|
||||
docgen_cmd.step.dependOn(&docgen_exe.step);
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ const max_doc_file_size = 10 * 1024 * 1024;
|
|||
const exe_ext = std.build.Target(std.build.Target.Native).exeFileExt();
|
||||
const obj_ext = std.build.Target(std.build.Target.Native).oFileExt();
|
||||
const tmp_dir_name = "docgen_tmp";
|
||||
const test_out_path = tmp_dir_name ++ os.path.sep_str ++ "test" ++ exe_ext;
|
||||
|
||||
pub fn main() !void {
|
||||
var direct_allocator = std.heap.DirectAllocator.init();
|
||||
|
@ -821,6 +822,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
|||
zig_exe,
|
||||
"test",
|
||||
tmp_source_file_name,
|
||||
"--output",
|
||||
test_out_path,
|
||||
});
|
||||
try out.print("<pre><code class=\"shell\">$ zig test {}.zig", code.name);
|
||||
switch (code.mode) {
|
||||
|
@ -863,6 +866,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
|||
"--color",
|
||||
"on",
|
||||
tmp_source_file_name,
|
||||
"--output",
|
||||
test_out_path,
|
||||
});
|
||||
try out.print("<pre><code class=\"shell\">$ zig test {}.zig", code.name);
|
||||
switch (code.mode) {
|
||||
|
@ -918,6 +923,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
|||
zig_exe,
|
||||
"test",
|
||||
tmp_source_file_name,
|
||||
"--output",
|
||||
test_out_path,
|
||||
});
|
||||
switch (code.mode) {
|
||||
builtin.Mode.Debug => {},
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "list.hpp"
|
||||
#include "buffer.hpp"
|
||||
#include "cache_hash.hpp"
|
||||
#include "zig_llvm.h"
|
||||
#include "hash_map.hpp"
|
||||
#include "errmsg.hpp"
|
||||
|
@ -1550,22 +1551,50 @@ struct LinkLib {
|
|||
bool provided_explicitly;
|
||||
};
|
||||
|
||||
// When adding fields, check if they should be added to the hash computation in build_with_cache
|
||||
struct CodeGen {
|
||||
//////////////////////////// Runtime State
|
||||
LLVMModuleRef module;
|
||||
ZigList<ErrorMsg*> errors;
|
||||
LLVMBuilderRef builder;
|
||||
ZigLLVMDIBuilder *dbuilder;
|
||||
ZigLLVMDICompileUnit *compile_unit;
|
||||
ZigLLVMDIFile *compile_unit_file;
|
||||
|
||||
ZigList<LinkLib *> link_libs_list;
|
||||
LinkLib *libc_link_lib;
|
||||
|
||||
// add -framework [name] args to linker
|
||||
ZigList<Buf *> darwin_frameworks;
|
||||
// add -rpath [name] args to linker
|
||||
ZigList<Buf *> rpath_list;
|
||||
|
||||
LLVMTargetDataRef target_data_ref;
|
||||
LLVMTargetMachineRef target_machine;
|
||||
ZigLLVMDIFile *dummy_di_file;
|
||||
LLVMValueRef cur_ret_ptr;
|
||||
LLVMValueRef cur_fn_val;
|
||||
LLVMValueRef cur_err_ret_trace_val_arg;
|
||||
LLVMValueRef cur_err_ret_trace_val_stack;
|
||||
LLVMValueRef memcpy_fn_val;
|
||||
LLVMValueRef memset_fn_val;
|
||||
LLVMValueRef trap_fn_val;
|
||||
LLVMValueRef return_address_fn_val;
|
||||
LLVMValueRef frame_address_fn_val;
|
||||
LLVMValueRef coro_destroy_fn_val;
|
||||
LLVMValueRef coro_id_fn_val;
|
||||
LLVMValueRef coro_alloc_fn_val;
|
||||
LLVMValueRef coro_size_fn_val;
|
||||
LLVMValueRef coro_begin_fn_val;
|
||||
LLVMValueRef coro_suspend_fn_val;
|
||||
LLVMValueRef coro_end_fn_val;
|
||||
LLVMValueRef coro_free_fn_val;
|
||||
LLVMValueRef coro_resume_fn_val;
|
||||
LLVMValueRef coro_save_fn_val;
|
||||
LLVMValueRef coro_promise_fn_val;
|
||||
LLVMValueRef coro_alloc_helper_fn_val;
|
||||
LLVMValueRef coro_frame_fn_val;
|
||||
LLVMValueRef merge_err_ret_traces_fn_val;
|
||||
LLVMValueRef add_error_return_trace_addr_fn_val;
|
||||
LLVMValueRef stacksave_fn_val;
|
||||
LLVMValueRef stackrestore_fn_val;
|
||||
LLVMValueRef write_register_fn_val;
|
||||
LLVMValueRef sp_md_node;
|
||||
LLVMValueRef err_name_table;
|
||||
LLVMValueRef safety_crash_err_fn;
|
||||
LLVMValueRef return_err_fn;
|
||||
|
||||
// reminder: hash tables must be initialized before use
|
||||
HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table;
|
||||
|
@ -1582,15 +1611,29 @@ struct CodeGen {
|
|||
HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table;
|
||||
HashMap<const ZigType *, ConstExprValue *, type_ptr_hash, type_ptr_eql> type_info_cache;
|
||||
|
||||
|
||||
ZigList<ImportTableEntry *> import_queue;
|
||||
size_t import_queue_index;
|
||||
ZigList<Tld *> resolve_queue;
|
||||
size_t resolve_queue_index;
|
||||
ZigList<AstNode *> use_queue;
|
||||
size_t use_queue_index;
|
||||
ZigList<TimeEvent> timing_events;
|
||||
ZigList<ZigLLVMDIType **> error_di_types;
|
||||
ZigList<AstNode *> tld_ref_source_node_stack;
|
||||
ZigList<ZigFn *> inline_fns;
|
||||
ZigList<ZigFn *> test_fns;
|
||||
ZigList<ZigLLVMDIEnumerator *> err_enumerators;
|
||||
ZigList<ErrorTableEntry *> errors_by_index;
|
||||
size_t largest_err_name_len;
|
||||
|
||||
uint32_t next_unresolved_index;
|
||||
PackageTableEntry *std_package;
|
||||
PackageTableEntry *panic_package;
|
||||
PackageTableEntry *test_runner_package;
|
||||
PackageTableEntry *compile_var_package;
|
||||
ImportTableEntry *compile_var_import;
|
||||
ImportTableEntry *root_import;
|
||||
ImportTableEntry *bootstrap_import;
|
||||
ImportTableEntry *test_runner_import;
|
||||
|
||||
struct {
|
||||
ZigType *entry_bool;
|
||||
|
@ -1626,14 +1669,45 @@ struct CodeGen {
|
|||
ZigType *entry_arg_tuple;
|
||||
ZigType *entry_promise;
|
||||
} builtin_types;
|
||||
ZigType *align_amt_type;
|
||||
ZigType *stack_trace_type;
|
||||
ZigType *ptr_to_stack_trace_type;
|
||||
ZigType *err_tag_type;
|
||||
ZigType *test_fn_type;
|
||||
|
||||
EmitFileType emit_file_type;
|
||||
ZigTarget zig_target;
|
||||
LLVMTargetDataRef target_data_ref;
|
||||
Buf triple_str;
|
||||
Buf global_asm;
|
||||
Buf *out_h_path;
|
||||
Buf artifact_dir;
|
||||
Buf output_file_path;
|
||||
Buf o_file_output_path;
|
||||
Buf *wanted_output_file_path;
|
||||
Buf cache_dir;
|
||||
|
||||
IrInstruction *invalid_instruction;
|
||||
|
||||
ConstExprValue const_void_val;
|
||||
ConstExprValue panic_msg_vals[PanicMsgIdCount];
|
||||
|
||||
// The function definitions this module includes.
|
||||
ZigList<ZigFn *> fn_defs;
|
||||
size_t fn_defs_index;
|
||||
ZigList<TldVar *> global_vars;
|
||||
|
||||
ZigFn *cur_fn;
|
||||
ZigFn *main_fn;
|
||||
ZigFn *panic_fn;
|
||||
AstNode *root_export_decl;
|
||||
|
||||
CacheHash cache_hash;
|
||||
ErrColor err_color;
|
||||
uint32_t next_unresolved_index;
|
||||
unsigned pointer_size_bytes;
|
||||
uint32_t target_os_index;
|
||||
uint32_t target_arch_index;
|
||||
uint32_t target_environ_index;
|
||||
uint32_t target_oformat_index;
|
||||
bool is_big_endian;
|
||||
bool is_static;
|
||||
bool strip_debug_symbols;
|
||||
bool want_h_file;
|
||||
bool have_pub_main;
|
||||
bool have_c_main;
|
||||
|
@ -1641,6 +1715,65 @@ struct CodeGen {
|
|||
bool have_winmain_crt_startup;
|
||||
bool have_dllmain_crt_startup;
|
||||
bool have_pub_panic;
|
||||
bool have_err_ret_tracing;
|
||||
bool c_want_stdint;
|
||||
bool c_want_stdbool;
|
||||
bool verbose_tokenize;
|
||||
bool verbose_ast;
|
||||
bool verbose_link;
|
||||
bool verbose_ir;
|
||||
bool verbose_llvm_ir;
|
||||
bool verbose_cimport;
|
||||
bool error_during_imports;
|
||||
bool generate_error_name_table;
|
||||
bool enable_cache;
|
||||
bool enable_time_report;
|
||||
|
||||
//////////////////////////// Participates in Input Parameter Cache Hash
|
||||
ZigList<LinkLib *> link_libs_list;
|
||||
// add -framework [name] args to linker
|
||||
ZigList<Buf *> darwin_frameworks;
|
||||
// add -rpath [name] args to linker
|
||||
ZigList<Buf *> rpath_list;
|
||||
ZigList<Buf *> forbidden_libs;
|
||||
ZigList<Buf *> link_objects;
|
||||
ZigList<Buf *> assembly_files;
|
||||
ZigList<const char *> lib_dirs;
|
||||
|
||||
size_t version_major;
|
||||
size_t version_minor;
|
||||
size_t version_patch;
|
||||
const char *linker_script;
|
||||
|
||||
EmitFileType emit_file_type;
|
||||
BuildMode build_mode;
|
||||
OutType out_type;
|
||||
ZigTarget zig_target;
|
||||
bool is_static;
|
||||
bool strip_debug_symbols;
|
||||
bool is_test_build;
|
||||
bool is_native_target;
|
||||
bool windows_subsystem_windows;
|
||||
bool windows_subsystem_console;
|
||||
bool linker_rdynamic;
|
||||
bool no_rosegment_workaround;
|
||||
bool each_lib_rpath;
|
||||
|
||||
Buf *mmacosx_version_min;
|
||||
Buf *mios_version_min;
|
||||
Buf *root_out_name;
|
||||
Buf *test_filter;
|
||||
Buf *test_name_prefix;
|
||||
PackageTableEntry *root_package;
|
||||
|
||||
const char **llvm_argv;
|
||||
size_t llvm_argv_len;
|
||||
|
||||
const char **clang_argv;
|
||||
size_t clang_argv_len;
|
||||
|
||||
//////////////////////////// Unsorted
|
||||
|
||||
Buf *libc_lib_dir;
|
||||
Buf *libc_static_lib_dir;
|
||||
Buf *libc_include_dir;
|
||||
|
@ -1651,140 +1784,7 @@ struct CodeGen {
|
|||
Buf *zig_c_headers_dir;
|
||||
Buf *zig_std_special_dir;
|
||||
Buf *dynamic_linker;
|
||||
Buf *ar_path;
|
||||
ZigWindowsSDK *win_sdk;
|
||||
Buf triple_str;
|
||||
BuildMode build_mode;
|
||||
bool is_test_build;
|
||||
bool have_err_ret_tracing;
|
||||
uint32_t target_os_index;
|
||||
uint32_t target_arch_index;
|
||||
uint32_t target_environ_index;
|
||||
uint32_t target_oformat_index;
|
||||
LLVMTargetMachineRef target_machine;
|
||||
ZigLLVMDIFile *dummy_di_file;
|
||||
bool is_native_target;
|
||||
PackageTableEntry *root_package;
|
||||
PackageTableEntry *std_package;
|
||||
PackageTableEntry *panic_package;
|
||||
PackageTableEntry *test_runner_package;
|
||||
PackageTableEntry *compile_var_package;
|
||||
ImportTableEntry *compile_var_import;
|
||||
Buf *root_out_name;
|
||||
bool windows_subsystem_windows;
|
||||
bool windows_subsystem_console;
|
||||
Buf *mmacosx_version_min;
|
||||
Buf *mios_version_min;
|
||||
bool linker_rdynamic;
|
||||
const char *linker_script;
|
||||
|
||||
// The function definitions this module includes.
|
||||
ZigList<ZigFn *> fn_defs;
|
||||
size_t fn_defs_index;
|
||||
ZigList<TldVar *> global_vars;
|
||||
|
||||
OutType out_type;
|
||||
ZigFn *cur_fn;
|
||||
ZigFn *main_fn;
|
||||
ZigFn *panic_fn;
|
||||
LLVMValueRef cur_ret_ptr;
|
||||
LLVMValueRef cur_fn_val;
|
||||
LLVMValueRef cur_err_ret_trace_val_arg;
|
||||
LLVMValueRef cur_err_ret_trace_val_stack;
|
||||
bool c_want_stdint;
|
||||
bool c_want_stdbool;
|
||||
AstNode *root_export_decl;
|
||||
size_t version_major;
|
||||
size_t version_minor;
|
||||
size_t version_patch;
|
||||
bool verbose_tokenize;
|
||||
bool verbose_ast;
|
||||
bool verbose_link;
|
||||
bool verbose_ir;
|
||||
bool verbose_llvm_ir;
|
||||
bool verbose_cimport;
|
||||
ErrColor err_color;
|
||||
ImportTableEntry *root_import;
|
||||
ImportTableEntry *bootstrap_import;
|
||||
ImportTableEntry *test_runner_import;
|
||||
LLVMValueRef memcpy_fn_val;
|
||||
LLVMValueRef memset_fn_val;
|
||||
LLVMValueRef trap_fn_val;
|
||||
LLVMValueRef return_address_fn_val;
|
||||
LLVMValueRef frame_address_fn_val;
|
||||
LLVMValueRef coro_destroy_fn_val;
|
||||
LLVMValueRef coro_id_fn_val;
|
||||
LLVMValueRef coro_alloc_fn_val;
|
||||
LLVMValueRef coro_size_fn_val;
|
||||
LLVMValueRef coro_begin_fn_val;
|
||||
LLVMValueRef coro_suspend_fn_val;
|
||||
LLVMValueRef coro_end_fn_val;
|
||||
LLVMValueRef coro_free_fn_val;
|
||||
LLVMValueRef coro_resume_fn_val;
|
||||
LLVMValueRef coro_save_fn_val;
|
||||
LLVMValueRef coro_promise_fn_val;
|
||||
LLVMValueRef coro_alloc_helper_fn_val;
|
||||
LLVMValueRef coro_frame_fn_val;
|
||||
LLVMValueRef merge_err_ret_traces_fn_val;
|
||||
LLVMValueRef add_error_return_trace_addr_fn_val;
|
||||
LLVMValueRef stacksave_fn_val;
|
||||
LLVMValueRef stackrestore_fn_val;
|
||||
LLVMValueRef write_register_fn_val;
|
||||
bool error_during_imports;
|
||||
|
||||
LLVMValueRef sp_md_node;
|
||||
|
||||
const char **clang_argv;
|
||||
size_t clang_argv_len;
|
||||
ZigList<const char *> lib_dirs;
|
||||
|
||||
const char **llvm_argv;
|
||||
size_t llvm_argv_len;
|
||||
|
||||
ZigList<ZigFn *> test_fns;
|
||||
ZigType *test_fn_type;
|
||||
|
||||
bool each_lib_rpath;
|
||||
|
||||
ZigType *err_tag_type;
|
||||
ZigList<ZigLLVMDIEnumerator *> err_enumerators;
|
||||
ZigList<ErrorTableEntry *> errors_by_index;
|
||||
bool generate_error_name_table;
|
||||
LLVMValueRef err_name_table;
|
||||
size_t largest_err_name_len;
|
||||
LLVMValueRef safety_crash_err_fn;
|
||||
|
||||
LLVMValueRef return_err_fn;
|
||||
|
||||
IrInstruction *invalid_instruction;
|
||||
ConstExprValue const_void_val;
|
||||
|
||||
ConstExprValue panic_msg_vals[PanicMsgIdCount];
|
||||
|
||||
Buf global_asm;
|
||||
ZigList<Buf *> link_objects;
|
||||
ZigList<Buf *> assembly_files;
|
||||
|
||||
Buf *test_filter;
|
||||
Buf *test_name_prefix;
|
||||
|
||||
ZigList<TimeEvent> timing_events;
|
||||
|
||||
Buf cache_dir;
|
||||
Buf *out_h_path;
|
||||
|
||||
ZigList<ZigFn *> inline_fns;
|
||||
ZigList<AstNode *> tld_ref_source_node_stack;
|
||||
|
||||
ZigType *align_amt_type;
|
||||
ZigType *stack_trace_type;
|
||||
ZigType *ptr_to_stack_trace_type;
|
||||
|
||||
ZigList<ZigLLVMDIType **> error_di_types;
|
||||
|
||||
ZigList<Buf *> forbidden_libs;
|
||||
|
||||
bool no_rosegment_workaround;
|
||||
};
|
||||
|
||||
enum VarLinkage {
|
||||
|
|
|
@ -6289,6 +6289,12 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) {
|
|||
if (is_libc && g->libc_link_lib != nullptr)
|
||||
return g->libc_link_lib;
|
||||
|
||||
if (g->enable_cache && is_libc && g->zig_target.os != OsMacOSX && g->zig_target.os != OsIOS) {
|
||||
fprintf(stderr, "TODO linking against libc is currently incompatible with `--cache on`.\n"
|
||||
"Zig is not yet capable of determining whether the libc installation has changed on subsequent builds.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
|
||||
LinkLib *existing_lib = g->link_libs_list.at(i);
|
||||
if (buf_eql_buf(existing_lib->name, name)) {
|
||||
|
@ -6398,6 +6404,14 @@ not_integer:
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
Error file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents) {
|
||||
if (g->enable_cache) {
|
||||
return cache_add_file_fetch(&g->cache_hash, resolved_path, contents);
|
||||
} else {
|
||||
return os_fetch_file_path(resolved_path, contents, false);
|
||||
}
|
||||
}
|
||||
|
||||
X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) {
|
||||
size_t ty_size = type_size(g, ty);
|
||||
if (get_codegen_ptr_type(ty) != nullptr)
|
||||
|
@ -6478,4 +6492,3 @@ bool type_is_c_abi_int(CodeGen *g, ZigType *ty) {
|
|||
ty->id == ZigTypeIdUnreachable ||
|
||||
get_codegen_ptr_type(ty) != nullptr);
|
||||
}
|
||||
|
||||
|
|
|
@ -209,6 +209,8 @@ ZigType *get_primitive_type(CodeGen *g, Buf *name);
|
|||
bool calling_convention_allows_zig_types(CallingConvention cc);
|
||||
const char *calling_convention_name(CallingConvention cc);
|
||||
|
||||
Error ATTRIBUTE_MUST_USE file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents);
|
||||
|
||||
void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk);
|
||||
X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty);
|
||||
bool type_is_c_abi_int(CodeGen *g, ZigType *ty);
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
BLAKE2 reference source code package - reference C implementations
|
||||
|
||||
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
|
||||
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
|
||||
your option. The terms of these licenses can be found at:
|
||||
|
||||
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
- OpenSSL license : https://www.openssl.org/source/license.html
|
||||
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
More information about the BLAKE2 hash function can be found at
|
||||
https://blake2.net.
|
||||
*/
|
||||
#ifndef BLAKE2_H
|
||||
#define BLAKE2_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define BLAKE2_PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop))
|
||||
#else
|
||||
#define BLAKE2_PACKED(x) x __attribute__((packed))
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum blake2s_constant
|
||||
{
|
||||
BLAKE2S_BLOCKBYTES = 64,
|
||||
BLAKE2S_OUTBYTES = 32,
|
||||
BLAKE2S_KEYBYTES = 32,
|
||||
BLAKE2S_SALTBYTES = 8,
|
||||
BLAKE2S_PERSONALBYTES = 8
|
||||
};
|
||||
|
||||
enum blake2b_constant
|
||||
{
|
||||
BLAKE2B_BLOCKBYTES = 128,
|
||||
BLAKE2B_OUTBYTES = 64,
|
||||
BLAKE2B_KEYBYTES = 64,
|
||||
BLAKE2B_SALTBYTES = 16,
|
||||
BLAKE2B_PERSONALBYTES = 16
|
||||
};
|
||||
|
||||
typedef struct blake2s_state__
|
||||
{
|
||||
uint32_t h[8];
|
||||
uint32_t t[2];
|
||||
uint32_t f[2];
|
||||
uint8_t buf[BLAKE2S_BLOCKBYTES];
|
||||
size_t buflen;
|
||||
size_t outlen;
|
||||
uint8_t last_node;
|
||||
} blake2s_state;
|
||||
|
||||
typedef struct blake2b_state__
|
||||
{
|
||||
uint64_t h[8];
|
||||
uint64_t t[2];
|
||||
uint64_t f[2];
|
||||
uint8_t buf[BLAKE2B_BLOCKBYTES];
|
||||
size_t buflen;
|
||||
size_t outlen;
|
||||
uint8_t last_node;
|
||||
} blake2b_state;
|
||||
|
||||
typedef struct blake2sp_state__
|
||||
{
|
||||
blake2s_state S[8][1];
|
||||
blake2s_state R[1];
|
||||
uint8_t buf[8 * BLAKE2S_BLOCKBYTES];
|
||||
size_t buflen;
|
||||
size_t outlen;
|
||||
} blake2sp_state;
|
||||
|
||||
typedef struct blake2bp_state__
|
||||
{
|
||||
blake2b_state S[4][1];
|
||||
blake2b_state R[1];
|
||||
uint8_t buf[4 * BLAKE2B_BLOCKBYTES];
|
||||
size_t buflen;
|
||||
size_t outlen;
|
||||
} blake2bp_state;
|
||||
|
||||
|
||||
BLAKE2_PACKED(struct blake2s_param__
|
||||
{
|
||||
uint8_t digest_length; /* 1 */
|
||||
uint8_t key_length; /* 2 */
|
||||
uint8_t fanout; /* 3 */
|
||||
uint8_t depth; /* 4 */
|
||||
uint32_t leaf_length; /* 8 */
|
||||
uint32_t node_offset; /* 12 */
|
||||
uint16_t xof_length; /* 14 */
|
||||
uint8_t node_depth; /* 15 */
|
||||
uint8_t inner_length; /* 16 */
|
||||
/* uint8_t reserved[0]; */
|
||||
uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */
|
||||
uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */
|
||||
});
|
||||
|
||||
typedef struct blake2s_param__ blake2s_param;
|
||||
|
||||
BLAKE2_PACKED(struct blake2b_param__
|
||||
{
|
||||
uint8_t digest_length; /* 1 */
|
||||
uint8_t key_length; /* 2 */
|
||||
uint8_t fanout; /* 3 */
|
||||
uint8_t depth; /* 4 */
|
||||
uint32_t leaf_length; /* 8 */
|
||||
uint32_t node_offset; /* 12 */
|
||||
uint32_t xof_length; /* 16 */
|
||||
uint8_t node_depth; /* 17 */
|
||||
uint8_t inner_length; /* 18 */
|
||||
uint8_t reserved[14]; /* 32 */
|
||||
uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */
|
||||
uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */
|
||||
});
|
||||
|
||||
typedef struct blake2b_param__ blake2b_param;
|
||||
|
||||
typedef struct blake2xs_state__
|
||||
{
|
||||
blake2s_state S[1];
|
||||
blake2s_param P[1];
|
||||
} blake2xs_state;
|
||||
|
||||
typedef struct blake2xb_state__
|
||||
{
|
||||
blake2b_state S[1];
|
||||
blake2b_param P[1];
|
||||
} blake2xb_state;
|
||||
|
||||
/* Padded structs result in a compile-time error */
|
||||
enum {
|
||||
BLAKE2_DUMMY_1 = 1/(sizeof(blake2s_param) == BLAKE2S_OUTBYTES),
|
||||
BLAKE2_DUMMY_2 = 1/(sizeof(blake2b_param) == BLAKE2B_OUTBYTES)
|
||||
};
|
||||
|
||||
/* Streaming API */
|
||||
int blake2s_init( blake2s_state *S, size_t outlen );
|
||||
int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen );
|
||||
int blake2s_init_param( blake2s_state *S, const blake2s_param *P );
|
||||
int blake2s_update( blake2s_state *S, const void *in, size_t inlen );
|
||||
int blake2s_final( blake2s_state *S, void *out, size_t outlen );
|
||||
|
||||
int blake2b_init( blake2b_state *S, size_t outlen );
|
||||
int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen );
|
||||
int blake2b_init_param( blake2b_state *S, const blake2b_param *P );
|
||||
int blake2b_update( blake2b_state *S, const void *in, size_t inlen );
|
||||
int blake2b_final( blake2b_state *S, void *out, size_t outlen );
|
||||
|
||||
int blake2sp_init( blake2sp_state *S, size_t outlen );
|
||||
int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen );
|
||||
int blake2sp_update( blake2sp_state *S, const void *in, size_t inlen );
|
||||
int blake2sp_final( blake2sp_state *S, void *out, size_t outlen );
|
||||
|
||||
int blake2bp_init( blake2bp_state *S, size_t outlen );
|
||||
int blake2bp_init_key( blake2bp_state *S, size_t outlen, const void *key, size_t keylen );
|
||||
int blake2bp_update( blake2bp_state *S, const void *in, size_t inlen );
|
||||
int blake2bp_final( blake2bp_state *S, void *out, size_t outlen );
|
||||
|
||||
/* Variable output length API */
|
||||
int blake2xs_init( blake2xs_state *S, const size_t outlen );
|
||||
int blake2xs_init_key( blake2xs_state *S, const size_t outlen, const void *key, size_t keylen );
|
||||
int blake2xs_update( blake2xs_state *S, const void *in, size_t inlen );
|
||||
int blake2xs_final(blake2xs_state *S, void *out, size_t outlen);
|
||||
|
||||
int blake2xb_init( blake2xb_state *S, const size_t outlen );
|
||||
int blake2xb_init_key( blake2xb_state *S, const size_t outlen, const void *key, size_t keylen );
|
||||
int blake2xb_update( blake2xb_state *S, const void *in, size_t inlen );
|
||||
int blake2xb_final(blake2xb_state *S, void *out, size_t outlen);
|
||||
|
||||
/* Simple API */
|
||||
int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
|
||||
int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
|
||||
|
||||
int blake2sp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
|
||||
int blake2bp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
|
||||
|
||||
int blake2xs( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
|
||||
int blake2xb( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
|
||||
|
||||
/* This is simply an alias for blake2b */
|
||||
int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,539 @@
|
|||
/*
|
||||
BLAKE2 reference source code package - reference C implementations
|
||||
|
||||
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
|
||||
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
|
||||
your option. The terms of these licenses can be found at:
|
||||
|
||||
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
- OpenSSL license : https://www.openssl.org/source/license.html
|
||||
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
More information about the BLAKE2 hash function can be found at
|
||||
https://blake2.net.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "blake2.h"
|
||||
/*
|
||||
BLAKE2 reference source code package - reference C implementations
|
||||
|
||||
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
|
||||
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
|
||||
your option. The terms of these licenses can be found at:
|
||||
|
||||
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
- OpenSSL license : https://www.openssl.org/source/license.html
|
||||
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
More information about the BLAKE2 hash function can be found at
|
||||
https://blake2.net.
|
||||
*/
|
||||
#ifndef BLAKE2_IMPL_H
|
||||
#define BLAKE2_IMPL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L)
|
||||
#if defined(_MSC_VER)
|
||||
#define BLAKE2_INLINE __inline
|
||||
#elif defined(__GNUC__)
|
||||
#define BLAKE2_INLINE __inline__
|
||||
#else
|
||||
#define BLAKE2_INLINE
|
||||
#endif
|
||||
#else
|
||||
#define BLAKE2_INLINE inline
|
||||
#endif
|
||||
|
||||
static BLAKE2_INLINE uint32_t load32( const void *src )
|
||||
{
|
||||
#if defined(NATIVE_LITTLE_ENDIAN)
|
||||
uint32_t w;
|
||||
memcpy(&w, src, sizeof w);
|
||||
return w;
|
||||
#else
|
||||
const uint8_t *p = ( const uint8_t * )src;
|
||||
return (( uint32_t )( p[0] ) << 0) |
|
||||
(( uint32_t )( p[1] ) << 8) |
|
||||
(( uint32_t )( p[2] ) << 16) |
|
||||
(( uint32_t )( p[3] ) << 24) ;
|
||||
#endif
|
||||
}
|
||||
|
||||
static BLAKE2_INLINE uint64_t load64( const void *src )
|
||||
{
|
||||
#if defined(NATIVE_LITTLE_ENDIAN)
|
||||
uint64_t w;
|
||||
memcpy(&w, src, sizeof w);
|
||||
return w;
|
||||
#else
|
||||
const uint8_t *p = ( const uint8_t * )src;
|
||||
return (( uint64_t )( p[0] ) << 0) |
|
||||
(( uint64_t )( p[1] ) << 8) |
|
||||
(( uint64_t )( p[2] ) << 16) |
|
||||
(( uint64_t )( p[3] ) << 24) |
|
||||
(( uint64_t )( p[4] ) << 32) |
|
||||
(( uint64_t )( p[5] ) << 40) |
|
||||
(( uint64_t )( p[6] ) << 48) |
|
||||
(( uint64_t )( p[7] ) << 56) ;
|
||||
#endif
|
||||
}
|
||||
|
||||
static BLAKE2_INLINE uint16_t load16( const void *src )
|
||||
{
|
||||
#if defined(NATIVE_LITTLE_ENDIAN)
|
||||
uint16_t w;
|
||||
memcpy(&w, src, sizeof w);
|
||||
return w;
|
||||
#else
|
||||
const uint8_t *p = ( const uint8_t * )src;
|
||||
return ( uint16_t )((( uint32_t )( p[0] ) << 0) |
|
||||
(( uint32_t )( p[1] ) << 8));
|
||||
#endif
|
||||
}
|
||||
|
||||
static BLAKE2_INLINE void store16( void *dst, uint16_t w )
|
||||
{
|
||||
#if defined(NATIVE_LITTLE_ENDIAN)
|
||||
memcpy(dst, &w, sizeof w);
|
||||
#else
|
||||
uint8_t *p = ( uint8_t * )dst;
|
||||
*p++ = ( uint8_t )w; w >>= 8;
|
||||
*p++ = ( uint8_t )w;
|
||||
#endif
|
||||
}
|
||||
|
||||
static BLAKE2_INLINE void store32( void *dst, uint32_t w )
|
||||
{
|
||||
#if defined(NATIVE_LITTLE_ENDIAN)
|
||||
memcpy(dst, &w, sizeof w);
|
||||
#else
|
||||
uint8_t *p = ( uint8_t * )dst;
|
||||
p[0] = (uint8_t)(w >> 0);
|
||||
p[1] = (uint8_t)(w >> 8);
|
||||
p[2] = (uint8_t)(w >> 16);
|
||||
p[3] = (uint8_t)(w >> 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
static BLAKE2_INLINE void store64( void *dst, uint64_t w )
|
||||
{
|
||||
#if defined(NATIVE_LITTLE_ENDIAN)
|
||||
memcpy(dst, &w, sizeof w);
|
||||
#else
|
||||
uint8_t *p = ( uint8_t * )dst;
|
||||
p[0] = (uint8_t)(w >> 0);
|
||||
p[1] = (uint8_t)(w >> 8);
|
||||
p[2] = (uint8_t)(w >> 16);
|
||||
p[3] = (uint8_t)(w >> 24);
|
||||
p[4] = (uint8_t)(w >> 32);
|
||||
p[5] = (uint8_t)(w >> 40);
|
||||
p[6] = (uint8_t)(w >> 48);
|
||||
p[7] = (uint8_t)(w >> 56);
|
||||
#endif
|
||||
}
|
||||
|
||||
static BLAKE2_INLINE uint64_t load48( const void *src )
|
||||
{
|
||||
const uint8_t *p = ( const uint8_t * )src;
|
||||
return (( uint64_t )( p[0] ) << 0) |
|
||||
(( uint64_t )( p[1] ) << 8) |
|
||||
(( uint64_t )( p[2] ) << 16) |
|
||||
(( uint64_t )( p[3] ) << 24) |
|
||||
(( uint64_t )( p[4] ) << 32) |
|
||||
(( uint64_t )( p[5] ) << 40) ;
|
||||
}
|
||||
|
||||
static BLAKE2_INLINE void store48( void *dst, uint64_t w )
|
||||
{
|
||||
uint8_t *p = ( uint8_t * )dst;
|
||||
p[0] = (uint8_t)(w >> 0);
|
||||
p[1] = (uint8_t)(w >> 8);
|
||||
p[2] = (uint8_t)(w >> 16);
|
||||
p[3] = (uint8_t)(w >> 24);
|
||||
p[4] = (uint8_t)(w >> 32);
|
||||
p[5] = (uint8_t)(w >> 40);
|
||||
}
|
||||
|
||||
static BLAKE2_INLINE uint32_t rotr32( const uint32_t w, const unsigned c )
|
||||
{
|
||||
return ( w >> c ) | ( w << ( 32 - c ) );
|
||||
}
|
||||
|
||||
static BLAKE2_INLINE uint64_t rotr64( const uint64_t w, const unsigned c )
|
||||
{
|
||||
return ( w >> c ) | ( w << ( 64 - c ) );
|
||||
}
|
||||
|
||||
/* prevents compiler optimizing out memset() */
|
||||
static BLAKE2_INLINE void secure_zero_memory(void *v, size_t n)
|
||||
{
|
||||
static void *(*const volatile memset_v)(void *, int, size_t) = &memset;
|
||||
memset_v(v, 0, n);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static const uint64_t blake2b_IV[8] =
|
||||
{
|
||||
0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
|
||||
0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
|
||||
0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
|
||||
0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
|
||||
};
|
||||
|
||||
static const uint8_t blake2b_sigma[12][16] =
|
||||
{
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
|
||||
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
|
||||
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
|
||||
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
|
||||
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
|
||||
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
|
||||
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
|
||||
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
|
||||
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
|
||||
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
|
||||
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }
|
||||
};
|
||||
|
||||
|
||||
static void blake2b_set_lastnode( blake2b_state *S )
|
||||
{
|
||||
S->f[1] = (uint64_t)-1;
|
||||
}
|
||||
|
||||
/* Some helper functions, not necessarily useful */
|
||||
static int blake2b_is_lastblock( const blake2b_state *S )
|
||||
{
|
||||
return S->f[0] != 0;
|
||||
}
|
||||
|
||||
static void blake2b_set_lastblock( blake2b_state *S )
|
||||
{
|
||||
if( S->last_node ) blake2b_set_lastnode( S );
|
||||
|
||||
S->f[0] = (uint64_t)-1;
|
||||
}
|
||||
|
||||
static void blake2b_increment_counter( blake2b_state *S, const uint64_t inc )
|
||||
{
|
||||
S->t[0] += inc;
|
||||
S->t[1] += ( S->t[0] < inc );
|
||||
}
|
||||
|
||||
static void blake2b_init0( blake2b_state *S )
|
||||
{
|
||||
size_t i;
|
||||
memset( S, 0, sizeof( blake2b_state ) );
|
||||
|
||||
for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i];
|
||||
}
|
||||
|
||||
/* init xors IV with input parameter block */
|
||||
int blake2b_init_param( blake2b_state *S, const blake2b_param *P )
|
||||
{
|
||||
const uint8_t *p = ( const uint8_t * )( P );
|
||||
size_t i;
|
||||
|
||||
blake2b_init0( S );
|
||||
|
||||
/* IV XOR ParamBlock */
|
||||
for( i = 0; i < 8; ++i )
|
||||
S->h[i] ^= load64( p + sizeof( S->h[i] ) * i );
|
||||
|
||||
S->outlen = P->digest_length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int blake2b_init( blake2b_state *S, size_t outlen )
|
||||
{
|
||||
blake2b_param P[1];
|
||||
|
||||
if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
|
||||
|
||||
P->digest_length = (uint8_t)outlen;
|
||||
P->key_length = 0;
|
||||
P->fanout = 1;
|
||||
P->depth = 1;
|
||||
store32( &P->leaf_length, 0 );
|
||||
store32( &P->node_offset, 0 );
|
||||
store32( &P->xof_length, 0 );
|
||||
P->node_depth = 0;
|
||||
P->inner_length = 0;
|
||||
memset( P->reserved, 0, sizeof( P->reserved ) );
|
||||
memset( P->salt, 0, sizeof( P->salt ) );
|
||||
memset( P->personal, 0, sizeof( P->personal ) );
|
||||
return blake2b_init_param( S, P );
|
||||
}
|
||||
|
||||
|
||||
int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen )
|
||||
{
|
||||
blake2b_param P[1];
|
||||
|
||||
if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
|
||||
|
||||
if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1;
|
||||
|
||||
P->digest_length = (uint8_t)outlen;
|
||||
P->key_length = (uint8_t)keylen;
|
||||
P->fanout = 1;
|
||||
P->depth = 1;
|
||||
store32( &P->leaf_length, 0 );
|
||||
store32( &P->node_offset, 0 );
|
||||
store32( &P->xof_length, 0 );
|
||||
P->node_depth = 0;
|
||||
P->inner_length = 0;
|
||||
memset( P->reserved, 0, sizeof( P->reserved ) );
|
||||
memset( P->salt, 0, sizeof( P->salt ) );
|
||||
memset( P->personal, 0, sizeof( P->personal ) );
|
||||
|
||||
if( blake2b_init_param( S, P ) < 0 ) return -1;
|
||||
|
||||
{
|
||||
uint8_t block[BLAKE2B_BLOCKBYTES];
|
||||
memset( block, 0, BLAKE2B_BLOCKBYTES );
|
||||
memcpy( block, key, keylen );
|
||||
blake2b_update( S, block, BLAKE2B_BLOCKBYTES );
|
||||
secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define G(r,i,a,b,c,d) \
|
||||
do { \
|
||||
a = a + b + m[blake2b_sigma[r][2*i+0]]; \
|
||||
d = rotr64(d ^ a, 32); \
|
||||
c = c + d; \
|
||||
b = rotr64(b ^ c, 24); \
|
||||
a = a + b + m[blake2b_sigma[r][2*i+1]]; \
|
||||
d = rotr64(d ^ a, 16); \
|
||||
c = c + d; \
|
||||
b = rotr64(b ^ c, 63); \
|
||||
} while(0)
|
||||
|
||||
#define ROUND(r) \
|
||||
do { \
|
||||
G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
|
||||
G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
|
||||
G(r,2,v[ 2],v[ 6],v[10],v[14]); \
|
||||
G(r,3,v[ 3],v[ 7],v[11],v[15]); \
|
||||
G(r,4,v[ 0],v[ 5],v[10],v[15]); \
|
||||
G(r,5,v[ 1],v[ 6],v[11],v[12]); \
|
||||
G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
|
||||
G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
|
||||
} while(0)
|
||||
|
||||
static void blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] )
|
||||
{
|
||||
uint64_t m[16];
|
||||
uint64_t v[16];
|
||||
size_t i;
|
||||
|
||||
for( i = 0; i < 16; ++i ) {
|
||||
m[i] = load64( block + i * sizeof( m[i] ) );
|
||||
}
|
||||
|
||||
for( i = 0; i < 8; ++i ) {
|
||||
v[i] = S->h[i];
|
||||
}
|
||||
|
||||
v[ 8] = blake2b_IV[0];
|
||||
v[ 9] = blake2b_IV[1];
|
||||
v[10] = blake2b_IV[2];
|
||||
v[11] = blake2b_IV[3];
|
||||
v[12] = blake2b_IV[4] ^ S->t[0];
|
||||
v[13] = blake2b_IV[5] ^ S->t[1];
|
||||
v[14] = blake2b_IV[6] ^ S->f[0];
|
||||
v[15] = blake2b_IV[7] ^ S->f[1];
|
||||
|
||||
ROUND( 0 );
|
||||
ROUND( 1 );
|
||||
ROUND( 2 );
|
||||
ROUND( 3 );
|
||||
ROUND( 4 );
|
||||
ROUND( 5 );
|
||||
ROUND( 6 );
|
||||
ROUND( 7 );
|
||||
ROUND( 8 );
|
||||
ROUND( 9 );
|
||||
ROUND( 10 );
|
||||
ROUND( 11 );
|
||||
|
||||
for( i = 0; i < 8; ++i ) {
|
||||
S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
|
||||
}
|
||||
}
|
||||
|
||||
#undef G
|
||||
#undef ROUND
|
||||
|
||||
int blake2b_update( blake2b_state *S, const void *pin, size_t inlen )
|
||||
{
|
||||
const unsigned char * in = (const unsigned char *)pin;
|
||||
if( inlen > 0 )
|
||||
{
|
||||
size_t left = S->buflen;
|
||||
size_t fill = BLAKE2B_BLOCKBYTES - left;
|
||||
if( inlen > fill )
|
||||
{
|
||||
S->buflen = 0;
|
||||
memcpy( S->buf + left, in, fill ); /* Fill buffer */
|
||||
blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
|
||||
blake2b_compress( S, S->buf ); /* Compress */
|
||||
in += fill; inlen -= fill;
|
||||
while(inlen > BLAKE2B_BLOCKBYTES) {
|
||||
blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);
|
||||
blake2b_compress( S, in );
|
||||
in += BLAKE2B_BLOCKBYTES;
|
||||
inlen -= BLAKE2B_BLOCKBYTES;
|
||||
}
|
||||
}
|
||||
memcpy( S->buf + S->buflen, in, inlen );
|
||||
S->buflen += inlen;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blake2b_final( blake2b_state *S, void *out, size_t outlen )
|
||||
{
|
||||
uint8_t buffer[BLAKE2B_OUTBYTES] = {0};
|
||||
size_t i;
|
||||
|
||||
if( out == NULL || outlen < S->outlen )
|
||||
return -1;
|
||||
|
||||
if( blake2b_is_lastblock( S ) )
|
||||
return -1;
|
||||
|
||||
blake2b_increment_counter( S, S->buflen );
|
||||
blake2b_set_lastblock( S );
|
||||
memset( S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */
|
||||
blake2b_compress( S, S->buf );
|
||||
|
||||
for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */
|
||||
store64( buffer + sizeof( S->h[i] ) * i, S->h[i] );
|
||||
|
||||
memcpy( out, buffer, S->outlen );
|
||||
secure_zero_memory(buffer, sizeof(buffer));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* inlen, at least, should be uint64_t. Others can be size_t. */
|
||||
int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen )
|
||||
{
|
||||
blake2b_state S[1];
|
||||
|
||||
/* Verify parameters */
|
||||
if ( NULL == in && inlen > 0 ) return -1;
|
||||
|
||||
if ( NULL == out ) return -1;
|
||||
|
||||
if( NULL == key && keylen > 0 ) return -1;
|
||||
|
||||
if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1;
|
||||
|
||||
if( keylen > BLAKE2B_KEYBYTES ) return -1;
|
||||
|
||||
if( keylen > 0 )
|
||||
{
|
||||
if( blake2b_init_key( S, outlen, key, keylen ) < 0 ) return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( blake2b_init( S, outlen ) < 0 ) return -1;
|
||||
}
|
||||
|
||||
blake2b_update( S, ( const uint8_t * )in, inlen );
|
||||
blake2b_final( S, out, outlen );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) {
|
||||
return blake2b(out, outlen, in, inlen, key, keylen);
|
||||
}
|
||||
|
||||
#if defined(SUPERCOP)
|
||||
int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen )
|
||||
{
|
||||
return blake2b( out, BLAKE2B_OUTBYTES, in, inlen, NULL, 0 );
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BLAKE2B_SELFTEST)
|
||||
#include <string.h>
|
||||
#include "blake2-kat.h"
|
||||
int main( void )
|
||||
{
|
||||
uint8_t key[BLAKE2B_KEYBYTES];
|
||||
uint8_t buf[BLAKE2_KAT_LENGTH];
|
||||
size_t i, step;
|
||||
|
||||
for( i = 0; i < BLAKE2B_KEYBYTES; ++i )
|
||||
key[i] = ( uint8_t )i;
|
||||
|
||||
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
|
||||
buf[i] = ( uint8_t )i;
|
||||
|
||||
/* Test simple API */
|
||||
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
|
||||
{
|
||||
uint8_t hash[BLAKE2B_OUTBYTES];
|
||||
blake2b( hash, BLAKE2B_OUTBYTES, buf, i, key, BLAKE2B_KEYBYTES );
|
||||
|
||||
if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) )
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Test streaming API */
|
||||
for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) {
|
||||
for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
|
||||
uint8_t hash[BLAKE2B_OUTBYTES];
|
||||
blake2b_state S;
|
||||
uint8_t * p = buf;
|
||||
size_t mlen = i;
|
||||
int err = 0;
|
||||
|
||||
if( (err = blake2b_init_key(&S, BLAKE2B_OUTBYTES, key, BLAKE2B_KEYBYTES)) < 0 ) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
while (mlen >= step) {
|
||||
if ( (err = blake2b_update(&S, p, step)) < 0 ) {
|
||||
goto fail;
|
||||
}
|
||||
mlen -= step;
|
||||
p += step;
|
||||
}
|
||||
if ( (err = blake2b_update(&S, p, mlen)) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
if ( (err = blake2b_final(&S, hash, BLAKE2B_OUTBYTES)) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (0 != memcmp(hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES)) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
puts( "ok" );
|
||||
return 0;
|
||||
fail:
|
||||
puts("error");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -78,6 +78,10 @@ static inline Buf *buf_create_from_mem(const char *ptr, size_t len) {
|
|||
return buf;
|
||||
}
|
||||
|
||||
static inline Buf *buf_create_from_slice(Slice<uint8_t> slice) {
|
||||
return buf_create_from_mem((const char *)slice.ptr, slice.len);
|
||||
}
|
||||
|
||||
static inline Buf *buf_create_from_str(const char *str) {
|
||||
return buf_create_from_mem(str, strlen(str));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,469 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Andrew Kelley
|
||||
*
|
||||
* This file is part of zig, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "cache_hash.hpp"
|
||||
#include "all_types.hpp"
|
||||
#include "buffer.hpp"
|
||||
#include "os.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void cache_init(CacheHash *ch, Buf *manifest_dir) {
|
||||
int rc = blake2b_init(&ch->blake, 48);
|
||||
assert(rc == 0);
|
||||
ch->files = {};
|
||||
ch->manifest_dir = manifest_dir;
|
||||
ch->manifest_file_path = nullptr;
|
||||
ch->manifest_dirty = false;
|
||||
}
|
||||
|
||||
void cache_str(CacheHash *ch, const char *ptr) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
assert(ptr != nullptr);
|
||||
// + 1 to include the null byte
|
||||
blake2b_update(&ch->blake, ptr, strlen(ptr) + 1);
|
||||
}
|
||||
|
||||
void cache_int(CacheHash *ch, int x) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
// + 1 to include the null byte
|
||||
uint8_t buf[sizeof(int) + 1];
|
||||
memcpy(buf, &x, sizeof(int));
|
||||
buf[sizeof(int)] = 0;
|
||||
blake2b_update(&ch->blake, buf, sizeof(int) + 1);
|
||||
}
|
||||
|
||||
void cache_usize(CacheHash *ch, size_t x) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
// + 1 to include the null byte
|
||||
uint8_t buf[sizeof(size_t) + 1];
|
||||
memcpy(buf, &x, sizeof(size_t));
|
||||
buf[sizeof(size_t)] = 0;
|
||||
blake2b_update(&ch->blake, buf, sizeof(size_t) + 1);
|
||||
}
|
||||
|
||||
void cache_bool(CacheHash *ch, bool x) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
blake2b_update(&ch->blake, &x, 1);
|
||||
}
|
||||
|
||||
void cache_buf(CacheHash *ch, Buf *buf) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
assert(buf != nullptr);
|
||||
// + 1 to include the null byte
|
||||
blake2b_update(&ch->blake, buf_ptr(buf), buf_len(buf) + 1);
|
||||
}
|
||||
|
||||
void cache_buf_opt(CacheHash *ch, Buf *buf) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
if (buf == nullptr) {
|
||||
cache_str(ch, "");
|
||||
cache_str(ch, "");
|
||||
} else {
|
||||
cache_buf(ch, buf);
|
||||
}
|
||||
}
|
||||
|
||||
void cache_list_of_link_lib(CacheHash *ch, LinkLib **ptr, size_t len) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
for (size_t i = 0; i < len; i += 1) {
|
||||
LinkLib *lib = ptr[i];
|
||||
if (lib->provided_explicitly) {
|
||||
cache_buf(ch, lib->name);
|
||||
}
|
||||
}
|
||||
cache_str(ch, "");
|
||||
}
|
||||
|
||||
void cache_list_of_buf(CacheHash *ch, Buf **ptr, size_t len) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
for (size_t i = 0; i < len; i += 1) {
|
||||
Buf *buf = ptr[i];
|
||||
cache_buf(ch, buf);
|
||||
}
|
||||
cache_str(ch, "");
|
||||
}
|
||||
|
||||
void cache_list_of_file(CacheHash *ch, Buf **ptr, size_t len) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
|
||||
for (size_t i = 0; i < len; i += 1) {
|
||||
Buf *buf = ptr[i];
|
||||
cache_file(ch, buf);
|
||||
}
|
||||
cache_str(ch, "");
|
||||
}
|
||||
|
||||
void cache_list_of_str(CacheHash *ch, const char **ptr, size_t len) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
|
||||
for (size_t i = 0; i < len; i += 1) {
|
||||
const char *s = ptr[i];
|
||||
cache_str(ch, s);
|
||||
}
|
||||
cache_str(ch, "");
|
||||
}
|
||||
|
||||
void cache_file(CacheHash *ch, Buf *file_path) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
assert(file_path != nullptr);
|
||||
Buf *resolved_path = buf_alloc();
|
||||
*resolved_path = os_path_resolve(&file_path, 1);
|
||||
CacheHashFile *chf = ch->files.add_one();
|
||||
chf->path = resolved_path;
|
||||
cache_buf(ch, resolved_path);
|
||||
}
|
||||
|
||||
void cache_file_opt(CacheHash *ch, Buf *file_path) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
if (file_path == nullptr) {
|
||||
cache_str(ch, "");
|
||||
cache_str(ch, "");
|
||||
} else {
|
||||
cache_file(ch, file_path);
|
||||
}
|
||||
}
|
||||
|
||||
// Ported from std/base64.zig
|
||||
static uint8_t base64_fs_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
static void base64_encode(Slice<uint8_t> dest, Slice<uint8_t> source) {
|
||||
size_t dest_len = ((source.len + 2) / 3) * 4;
|
||||
assert(dest.len == dest_len);
|
||||
|
||||
size_t i = 0;
|
||||
size_t out_index = 0;
|
||||
for (; i + 2 < source.len; i += 3) {
|
||||
dest.ptr[out_index] = base64_fs_alphabet[(source.ptr[i] >> 2) & 0x3f];
|
||||
out_index += 1;
|
||||
|
||||
dest.ptr[out_index] = base64_fs_alphabet[((source.ptr[i] & 0x3) << 4) | ((source.ptr[i + 1] & 0xf0) >> 4)];
|
||||
out_index += 1;
|
||||
|
||||
dest.ptr[out_index] = base64_fs_alphabet[((source.ptr[i + 1] & 0xf) << 2) | ((source.ptr[i + 2] & 0xc0) >> 6)];
|
||||
out_index += 1;
|
||||
|
||||
dest.ptr[out_index] = base64_fs_alphabet[source.ptr[i + 2] & 0x3f];
|
||||
out_index += 1;
|
||||
}
|
||||
|
||||
// Assert that we never need pad characters.
|
||||
assert(i == source.len);
|
||||
}
|
||||
|
||||
// Ported from std/base64.zig
|
||||
static Error base64_decode(Slice<uint8_t> dest, Slice<uint8_t> source) {
|
||||
assert(source.len % 4 == 0);
|
||||
assert(dest.len == (source.len / 4) * 3);
|
||||
|
||||
// In Zig this is comptime computed. In C++ it's not worth it to do that.
|
||||
uint8_t char_to_index[256];
|
||||
bool char_in_alphabet[256] = {0};
|
||||
for (size_t i = 0; i < 64; i += 1) {
|
||||
uint8_t c = base64_fs_alphabet[i];
|
||||
assert(!char_in_alphabet[c]);
|
||||
char_in_alphabet[c] = true;
|
||||
char_to_index[c] = i;
|
||||
}
|
||||
|
||||
size_t src_cursor = 0;
|
||||
size_t dest_cursor = 0;
|
||||
|
||||
for (;src_cursor < source.len; src_cursor += 4) {
|
||||
if (!char_in_alphabet[source.ptr[src_cursor + 0]]) return ErrorInvalidFormat;
|
||||
if (!char_in_alphabet[source.ptr[src_cursor + 1]]) return ErrorInvalidFormat;
|
||||
if (!char_in_alphabet[source.ptr[src_cursor + 2]]) return ErrorInvalidFormat;
|
||||
if (!char_in_alphabet[source.ptr[src_cursor + 3]]) return ErrorInvalidFormat;
|
||||
dest.ptr[dest_cursor + 0] = (char_to_index[source.ptr[src_cursor + 0]] << 2) | (char_to_index[source.ptr[src_cursor + 1]] >> 4);
|
||||
dest.ptr[dest_cursor + 1] = (char_to_index[source.ptr[src_cursor + 1]] << 4) | (char_to_index[source.ptr[src_cursor + 2]] >> 2);
|
||||
dest.ptr[dest_cursor + 2] = (char_to_index[source.ptr[src_cursor + 2]] << 6) | (char_to_index[source.ptr[src_cursor + 3]]);
|
||||
dest_cursor += 3;
|
||||
}
|
||||
|
||||
assert(src_cursor == source.len);
|
||||
assert(dest_cursor == dest.len);
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
static Error hash_file(uint8_t *digest, OsFile handle, Buf *contents) {
|
||||
Error err;
|
||||
|
||||
if (contents) {
|
||||
buf_resize(contents, 0);
|
||||
}
|
||||
|
||||
blake2b_state blake;
|
||||
int rc = blake2b_init(&blake, 48);
|
||||
assert(rc == 0);
|
||||
|
||||
for (;;) {
|
||||
uint8_t buf[4096];
|
||||
size_t amt = 4096;
|
||||
if ((err = os_file_read(handle, buf, &amt)))
|
||||
return err;
|
||||
if (amt == 0) {
|
||||
rc = blake2b_final(&blake, digest, 48);
|
||||
assert(rc == 0);
|
||||
return ErrorNone;
|
||||
}
|
||||
blake2b_update(&blake, buf, amt);
|
||||
if (contents) {
|
||||
buf_append_mem(contents, (char*)buf, amt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Error populate_file_hash(CacheHash *ch, CacheHashFile *chf, Buf *contents) {
|
||||
Error err;
|
||||
|
||||
assert(chf->path != nullptr);
|
||||
|
||||
OsFile this_file;
|
||||
if ((err = os_file_open_r(chf->path, &this_file)))
|
||||
return err;
|
||||
|
||||
if ((err = os_file_mtime(this_file, &chf->mtime))) {
|
||||
os_file_close(this_file);
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = hash_file(chf->bin_digest, this_file, contents))) {
|
||||
os_file_close(this_file);
|
||||
return err;
|
||||
}
|
||||
os_file_close(this_file);
|
||||
|
||||
blake2b_update(&ch->blake, chf->bin_digest, 48);
|
||||
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
Error cache_hit(CacheHash *ch, Buf *out_digest) {
|
||||
Error err;
|
||||
|
||||
uint8_t bin_digest[48];
|
||||
int rc = blake2b_final(&ch->blake, bin_digest, 48);
|
||||
assert(rc == 0);
|
||||
|
||||
if (ch->files.length == 0) {
|
||||
buf_resize(out_digest, 64);
|
||||
base64_encode(buf_to_slice(out_digest), {bin_digest, 48});
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
Buf b64_digest = BUF_INIT;
|
||||
buf_resize(&b64_digest, 64);
|
||||
base64_encode(buf_to_slice(&b64_digest), {bin_digest, 48});
|
||||
|
||||
rc = blake2b_init(&ch->blake, 48);
|
||||
assert(rc == 0);
|
||||
blake2b_update(&ch->blake, bin_digest, 48);
|
||||
|
||||
ch->manifest_file_path = buf_alloc();
|
||||
os_path_join(ch->manifest_dir, &b64_digest, ch->manifest_file_path);
|
||||
|
||||
buf_append_str(ch->manifest_file_path, ".txt");
|
||||
|
||||
if ((err = os_make_path(ch->manifest_dir)))
|
||||
return err;
|
||||
|
||||
if ((err = os_file_open_lock_rw(ch->manifest_file_path, &ch->manifest_file)))
|
||||
return err;
|
||||
|
||||
Buf line_buf = BUF_INIT;
|
||||
buf_resize(&line_buf, 512);
|
||||
if ((err = os_file_read_all(ch->manifest_file, &line_buf))) {
|
||||
os_file_close(ch->manifest_file);
|
||||
return err;
|
||||
}
|
||||
|
||||
size_t input_file_count = ch->files.length;
|
||||
bool any_file_changed = false;
|
||||
size_t file_i = 0;
|
||||
SplitIterator line_it = memSplit(buf_to_slice(&line_buf), str("\n"));
|
||||
for (;; file_i += 1) {
|
||||
Optional<Slice<uint8_t>> opt_line = SplitIterator_next(&line_it);
|
||||
if (!opt_line.is_some)
|
||||
break;
|
||||
|
||||
CacheHashFile *chf;
|
||||
if (file_i < input_file_count) {
|
||||
chf = &ch->files.at(file_i);
|
||||
} else if (any_file_changed) {
|
||||
// cache miss.
|
||||
// keep the the manifest file open with the rw lock
|
||||
// reset the hash
|
||||
rc = blake2b_init(&ch->blake, 48);
|
||||
assert(rc == 0);
|
||||
blake2b_update(&ch->blake, bin_digest, 48);
|
||||
ch->files.resize(input_file_count);
|
||||
// bring the hash up to the input file hashes
|
||||
for (file_i = 0; file_i < input_file_count; file_i += 1) {
|
||||
blake2b_update(&ch->blake, ch->files.at(file_i).bin_digest, 48);
|
||||
}
|
||||
// caller can notice that out_digest is unmodified.
|
||||
return ErrorNone;
|
||||
} else {
|
||||
chf = ch->files.add_one();
|
||||
chf->path = nullptr;
|
||||
}
|
||||
|
||||
SplitIterator it = memSplit(opt_line.value, str(" "));
|
||||
|
||||
Optional<Slice<uint8_t>> opt_mtime_sec = SplitIterator_next(&it);
|
||||
if (!opt_mtime_sec.is_some) {
|
||||
os_file_close(ch->manifest_file);
|
||||
return ErrorInvalidFormat;
|
||||
}
|
||||
chf->mtime.sec = strtoull((const char *)opt_mtime_sec.value.ptr, nullptr, 10);
|
||||
|
||||
Optional<Slice<uint8_t>> opt_mtime_nsec = SplitIterator_next(&it);
|
||||
if (!opt_mtime_nsec.is_some) {
|
||||
os_file_close(ch->manifest_file);
|
||||
return ErrorInvalidFormat;
|
||||
}
|
||||
chf->mtime.nsec = strtoull((const char *)opt_mtime_nsec.value.ptr, nullptr, 10);
|
||||
|
||||
Optional<Slice<uint8_t>> opt_digest = SplitIterator_next(&it);
|
||||
if (!opt_digest.is_some) {
|
||||
os_file_close(ch->manifest_file);
|
||||
return ErrorInvalidFormat;
|
||||
}
|
||||
if ((err = base64_decode({chf->bin_digest, 48}, opt_digest.value))) {
|
||||
os_file_close(ch->manifest_file);
|
||||
return ErrorInvalidFormat;
|
||||
}
|
||||
|
||||
Optional<Slice<uint8_t>> opt_file_path = SplitIterator_next(&it);
|
||||
if (!opt_file_path.is_some) {
|
||||
os_file_close(ch->manifest_file);
|
||||
return ErrorInvalidFormat;
|
||||
}
|
||||
Buf *this_path = buf_create_from_slice(opt_file_path.value);
|
||||
if (chf->path != nullptr && !buf_eql_buf(this_path, chf->path)) {
|
||||
os_file_close(ch->manifest_file);
|
||||
return ErrorInvalidFormat;
|
||||
}
|
||||
chf->path = this_path;
|
||||
|
||||
// if the mtime matches we can trust the digest
|
||||
OsFile this_file;
|
||||
if ((err = os_file_open_r(chf->path, &this_file))) {
|
||||
os_file_close(ch->manifest_file);
|
||||
return err;
|
||||
}
|
||||
OsTimeStamp actual_mtime;
|
||||
if ((err = os_file_mtime(this_file, &actual_mtime))) {
|
||||
os_file_close(this_file);
|
||||
os_file_close(ch->manifest_file);
|
||||
return err;
|
||||
}
|
||||
if (chf->mtime.sec == actual_mtime.sec && chf->mtime.nsec == actual_mtime.nsec) {
|
||||
os_file_close(this_file);
|
||||
} else {
|
||||
// we have to recompute the digest.
|
||||
// later we'll rewrite the manifest with the new mtime/digest values
|
||||
ch->manifest_dirty = true;
|
||||
chf->mtime = actual_mtime;
|
||||
|
||||
uint8_t actual_digest[48];
|
||||
if ((err = hash_file(actual_digest, this_file, nullptr))) {
|
||||
os_file_close(this_file);
|
||||
os_file_close(ch->manifest_file);
|
||||
return err;
|
||||
}
|
||||
os_file_close(this_file);
|
||||
if (memcmp(chf->bin_digest, actual_digest, 48) != 0) {
|
||||
memcpy(chf->bin_digest, actual_digest, 48);
|
||||
// keep going until we have the input file digests
|
||||
any_file_changed = true;
|
||||
}
|
||||
}
|
||||
if (!any_file_changed) {
|
||||
blake2b_update(&ch->blake, chf->bin_digest, 48);
|
||||
}
|
||||
}
|
||||
if (file_i < input_file_count) {
|
||||
// manifest file is empty or missing entries, so this is a cache miss
|
||||
ch->manifest_dirty = true;
|
||||
for (; file_i < input_file_count; file_i += 1) {
|
||||
CacheHashFile *chf = &ch->files.at(file_i);
|
||||
if ((err = populate_file_hash(ch, chf, nullptr))) {
|
||||
os_file_close(ch->manifest_file);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return ErrorNone;
|
||||
}
|
||||
// Cache Hit
|
||||
return cache_final(ch, out_digest);
|
||||
}
|
||||
|
||||
Error cache_add_file_fetch(CacheHash *ch, Buf *resolved_path, Buf *contents) {
|
||||
Error err;
|
||||
|
||||
assert(ch->manifest_file_path != nullptr);
|
||||
CacheHashFile *chf = ch->files.add_one();
|
||||
chf->path = resolved_path;
|
||||
if ((err = populate_file_hash(ch, chf, contents))) {
|
||||
os_file_close(ch->manifest_file);
|
||||
return err;
|
||||
}
|
||||
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
Error cache_add_file(CacheHash *ch, Buf *path) {
|
||||
Buf *resolved_path = buf_alloc();
|
||||
*resolved_path = os_path_resolve(&path, 1);
|
||||
return cache_add_file_fetch(ch, resolved_path, nullptr);
|
||||
}
|
||||
|
||||
static Error write_manifest_file(CacheHash *ch) {
|
||||
Error err;
|
||||
Buf contents = BUF_INIT;
|
||||
buf_resize(&contents, 0);
|
||||
uint8_t encoded_digest[65];
|
||||
encoded_digest[64] = 0;
|
||||
for (size_t i = 0; i < ch->files.length; i += 1) {
|
||||
CacheHashFile *chf = &ch->files.at(i);
|
||||
base64_encode({encoded_digest, 64}, {chf->bin_digest, 48});
|
||||
buf_appendf(&contents, "%" ZIG_PRI_u64 " %" ZIG_PRI_u64 " %s %s\n",
|
||||
chf->mtime.sec, chf->mtime.nsec, encoded_digest, buf_ptr(chf->path));
|
||||
}
|
||||
if ((err = os_file_overwrite(ch->manifest_file, &contents)))
|
||||
return err;
|
||||
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
Error cache_final(CacheHash *ch, Buf *out_digest) {
|
||||
Error err;
|
||||
|
||||
assert(ch->manifest_file_path != nullptr);
|
||||
|
||||
if (ch->manifest_dirty) {
|
||||
if ((err = write_manifest_file(ch))) {
|
||||
fprintf(stderr, "Warning: Unable to write cache file '%s': %s\n",
|
||||
buf_ptr(ch->manifest_file_path), err_str(err));
|
||||
}
|
||||
}
|
||||
// We don't close the manifest file yet, because we want to
|
||||
// keep it locked until the API user is done using it.
|
||||
|
||||
uint8_t bin_digest[48];
|
||||
int rc = blake2b_final(&ch->blake, bin_digest, 48);
|
||||
assert(rc == 0);
|
||||
buf_resize(out_digest, 64);
|
||||
base64_encode(buf_to_slice(out_digest), {bin_digest, 48});
|
||||
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
void cache_release(CacheHash *ch) {
|
||||
assert(ch->manifest_file_path != nullptr);
|
||||
os_file_close(ch->manifest_file);
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Andrew Kelley
|
||||
*
|
||||
* This file is part of zig, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#ifndef ZIG_CACHE_HASH_HPP
|
||||
#define ZIG_CACHE_HASH_HPP
|
||||
|
||||
#include "blake2.h"
|
||||
#include "os.hpp"
|
||||
|
||||
struct LinkLib;
|
||||
|
||||
struct CacheHashFile {
|
||||
Buf *path;
|
||||
OsTimeStamp mtime;
|
||||
uint8_t bin_digest[48];
|
||||
Buf *contents;
|
||||
};
|
||||
|
||||
struct CacheHash {
|
||||
blake2b_state blake;
|
||||
ZigList<CacheHashFile> files;
|
||||
Buf *manifest_dir;
|
||||
Buf *manifest_file_path;
|
||||
OsFile manifest_file;
|
||||
bool manifest_dirty;
|
||||
};
|
||||
|
||||
// Always call this first to set up.
|
||||
void cache_init(CacheHash *ch, Buf *manifest_dir);
|
||||
|
||||
// Next, use the hash population functions to add the initial parameters.
|
||||
void cache_str(CacheHash *ch, const char *ptr);
|
||||
void cache_int(CacheHash *ch, int x);
|
||||
void cache_bool(CacheHash *ch, bool x);
|
||||
void cache_usize(CacheHash *ch, size_t x);
|
||||
void cache_buf(CacheHash *ch, Buf *buf);
|
||||
void cache_buf_opt(CacheHash *ch, Buf *buf);
|
||||
void cache_list_of_link_lib(CacheHash *ch, LinkLib **ptr, size_t len);
|
||||
void cache_list_of_buf(CacheHash *ch, Buf **ptr, size_t len);
|
||||
void cache_list_of_file(CacheHash *ch, Buf **ptr, size_t len);
|
||||
void cache_list_of_str(CacheHash *ch, const char **ptr, size_t len);
|
||||
void cache_file(CacheHash *ch, Buf *path);
|
||||
void cache_file_opt(CacheHash *ch, Buf *path);
|
||||
|
||||
// Then call cache_hit when you're ready to see if you can skip the next step.
|
||||
// out_b64_digest will be left unchanged if it was a cache miss.
|
||||
// If you got a cache hit, the next step is cache_release.
|
||||
// From this point on, there is a lock on the input params. Release
|
||||
// the lock with cache_release.
|
||||
Error ATTRIBUTE_MUST_USE cache_hit(CacheHash *ch, Buf *out_b64_digest);
|
||||
|
||||
// If you did not get a cache hit, call this function for every file
|
||||
// that is depended on, and then finish with cache_final.
|
||||
Error ATTRIBUTE_MUST_USE cache_add_file(CacheHash *ch, Buf *path);
|
||||
|
||||
// This variant of cache_add_file returns the file contents.
|
||||
// Also the file path argument must be already resolved.
|
||||
Error ATTRIBUTE_MUST_USE cache_add_file_fetch(CacheHash *ch, Buf *resolved_path, Buf *contents);
|
||||
|
||||
// out_b64_digest will be the same thing that cache_hit returns if you got a cache hit
|
||||
Error ATTRIBUTE_MUST_USE cache_final(CacheHash *ch, Buf *out_b64_digest);
|
||||
|
||||
// Until this function is called, no one will be able to get a lock on your input params.
|
||||
void cache_release(CacheHash *ch);
|
||||
|
||||
|
||||
#endif
|
424
src/codegen.cpp
424
src/codegen.cpp
|
@ -8,12 +8,12 @@
|
|||
#include "analyze.hpp"
|
||||
#include "ast_render.hpp"
|
||||
#include "codegen.hpp"
|
||||
#include "compiler.hpp"
|
||||
#include "config.h"
|
||||
#include "errmsg.hpp"
|
||||
#include "error.hpp"
|
||||
#include "hash_map.hpp"
|
||||
#include "ir.hpp"
|
||||
#include "link.hpp"
|
||||
#include "os.hpp"
|
||||
#include "translate_c.hpp"
|
||||
#include "target.hpp"
|
||||
|
@ -183,14 +183,14 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
|
|||
return g;
|
||||
}
|
||||
|
||||
void codegen_destroy(CodeGen *codegen) {
|
||||
LLVMDisposeTargetMachine(codegen->target_machine);
|
||||
}
|
||||
|
||||
void codegen_set_output_h_path(CodeGen *g, Buf *h_path) {
|
||||
g->out_h_path = h_path;
|
||||
}
|
||||
|
||||
void codegen_set_output_path(CodeGen *g, Buf *path) {
|
||||
g->wanted_output_file_path = path;
|
||||
}
|
||||
|
||||
void codegen_set_clang_argv(CodeGen *g, const char **args, size_t len) {
|
||||
g->clang_argv = args;
|
||||
g->clang_argv_len = len;
|
||||
|
@ -243,10 +243,6 @@ void codegen_set_out_name(CodeGen *g, Buf *out_name) {
|
|||
g->root_out_name = out_name;
|
||||
}
|
||||
|
||||
void codegen_set_cache_dir(CodeGen *g, Buf cache_dir) {
|
||||
g->cache_dir = cache_dir;
|
||||
}
|
||||
|
||||
void codegen_set_libc_lib_dir(CodeGen *g, Buf *libc_lib_dir) {
|
||||
g->libc_lib_dir = libc_lib_dir;
|
||||
}
|
||||
|
@ -6076,13 +6072,6 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val,
|
|||
// TODO ^^ make an actual global variable
|
||||
}
|
||||
|
||||
static void ensure_cache_dir(CodeGen *g) {
|
||||
int err;
|
||||
if ((err = os_make_path(&g->cache_dir))) {
|
||||
zig_panic("unable to make cache dir: %s", err_str(err));
|
||||
}
|
||||
}
|
||||
|
||||
static void validate_inline_fns(CodeGen *g) {
|
||||
for (size_t i = 0; i < g->inline_fns.length; i += 1) {
|
||||
ZigFn *fn_entry = g->inline_fns.at(i);
|
||||
|
@ -6097,8 +6086,6 @@ static void validate_inline_fns(CodeGen *g) {
|
|||
static void do_code_gen(CodeGen *g) {
|
||||
assert(!g->errors.length);
|
||||
|
||||
codegen_add_time_event(g, "Code Generation");
|
||||
|
||||
{
|
||||
// create debug type for error sets
|
||||
assert(g->err_enumerators.length == g->errors_by_index.length);
|
||||
|
@ -6401,45 +6388,18 @@ static void do_code_gen(CodeGen *g) {
|
|||
char *error = nullptr;
|
||||
LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error);
|
||||
#endif
|
||||
}
|
||||
|
||||
codegen_add_time_event(g, "LLVM Emit Output");
|
||||
|
||||
char *err_msg = nullptr;
|
||||
Buf *o_basename = buf_create_from_buf(g->root_out_name);
|
||||
|
||||
switch (g->emit_file_type) {
|
||||
case EmitFileTypeBinary:
|
||||
{
|
||||
const char *o_ext = target_o_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, o_ext);
|
||||
break;
|
||||
}
|
||||
case EmitFileTypeAssembly:
|
||||
{
|
||||
const char *asm_ext = target_asm_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, asm_ext);
|
||||
break;
|
||||
}
|
||||
case EmitFileTypeLLVMIr:
|
||||
{
|
||||
const char *llvm_ir_ext = target_llvm_ir_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, llvm_ir_ext);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
Buf *output_path = buf_alloc();
|
||||
os_path_join(&g->cache_dir, o_basename, output_path);
|
||||
ensure_cache_dir(g);
|
||||
|
||||
static void zig_llvm_emit_output(CodeGen *g) {
|
||||
bool is_small = g->build_mode == BuildModeSmallRelease;
|
||||
|
||||
Buf *output_path = &g->o_file_output_path;
|
||||
char *err_msg = nullptr;
|
||||
switch (g->emit_file_type) {
|
||||
case EmitFileTypeBinary:
|
||||
if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
|
||||
ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug, is_small))
|
||||
ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug, is_small,
|
||||
g->enable_time_report))
|
||||
{
|
||||
zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg);
|
||||
}
|
||||
|
@ -6449,22 +6409,22 @@ static void do_code_gen(CodeGen *g) {
|
|||
|
||||
case EmitFileTypeAssembly:
|
||||
if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
|
||||
ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug, is_small))
|
||||
ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug, is_small,
|
||||
g->enable_time_report))
|
||||
{
|
||||
zig_panic("unable to write assembly file %s: %s", buf_ptr(output_path), err_msg);
|
||||
}
|
||||
validate_inline_fns(g);
|
||||
g->link_objects.append(output_path);
|
||||
break;
|
||||
|
||||
case EmitFileTypeLLVMIr:
|
||||
if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
|
||||
ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug, is_small))
|
||||
ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug, is_small,
|
||||
g->enable_time_report))
|
||||
{
|
||||
zig_panic("unable to write llvm-ir file %s: %s", buf_ptr(output_path), err_msg);
|
||||
}
|
||||
validate_inline_fns(g);
|
||||
g->link_objects.append(output_path);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -7189,36 +7149,84 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
|
|||
return contents;
|
||||
}
|
||||
|
||||
static void define_builtin_compile_vars(CodeGen *g) {
|
||||
static Error define_builtin_compile_vars(CodeGen *g) {
|
||||
if (g->std_package == nullptr)
|
||||
return;
|
||||
return ErrorNone;
|
||||
|
||||
Error err;
|
||||
|
||||
Buf *manifest_dir = buf_alloc();
|
||||
os_path_join(get_stage1_cache_path(), buf_create_from_str("builtin"), manifest_dir);
|
||||
|
||||
CacheHash cache_hash;
|
||||
cache_init(&cache_hash, manifest_dir);
|
||||
|
||||
Buf *compiler_id;
|
||||
if ((err = get_compiler_id(&compiler_id)))
|
||||
return err;
|
||||
|
||||
// Only a few things affect builtin.zig
|
||||
cache_buf(&cache_hash, compiler_id);
|
||||
cache_int(&cache_hash, g->build_mode);
|
||||
cache_bool(&cache_hash, g->is_test_build);
|
||||
cache_int(&cache_hash, g->zig_target.arch.arch);
|
||||
cache_int(&cache_hash, g->zig_target.arch.sub_arch);
|
||||
cache_int(&cache_hash, g->zig_target.vendor);
|
||||
cache_int(&cache_hash, g->zig_target.os);
|
||||
cache_int(&cache_hash, g->zig_target.env_type);
|
||||
cache_int(&cache_hash, g->zig_target.oformat);
|
||||
cache_bool(&cache_hash, g->have_err_ret_tracing);
|
||||
cache_bool(&cache_hash, g->libc_link_lib != nullptr);
|
||||
|
||||
Buf digest = BUF_INIT;
|
||||
buf_resize(&digest, 0);
|
||||
if ((err = cache_hit(&cache_hash, &digest)))
|
||||
return err;
|
||||
|
||||
// We should always get a cache hit because there are no
|
||||
// files in the input hash.
|
||||
assert(buf_len(&digest) != 0);
|
||||
|
||||
Buf *this_dir = buf_alloc();
|
||||
os_path_join(manifest_dir, &digest, this_dir);
|
||||
|
||||
if ((err = os_make_path(this_dir)))
|
||||
return err;
|
||||
|
||||
const char *builtin_zig_basename = "builtin.zig";
|
||||
Buf *builtin_zig_path = buf_alloc();
|
||||
os_path_join(&g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
|
||||
os_path_join(this_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
|
||||
|
||||
Buf *contents = codegen_generate_builtin_source(g);
|
||||
ensure_cache_dir(g);
|
||||
os_write_file(builtin_zig_path, contents);
|
||||
|
||||
Buf *resolved_path = buf_alloc();
|
||||
Buf *resolve_paths[] = {builtin_zig_path};
|
||||
*resolved_path = os_path_resolve(resolve_paths, 1);
|
||||
bool hit;
|
||||
if ((err = os_file_exists(builtin_zig_path, &hit)))
|
||||
return err;
|
||||
Buf *contents;
|
||||
if (hit) {
|
||||
contents = buf_alloc();
|
||||
if ((err = os_fetch_file_path(builtin_zig_path, contents, false))) {
|
||||
fprintf(stderr, "Unable to open '%s': %s\n", buf_ptr(builtin_zig_path), err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
contents = codegen_generate_builtin_source(g);
|
||||
os_write_file(builtin_zig_path, contents);
|
||||
}
|
||||
|
||||
assert(g->root_package);
|
||||
assert(g->std_package);
|
||||
g->compile_var_package = new_package(buf_ptr(&g->cache_dir), builtin_zig_basename);
|
||||
g->compile_var_package = new_package(buf_ptr(this_dir), builtin_zig_basename);
|
||||
g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
|
||||
g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
|
||||
g->compile_var_import = add_source_file(g, g->compile_var_package, resolved_path, contents);
|
||||
g->compile_var_import = add_source_file(g, g->compile_var_package, builtin_zig_path, contents);
|
||||
scan_import(g, g->compile_var_import);
|
||||
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
static void init(CodeGen *g) {
|
||||
if (g->module)
|
||||
return;
|
||||
|
||||
|
||||
if (g->llvm_argv_len > 0) {
|
||||
const char **args = allocate_nonzero<const char *>(g->llvm_argv_len + 2);
|
||||
args[0] = "zig (LLVM option parsing)";
|
||||
|
@ -7325,7 +7333,11 @@ static void init(CodeGen *g) {
|
|||
g->have_err_ret_tracing = g->build_mode != BuildModeFastRelease && g->build_mode != BuildModeSmallRelease;
|
||||
|
||||
define_builtin_fns(g);
|
||||
define_builtin_compile_vars(g);
|
||||
Error err;
|
||||
if ((err = define_builtin_compile_vars(g))) {
|
||||
fprintf(stderr, "Unable to create builtin.zig: %s\n", err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void codegen_translate_c(CodeGen *g, Buf *full_path) {
|
||||
|
@ -7371,8 +7383,8 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package
|
|||
Buf *resolved_path = buf_alloc();
|
||||
*resolved_path = os_path_resolve(resolve_paths, 1);
|
||||
Buf *import_code = buf_alloc();
|
||||
int err;
|
||||
if ((err = os_fetch_file_path(resolved_path, import_code, false))) {
|
||||
Error err;
|
||||
if ((err = file_fetch(g, resolved_path, import_code))) {
|
||||
zig_panic("unable to open '%s': %s\n", buf_ptr(&path_to_code_src), err_str(err));
|
||||
}
|
||||
|
||||
|
@ -7445,23 +7457,32 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
|
|||
g->test_runner_import = add_special_code(g, g->test_runner_package, "test_runner.zig");
|
||||
}
|
||||
|
||||
static void gen_root_source(CodeGen *g) {
|
||||
static Buf *get_resolved_root_src_path(CodeGen *g) {
|
||||
// TODO memoize
|
||||
if (buf_len(&g->root_package->root_src_path) == 0)
|
||||
return;
|
||||
return nullptr;
|
||||
|
||||
codegen_add_time_event(g, "Semantic Analysis");
|
||||
|
||||
Buf *rel_full_path = buf_alloc();
|
||||
os_path_join(&g->root_package->root_src_dir, &g->root_package->root_src_path, rel_full_path);
|
||||
Buf rel_full_path = BUF_INIT;
|
||||
os_path_join(&g->root_package->root_src_dir, &g->root_package->root_src_path, &rel_full_path);
|
||||
|
||||
Buf *resolved_path = buf_alloc();
|
||||
Buf *resolve_paths[] = {rel_full_path};
|
||||
Buf *resolve_paths[] = {&rel_full_path};
|
||||
*resolved_path = os_path_resolve(resolve_paths, 1);
|
||||
|
||||
return resolved_path;
|
||||
}
|
||||
|
||||
static void gen_root_source(CodeGen *g) {
|
||||
Buf *resolved_path = get_resolved_root_src_path(g);
|
||||
if (resolved_path == nullptr)
|
||||
return;
|
||||
|
||||
Buf *source_code = buf_alloc();
|
||||
int err;
|
||||
if ((err = os_fetch_file_path(rel_full_path, source_code, true))) {
|
||||
fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(rel_full_path), err_str(err));
|
||||
// No need for using the caching system for this file fetch because it is handled
|
||||
// separately.
|
||||
if ((err = os_fetch_file_path(resolved_path, source_code, true))) {
|
||||
fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(resolved_path), err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
@ -7526,6 +7547,8 @@ static void gen_global_asm(CodeGen *g) {
|
|||
int err;
|
||||
for (size_t i = 0; i < g->assembly_files.length; i += 1) {
|
||||
Buf *asm_file = g->assembly_files.at(i);
|
||||
// No need to use the caching system for these fetches because they
|
||||
// are handled separately.
|
||||
if ((err = os_fetch_file_path(asm_file, &contents, false))) {
|
||||
zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err));
|
||||
}
|
||||
|
@ -7789,19 +7812,11 @@ static Buf *preprocessor_mangle(Buf *src) {
|
|||
}
|
||||
|
||||
static void gen_h_file(CodeGen *g) {
|
||||
if (!g->want_h_file)
|
||||
return;
|
||||
|
||||
GenH gen_h_data = {0};
|
||||
GenH *gen_h = &gen_h_data;
|
||||
|
||||
codegen_add_time_event(g, "Generate .h");
|
||||
|
||||
assert(!g->is_test_build);
|
||||
|
||||
if (!g->out_h_path) {
|
||||
g->out_h_path = buf_sprintf("%s.h", buf_ptr(g->root_out_name));
|
||||
}
|
||||
assert(g->out_h_path != nullptr);
|
||||
|
||||
FILE *out_h = fopen(buf_ptr(g->out_h_path), "wb");
|
||||
if (!out_h)
|
||||
|
@ -8004,14 +8019,231 @@ void codegen_add_time_event(CodeGen *g, const char *name) {
|
|||
g->timing_events.append({os_get_time(), name});
|
||||
}
|
||||
|
||||
void codegen_build(CodeGen *g) {
|
||||
assert(g->out_type != OutTypeUnknown);
|
||||
init(g);
|
||||
static void add_cache_pkg(CodeGen *g, CacheHash *ch, PackageTableEntry *pkg) {
|
||||
if (buf_len(&pkg->root_src_path) == 0)
|
||||
return;
|
||||
|
||||
gen_global_asm(g);
|
||||
gen_root_source(g);
|
||||
do_code_gen(g);
|
||||
gen_h_file(g);
|
||||
Buf *rel_full_path = buf_alloc();
|
||||
os_path_join(&pkg->root_src_dir, &pkg->root_src_path, rel_full_path);
|
||||
cache_file(ch, rel_full_path);
|
||||
|
||||
auto it = pkg->package_table.entry_iterator();
|
||||
for (;;) {
|
||||
auto *entry = it.next();
|
||||
if (!entry)
|
||||
break;
|
||||
|
||||
cache_buf(ch, entry->key);
|
||||
add_cache_pkg(g, ch, entry->value);
|
||||
}
|
||||
}
|
||||
|
||||
// Called before init()
|
||||
static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
|
||||
Error err;
|
||||
|
||||
Buf *compiler_id;
|
||||
if ((err = get_compiler_id(&compiler_id)))
|
||||
return err;
|
||||
|
||||
CacheHash *ch = &g->cache_hash;
|
||||
cache_init(ch, manifest_dir);
|
||||
|
||||
add_cache_pkg(g, ch, g->root_package);
|
||||
if (g->linker_script != nullptr) {
|
||||
cache_file(ch, buf_create_from_str(g->linker_script));
|
||||
}
|
||||
cache_buf(ch, compiler_id);
|
||||
cache_buf(ch, g->root_out_name);
|
||||
cache_list_of_link_lib(ch, g->link_libs_list.items, g->link_libs_list.length);
|
||||
cache_list_of_buf(ch, g->darwin_frameworks.items, g->darwin_frameworks.length);
|
||||
cache_list_of_buf(ch, g->rpath_list.items, g->rpath_list.length);
|
||||
cache_list_of_buf(ch, g->forbidden_libs.items, g->forbidden_libs.length);
|
||||
cache_list_of_file(ch, g->link_objects.items, g->link_objects.length);
|
||||
cache_list_of_file(ch, g->assembly_files.items, g->assembly_files.length);
|
||||
cache_int(ch, g->emit_file_type);
|
||||
cache_int(ch, g->build_mode);
|
||||
cache_int(ch, g->out_type);
|
||||
cache_int(ch, g->zig_target.arch.arch);
|
||||
cache_int(ch, g->zig_target.arch.sub_arch);
|
||||
cache_int(ch, g->zig_target.vendor);
|
||||
cache_int(ch, g->zig_target.os);
|
||||
cache_int(ch, g->zig_target.env_type);
|
||||
cache_int(ch, g->zig_target.oformat);
|
||||
cache_bool(ch, g->is_static);
|
||||
cache_bool(ch, g->strip_debug_symbols);
|
||||
cache_bool(ch, g->is_test_build);
|
||||
cache_bool(ch, g->is_native_target);
|
||||
cache_bool(ch, g->windows_subsystem_windows);
|
||||
cache_bool(ch, g->windows_subsystem_console);
|
||||
cache_bool(ch, g->linker_rdynamic);
|
||||
cache_bool(ch, g->no_rosegment_workaround);
|
||||
cache_bool(ch, g->each_lib_rpath);
|
||||
cache_buf_opt(ch, g->mmacosx_version_min);
|
||||
cache_buf_opt(ch, g->mios_version_min);
|
||||
cache_usize(ch, g->version_major);
|
||||
cache_usize(ch, g->version_minor);
|
||||
cache_usize(ch, g->version_patch);
|
||||
cache_buf_opt(ch, g->test_filter);
|
||||
cache_buf_opt(ch, g->test_name_prefix);
|
||||
cache_list_of_str(ch, g->llvm_argv, g->llvm_argv_len);
|
||||
cache_list_of_str(ch, g->clang_argv, g->clang_argv_len);
|
||||
cache_list_of_str(ch, g->lib_dirs.items, g->lib_dirs.length);
|
||||
|
||||
buf_resize(digest, 0);
|
||||
if ((err = cache_hit(ch, digest)))
|
||||
return err;
|
||||
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
static void resolve_out_paths(CodeGen *g) {
|
||||
Buf *o_basename = buf_create_from_buf(g->root_out_name);
|
||||
|
||||
switch (g->emit_file_type) {
|
||||
case EmitFileTypeBinary:
|
||||
{
|
||||
const char *o_ext = target_o_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, o_ext);
|
||||
break;
|
||||
}
|
||||
case EmitFileTypeAssembly:
|
||||
{
|
||||
const char *asm_ext = target_asm_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, asm_ext);
|
||||
break;
|
||||
}
|
||||
case EmitFileTypeLLVMIr:
|
||||
{
|
||||
const char *llvm_ir_ext = target_llvm_ir_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, llvm_ir_ext);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
if (g->enable_cache || g->out_type != OutTypeObj) {
|
||||
os_path_join(&g->artifact_dir, o_basename, &g->o_file_output_path);
|
||||
} else if (g->wanted_output_file_path != nullptr && g->out_type == OutTypeObj) {
|
||||
buf_init_from_buf(&g->o_file_output_path, g->wanted_output_file_path);
|
||||
} else {
|
||||
buf_init_from_buf(&g->o_file_output_path, o_basename);
|
||||
}
|
||||
|
||||
if (g->out_type == OutTypeObj) {
|
||||
buf_init_from_buf(&g->output_file_path, &g->o_file_output_path);
|
||||
} else if (g->out_type == OutTypeExe) {
|
||||
if (!g->enable_cache && g->wanted_output_file_path != nullptr) {
|
||||
buf_init_from_buf(&g->output_file_path, g->wanted_output_file_path);
|
||||
} else {
|
||||
assert(g->root_out_name);
|
||||
|
||||
Buf basename = BUF_INIT;
|
||||
buf_init_from_buf(&basename, g->root_out_name);
|
||||
buf_append_str(&basename, target_exe_file_ext(&g->zig_target));
|
||||
if (g->enable_cache) {
|
||||
os_path_join(&g->artifact_dir, &basename, &g->output_file_path);
|
||||
} else {
|
||||
buf_init_from_buf(&g->output_file_path, &basename);
|
||||
}
|
||||
}
|
||||
} else if (g->out_type == OutTypeLib) {
|
||||
if (!g->enable_cache && g->wanted_output_file_path != nullptr) {
|
||||
buf_init_from_buf(&g->output_file_path, g->wanted_output_file_path);
|
||||
} else {
|
||||
Buf basename = BUF_INIT;
|
||||
buf_init_from_buf(&basename, g->root_out_name);
|
||||
buf_append_str(&basename, target_lib_file_ext(&g->zig_target, g->is_static,
|
||||
g->version_major, g->version_minor, g->version_patch));
|
||||
if (g->enable_cache) {
|
||||
os_path_join(&g->artifact_dir, &basename, &g->output_file_path);
|
||||
} else {
|
||||
buf_init_from_buf(&g->output_file_path, &basename);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
if (g->want_h_file && !g->out_h_path) {
|
||||
assert(g->root_out_name);
|
||||
Buf *h_basename = buf_sprintf("%s.h", buf_ptr(g->root_out_name));
|
||||
if (g->enable_cache) {
|
||||
g->out_h_path = buf_alloc();
|
||||
os_path_join(&g->artifact_dir, h_basename, g->out_h_path);
|
||||
} else {
|
||||
g->out_h_path = h_basename;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void codegen_build_and_link(CodeGen *g) {
|
||||
Error err;
|
||||
assert(g->out_type != OutTypeUnknown);
|
||||
|
||||
Buf *stage1_dir = get_stage1_cache_path();
|
||||
Buf *artifact_dir = buf_alloc();
|
||||
Buf digest = BUF_INIT;
|
||||
if (g->enable_cache) {
|
||||
codegen_add_time_event(g, "Check Cache");
|
||||
|
||||
Buf *manifest_dir = buf_alloc();
|
||||
os_path_join(stage1_dir, buf_create_from_str("build"), manifest_dir);
|
||||
|
||||
if ((err = check_cache(g, manifest_dir, &digest))) {
|
||||
fprintf(stderr, "Unable to check cache: %s\n", err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
os_path_join(stage1_dir, buf_create_from_str("artifact"), artifact_dir);
|
||||
}
|
||||
|
||||
if (g->enable_cache && buf_len(&digest) != 0) {
|
||||
os_path_join(artifact_dir, &digest, &g->artifact_dir);
|
||||
resolve_out_paths(g);
|
||||
} else {
|
||||
init(g);
|
||||
|
||||
codegen_add_time_event(g, "Semantic Analysis");
|
||||
|
||||
gen_global_asm(g);
|
||||
gen_root_source(g);
|
||||
|
||||
if (g->enable_cache) {
|
||||
if ((err = cache_final(&g->cache_hash, &digest))) {
|
||||
fprintf(stderr, "Unable to finalize cache hash: %s\n", err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
os_path_join(artifact_dir, &digest, &g->artifact_dir);
|
||||
} else {
|
||||
buf_init_from_buf(&g->artifact_dir, &g->cache_dir);
|
||||
}
|
||||
if ((err = os_make_path(&g->artifact_dir))) {
|
||||
fprintf(stderr, "Unable to create artifact directory: %s\n", err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
resolve_out_paths(g);
|
||||
|
||||
codegen_add_time_event(g, "Code Generation");
|
||||
do_code_gen(g);
|
||||
codegen_add_time_event(g, "LLVM Emit Output");
|
||||
zig_llvm_emit_output(g);
|
||||
|
||||
if (g->want_h_file) {
|
||||
codegen_add_time_event(g, "Generate .h");
|
||||
gen_h_file(g);
|
||||
}
|
||||
if (g->out_type != OutTypeObj) {
|
||||
codegen_link(g);
|
||||
}
|
||||
}
|
||||
|
||||
if (g->enable_cache) {
|
||||
cache_release(&g->cache_hash);
|
||||
}
|
||||
codegen_add_time_event(g, "Done");
|
||||
}
|
||||
|
||||
PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path) {
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode,
|
||||
Buf *zig_lib_dir);
|
||||
void codegen_destroy(CodeGen *codegen);
|
||||
|
||||
void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len);
|
||||
void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len);
|
||||
|
@ -47,11 +46,12 @@ void codegen_set_linker_script(CodeGen *g, const char *linker_script);
|
|||
void codegen_set_test_filter(CodeGen *g, Buf *filter);
|
||||
void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);
|
||||
void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch);
|
||||
void codegen_set_cache_dir(CodeGen *g, Buf cache_dir);
|
||||
void codegen_set_output_h_path(CodeGen *g, Buf *h_path);
|
||||
void codegen_set_output_path(CodeGen *g, Buf *path);
|
||||
void codegen_add_time_event(CodeGen *g, const char *name);
|
||||
void codegen_print_timing_report(CodeGen *g, FILE *f);
|
||||
void codegen_build(CodeGen *g);
|
||||
void codegen_link(CodeGen *g);
|
||||
void codegen_build_and_link(CodeGen *g);
|
||||
|
||||
PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path);
|
||||
void codegen_add_assembly(CodeGen *g, Buf *path);
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
#include "cache_hash.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static Buf saved_compiler_id = BUF_INIT;
|
||||
static Buf saved_app_data_dir = BUF_INIT;
|
||||
static Buf saved_stage1_path = BUF_INIT;
|
||||
|
||||
Buf *get_stage1_cache_path() {
|
||||
if (saved_stage1_path.list.length != 0) {
|
||||
return &saved_stage1_path;
|
||||
}
|
||||
Error err;
|
||||
if ((err = os_get_app_data_dir(&saved_app_data_dir, "zig"))) {
|
||||
fprintf(stderr, "Unable to get app data dir: %s\n", err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
os_path_join(&saved_app_data_dir, buf_create_from_str("stage1"), &saved_stage1_path);
|
||||
return &saved_stage1_path;
|
||||
}
|
||||
|
||||
Error get_compiler_id(Buf **result) {
|
||||
if (saved_compiler_id.list.length != 0) {
|
||||
*result = &saved_compiler_id;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
Error err;
|
||||
Buf *stage1_dir = get_stage1_cache_path();
|
||||
Buf *manifest_dir = buf_alloc();
|
||||
os_path_join(stage1_dir, buf_create_from_str("exe"), manifest_dir);
|
||||
|
||||
CacheHash cache_hash;
|
||||
CacheHash *ch = &cache_hash;
|
||||
cache_init(ch, manifest_dir);
|
||||
Buf self_exe_path = BUF_INIT;
|
||||
if ((err = os_self_exe_path(&self_exe_path)))
|
||||
return err;
|
||||
|
||||
cache_file(ch, &self_exe_path);
|
||||
|
||||
buf_resize(&saved_compiler_id, 0);
|
||||
if ((err = cache_hit(ch, &saved_compiler_id)))
|
||||
return err;
|
||||
if (buf_len(&saved_compiler_id) != 0) {
|
||||
cache_release(ch);
|
||||
*result = &saved_compiler_id;
|
||||
return ErrorNone;
|
||||
}
|
||||
ZigList<Buf *> lib_paths = {};
|
||||
if ((err = os_self_exe_shared_libs(lib_paths)))
|
||||
return err;
|
||||
for (size_t i = 0; i < lib_paths.length; i += 1) {
|
||||
Buf *lib_path = lib_paths.at(i);
|
||||
if ((err = cache_add_file(ch, lib_path)))
|
||||
return err;
|
||||
}
|
||||
if ((err = cache_final(ch, &saved_compiler_id)))
|
||||
return err;
|
||||
|
||||
cache_release(ch);
|
||||
|
||||
*result = &saved_compiler_id;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Andrew Kelley
|
||||
*
|
||||
* This file is part of zig, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#ifndef ZIG_COMPILER_HPP
|
||||
#define ZIG_COMPILER_HPP
|
||||
|
||||
#include "buffer.hpp"
|
||||
#include "error.hpp"
|
||||
|
||||
Buf *get_stage1_cache_path();
|
||||
Error get_compiler_id(Buf **result);
|
||||
|
||||
#endif
|
|
@ -27,6 +27,11 @@ const char *err_str(int err) {
|
|||
case ErrorNegativeDenominator: return "negative denominator";
|
||||
case ErrorShiftedOutOneBits: return "exact shift shifted out one bits";
|
||||
case ErrorCCompileErrors: return "C compile errors";
|
||||
case ErrorEndOfFile: return "end of file";
|
||||
case ErrorIsDir: return "is directory";
|
||||
case ErrorUnsupportedOperatingSystem: return "unsupported operating system";
|
||||
case ErrorSharingViolation: return "sharing violation";
|
||||
case ErrorPipeBusy: return "pipe busy";
|
||||
}
|
||||
return "(invalid error)";
|
||||
}
|
||||
|
|
|
@ -27,6 +27,11 @@ enum Error {
|
|||
ErrorNegativeDenominator,
|
||||
ErrorShiftedOutOneBits,
|
||||
ErrorCCompileErrors,
|
||||
ErrorEndOfFile,
|
||||
ErrorIsDir,
|
||||
ErrorUnsupportedOperatingSystem,
|
||||
ErrorSharingViolation,
|
||||
ErrorPipeBusy,
|
||||
};
|
||||
|
||||
const char *err_str(int err);
|
||||
|
|
17
src/ir.cpp
17
src/ir.cpp
|
@ -16231,6 +16231,8 @@ static ZigType *ir_analyze_instruction_union_tag(IrAnalyze *ira, IrInstructionUn
|
|||
}
|
||||
|
||||
static ZigType *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructionImport *import_instruction) {
|
||||
Error err;
|
||||
|
||||
IrInstruction *name_value = import_instruction->name->other;
|
||||
Buf *import_target_str = ir_resolve_str(ira, name_value);
|
||||
if (!import_target_str)
|
||||
|
@ -16274,8 +16276,7 @@ static ZigType *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructionImpor
|
|||
return ira->codegen->builtin_types.entry_namespace;
|
||||
}
|
||||
|
||||
int err;
|
||||
if ((err = os_fetch_file_path(resolved_path, import_code, true))) {
|
||||
if ((err = file_fetch(ira->codegen, resolved_path, import_code))) {
|
||||
if (err == ErrorFileNotFound) {
|
||||
ir_add_error_node(ira, source_node,
|
||||
buf_sprintf("unable to find '%s'", buf_ptr(import_target_path)));
|
||||
|
@ -16286,6 +16287,7 @@ static ZigType *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructionImpor
|
|||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
ImportTableEntry *target_import = add_source_file(ira->codegen, target_package, resolved_path, import_code);
|
||||
|
||||
scan_import(ira->codegen, target_import);
|
||||
|
@ -17959,6 +17961,12 @@ static ZigType *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTy
|
|||
}
|
||||
|
||||
static ZigType *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstructionCImport *instruction) {
|
||||
if (ira->codegen->enable_cache) {
|
||||
ir_add_error(ira, &instruction->base,
|
||||
buf_sprintf("TODO @cImport is incompatible with --cache on. The cache system currently is unable to detect subsequent changes in .h files."));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
AstNode *node = instruction->base.source_node;
|
||||
assert(node->type == NodeTypeFnCallExpr);
|
||||
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
|
|||
// load from file system into const expr
|
||||
Buf *file_contents = buf_alloc();
|
||||
int err;
|
||||
if ((err = os_fetch_file_path(&file_path, file_contents, false))) {
|
||||
if ((err = file_fetch(ira->codegen, &file_path, file_contents))) {
|
||||
if (err == ErrorFileNotFound) {
|
||||
ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
@ -18115,9 +18123,6 @@ static ZigType *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstructionE
|
|||
}
|
||||
}
|
||||
|
||||
// TODO add dependency on the file we embedded so that we know if it changes
|
||||
// we'll have to invalidate the cache
|
||||
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
init_const_str_lit(ira->codegen, out_val, file_contents);
|
||||
|
||||
|
|
79
src/link.cpp
79
src/link.cpp
|
@ -5,7 +5,6 @@
|
|||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "link.hpp"
|
||||
#include "os.hpp"
|
||||
#include "config.h"
|
||||
#include "codegen.hpp"
|
||||
|
@ -13,7 +12,6 @@
|
|||
|
||||
struct LinkJob {
|
||||
CodeGen *codegen;
|
||||
Buf out_file;
|
||||
ZigList<const char *> args;
|
||||
bool link_in_crt;
|
||||
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)
|
|||
child_gen->verbose_llvm_ir = parent_gen->verbose_llvm_ir;
|
||||
child_gen->verbose_cimport = parent_gen->verbose_cimport;
|
||||
|
||||
codegen_set_cache_dir(child_gen, parent_gen->cache_dir);
|
||||
|
||||
codegen_set_strip(child_gen, parent_gen->strip_debug_symbols);
|
||||
codegen_set_is_static(child_gen, parent_gen->is_static);
|
||||
|
||||
|
@ -62,16 +58,9 @@ static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path)
|
|||
new_link_lib->provided_explicitly = link_lib->provided_explicitly;
|
||||
}
|
||||
|
||||
codegen_build(child_gen);
|
||||
const char *o_ext = target_o_file_ext(&child_gen->zig_target);
|
||||
Buf *o_out_name = buf_sprintf("%s%s", oname, o_ext);
|
||||
Buf *output_path = buf_alloc();
|
||||
os_path_join(&parent_gen->cache_dir, o_out_name, output_path);
|
||||
codegen_link(child_gen, buf_ptr(output_path));
|
||||
|
||||
codegen_destroy(child_gen);
|
||||
|
||||
return output_path;
|
||||
child_gen->enable_cache = true;
|
||||
codegen_build_and_link(child_gen);
|
||||
return &child_gen->output_file_path;
|
||||
}
|
||||
|
||||
static Buf *build_o(CodeGen *parent_gen, const char *oname) {
|
||||
|
@ -239,15 +228,15 @@ static void construct_linker_job_elf(LinkJob *lj) {
|
|||
} else if (shared) {
|
||||
lj->args.append("-shared");
|
||||
|
||||
if (buf_len(&lj->out_file) == 0) {
|
||||
buf_appendf(&lj->out_file, "lib%s.so.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize "",
|
||||
if (buf_len(&g->output_file_path) == 0) {
|
||||
buf_appendf(&g->output_file_path, "lib%s.so.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize "",
|
||||
buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch);
|
||||
}
|
||||
soname = buf_sprintf("lib%s.so.%" ZIG_PRI_usize "", buf_ptr(g->root_out_name), g->version_major);
|
||||
}
|
||||
|
||||
lj->args.append("-o");
|
||||
lj->args.append(buf_ptr(&lj->out_file));
|
||||
lj->args.append(buf_ptr(&g->output_file_path));
|
||||
|
||||
if (lj->link_in_crt) {
|
||||
const char *crt1o;
|
||||
|
@ -399,7 +388,7 @@ static void construct_linker_job_wasm(LinkJob *lj) {
|
|||
|
||||
lj->args.append("--relocatable"); // So lld doesn't look for _start.
|
||||
lj->args.append("-o");
|
||||
lj->args.append(buf_ptr(&lj->out_file));
|
||||
lj->args.append(buf_ptr(&g->output_file_path));
|
||||
|
||||
// .o files
|
||||
for (size_t i = 0; i < g->link_objects.length; i += 1) {
|
||||
|
@ -480,7 +469,7 @@ static void construct_linker_job_coff(LinkJob *lj) {
|
|||
// }
|
||||
//}
|
||||
|
||||
lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&lj->out_file))));
|
||||
lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path))));
|
||||
|
||||
if (g->libc_link_lib != nullptr) {
|
||||
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) {
|
|||
buf_appendf(def_contents, "\n");
|
||||
|
||||
Buf *def_path = buf_alloc();
|
||||
os_path_join(&g->cache_dir, buf_sprintf("%s.def", buf_ptr(link_lib->name)), def_path);
|
||||
os_path_join(&g->artifact_dir, buf_sprintf("%s.def", buf_ptr(link_lib->name)), def_path);
|
||||
os_write_file(def_path, def_contents);
|
||||
|
||||
Buf *generated_lib_path = buf_alloc();
|
||||
os_path_join(&g->cache_dir, buf_sprintf("%s.lib", buf_ptr(link_lib->name)), generated_lib_path);
|
||||
os_path_join(&g->artifact_dir, buf_sprintf("%s.lib", buf_ptr(link_lib->name)), generated_lib_path);
|
||||
|
||||
gen_lib_args.resize(0);
|
||||
gen_lib_args.append("link");
|
||||
|
@ -799,8 +788,8 @@ static void construct_linker_job_macho(LinkJob *lj) {
|
|||
//lj->args.append("-install_name");
|
||||
//lj->args.append(buf_ptr(dylib_install_name));
|
||||
|
||||
if (buf_len(&lj->out_file) == 0) {
|
||||
buf_appendf(&lj->out_file, "lib%s.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".dylib",
|
||||
if (buf_len(&g->output_file_path) == 0) {
|
||||
buf_appendf(&g->output_file_path, "lib%s.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".dylib",
|
||||
buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch);
|
||||
}
|
||||
}
|
||||
|
@ -834,13 +823,13 @@ static void construct_linker_job_macho(LinkJob *lj) {
|
|||
}
|
||||
|
||||
lj->args.append("-o");
|
||||
lj->args.append(buf_ptr(&lj->out_file));
|
||||
lj->args.append(buf_ptr(&g->output_file_path));
|
||||
|
||||
for (size_t i = 0; i < g->rpath_list.length; i += 1) {
|
||||
Buf *rpath = g->rpath_list.at(i);
|
||||
add_rpath(lj, rpath);
|
||||
}
|
||||
add_rpath(lj, &lj->out_file);
|
||||
add_rpath(lj, &g->output_file_path);
|
||||
|
||||
if (shared) {
|
||||
lj->args.append("-headerpad_max_install_names");
|
||||
|
@ -944,7 +933,8 @@ static void construct_linker_job(LinkJob *lj) {
|
|||
}
|
||||
}
|
||||
|
||||
void codegen_link(CodeGen *g, const char *out_file) {
|
||||
void codegen_link(CodeGen *g) {
|
||||
assert(g->out_type != OutTypeObj);
|
||||
codegen_add_time_event(g, "Build Dependencies");
|
||||
|
||||
LinkJob lj = {0};
|
||||
|
@ -955,11 +945,6 @@ void codegen_link(CodeGen *g, const char *out_file) {
|
|||
|
||||
lj.rpath_table.init(4);
|
||||
lj.codegen = g;
|
||||
if (out_file) {
|
||||
buf_init_from_str(&lj.out_file, out_file);
|
||||
} else {
|
||||
buf_resize(&lj.out_file, 0);
|
||||
}
|
||||
|
||||
if (g->verbose_llvm_ir) {
|
||||
fprintf(stderr, "\nOptimization:\n");
|
||||
|
@ -968,35 +953,9 @@ void codegen_link(CodeGen *g, const char *out_file) {
|
|||
LLVMDumpModule(g->module);
|
||||
}
|
||||
|
||||
bool override_out_file = (buf_len(&lj.out_file) != 0);
|
||||
if (!override_out_file) {
|
||||
assert(g->root_out_name);
|
||||
|
||||
buf_init_from_buf(&lj.out_file, g->root_out_name);
|
||||
if (g->out_type == OutTypeExe) {
|
||||
buf_append_str(&lj.out_file, target_exe_file_ext(&g->zig_target));
|
||||
}
|
||||
}
|
||||
|
||||
if (g->out_type == OutTypeObj) {
|
||||
if (override_out_file) {
|
||||
assert(g->link_objects.length == 1);
|
||||
Buf *o_file_path = g->link_objects.at(0);
|
||||
int err;
|
||||
if ((err = os_rename(o_file_path, &lj.out_file))) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (g->out_type == OutTypeLib && g->is_static) {
|
||||
// invoke `ar`
|
||||
// example:
|
||||
// # static link into libfoo.a
|
||||
// ar rcs libfoo.a foo1.o foo2.o
|
||||
zig_panic("TODO invoke ar");
|
||||
return;
|
||||
fprintf(stderr, "Zig does not yet support creating static libraries\nSee https://github.com/ziglang/zig/issues/1493\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
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) {
|
|||
fprintf(stderr, "%s\n", buf_ptr(&diag));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
codegen_add_time_event(g, "Done");
|
||||
}
|
||||
|
|
17
src/link.hpp
17
src/link.hpp
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Andrew Kelley
|
||||
*
|
||||
* This file is part of zig, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#ifndef ZIG_LINK_HPP
|
||||
#define ZIG_LINK_HPP
|
||||
|
||||
#include "all_types.hpp"
|
||||
|
||||
void codegen_link(CodeGen *g, const char *out_file);
|
||||
|
||||
|
||||
#endif
|
||||
|
149
src/main.cpp
149
src/main.cpp
|
@ -8,9 +8,9 @@
|
|||
#include "ast_render.hpp"
|
||||
#include "buffer.hpp"
|
||||
#include "codegen.hpp"
|
||||
#include "compiler.hpp"
|
||||
#include "config.h"
|
||||
#include "error.hpp"
|
||||
#include "link.hpp"
|
||||
#include "os.hpp"
|
||||
#include "target.hpp"
|
||||
|
||||
|
@ -24,6 +24,7 @@ static int usage(const char *arg0) {
|
|||
" build-lib [source] create library from source or object files\n"
|
||||
" build-obj [source] create object from source or assembly\n"
|
||||
" builtin show the source code of that @import(\"builtin\")\n"
|
||||
" id print the base64-encoded compiler id\n"
|
||||
" run [source] create executable and run immediately\n"
|
||||
" translate-c [source] convert c code to zig code\n"
|
||||
" targets list available compilation targets\n"
|
||||
|
@ -33,9 +34,10 @@ static int usage(const char *arg0) {
|
|||
"Compile Options:\n"
|
||||
" --assembly [source] add assembly file to build\n"
|
||||
" --cache-dir [path] override the cache directory\n"
|
||||
" --cache [auto|off|on] build to the global cache and print output path to stdout\n"
|
||||
" --color [auto|off|on] enable or disable colored error messages\n"
|
||||
" --emit [asm|bin|llvm-ir] emit a specific file format as compilation output\n"
|
||||
" --enable-timing-info print timing diagnostics\n"
|
||||
" -ftime-report print timing diagnostics\n"
|
||||
" --libc-include-dir [path] directory where libc stdlib.h resides\n"
|
||||
" --name [name] override output name\n"
|
||||
" --output [file] override destination path\n"
|
||||
|
@ -256,6 +258,24 @@ static void add_package(CodeGen *g, CliPkg *cli_pkg, PackageTableEntry *pkg) {
|
|||
}
|
||||
}
|
||||
|
||||
enum CacheOpt {
|
||||
CacheOptAuto,
|
||||
CacheOptOn,
|
||||
CacheOptOff,
|
||||
};
|
||||
|
||||
static bool get_cache_opt(CacheOpt opt, bool default_value) {
|
||||
switch (opt) {
|
||||
case CacheOptAuto:
|
||||
return default_value;
|
||||
case CacheOptOn:
|
||||
return true;
|
||||
case CacheOptOff:
|
||||
return false;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc == 2 && strcmp(argv[1], "BUILD_INFO") == 0) {
|
||||
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) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (argc == 2 && strcmp(argv[1], "id") == 0) {
|
||||
Error err;
|
||||
Buf *compiler_id;
|
||||
if ((err = get_compiler_id(&compiler_id))) {
|
||||
fprintf(stderr, "Unable to determine compiler id: %s\n", err_str(err));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
printf("%s\n", buf_ptr(compiler_id));
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
os_init();
|
||||
|
||||
char *arg0 = argv[0];
|
||||
|
@ -289,6 +320,7 @@ int main(int argc, char **argv) {
|
|||
bool verbose_llvm_ir = false;
|
||||
bool verbose_cimport = false;
|
||||
ErrColor color = ErrColorAuto;
|
||||
CacheOpt enable_cache = CacheOptAuto;
|
||||
const char *libc_lib_dir = nullptr;
|
||||
const char *libc_static_lib_dir = nullptr;
|
||||
const char *libc_include_dir = nullptr;
|
||||
|
@ -325,8 +357,7 @@ int main(int argc, char **argv) {
|
|||
CliPkg *cur_pkg = allocate<CliPkg>(1);
|
||||
BuildMode build_mode = BuildModeDebug;
|
||||
ZigList<const char *> test_exec_args = {0};
|
||||
int comptime_args_end = 0;
|
||||
int runtime_args_start = argc;
|
||||
int runtime_args_start = -1;
|
||||
bool no_rosegment_workaround = false;
|
||||
|
||||
if (argc >= 2 && strcmp(argv[1], "build") == 0) {
|
||||
|
@ -370,8 +401,9 @@ int main(int argc, char **argv) {
|
|||
Buf *build_runner_path = buf_alloc();
|
||||
os_path_join(special_dir, buf_create_from_str("build_runner.zig"), build_runner_path);
|
||||
|
||||
|
||||
CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, zig_lib_dir_buf);
|
||||
g->enable_time_report = timing_info;
|
||||
buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name);
|
||||
codegen_set_out_name(g, buf_create_from_str("build"));
|
||||
|
||||
Buf *build_file_buf = buf_create_from_str(build_file);
|
||||
|
@ -380,6 +412,7 @@ int main(int argc, char **argv) {
|
|||
Buf build_file_dirname = BUF_INIT;
|
||||
os_path_split(&build_file_abs, &build_file_dirname, &build_file_basename);
|
||||
|
||||
|
||||
Buf full_cache_dir = BUF_INIT;
|
||||
if (cache_dir == nullptr) {
|
||||
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) {
|
|||
full_cache_dir = os_path_resolve(&cache_dir_buf, 1);
|
||||
}
|
||||
|
||||
Buf *path_to_build_exe = buf_alloc();
|
||||
os_path_join(&full_cache_dir, buf_create_from_str("build"), path_to_build_exe);
|
||||
codegen_set_cache_dir(g, full_cache_dir);
|
||||
|
||||
args.items[1] = buf_ptr(&build_file_dirname);
|
||||
args.items[2] = buf_ptr(&full_cache_dir);
|
||||
|
||||
|
@ -459,15 +488,14 @@ int main(int argc, char **argv) {
|
|||
PackageTableEntry *build_pkg = codegen_create_package(g, buf_ptr(&build_file_dirname),
|
||||
buf_ptr(&build_file_basename));
|
||||
g->root_package->package_table.put(buf_create_from_str("@build"), build_pkg);
|
||||
codegen_build(g);
|
||||
codegen_link(g, buf_ptr(path_to_build_exe));
|
||||
codegen_destroy(g);
|
||||
g->enable_cache = get_cache_opt(enable_cache, true);
|
||||
codegen_build_and_link(g);
|
||||
|
||||
Termination term;
|
||||
os_spawn_process(buf_ptr(path_to_build_exe), args, &term);
|
||||
os_spawn_process(buf_ptr(&g->output_file_path), args, &term);
|
||||
if (term.how != TerminationIdClean || term.code != 0) {
|
||||
fprintf(stderr, "\nBuild failed. The following command failed:\n");
|
||||
fprintf(stderr, "%s", buf_ptr(path_to_build_exe));
|
||||
fprintf(stderr, "%s", buf_ptr(&g->output_file_path));
|
||||
for (size_t i = 0; i < args.length; i += 1) {
|
||||
fprintf(stderr, " %s", args.at(i));
|
||||
}
|
||||
|
@ -476,15 +504,11 @@ int main(int argc, char **argv) {
|
|||
return (term.how == TerminationIdClean) ? term.code : -1;
|
||||
}
|
||||
|
||||
for (int i = 1; i < argc; i += 1, comptime_args_end += 1) {
|
||||
for (int i = 1; i < argc; i += 1) {
|
||||
char *arg = argv[i];
|
||||
|
||||
if (arg[0] == '-') {
|
||||
if (strcmp(arg, "--") == 0) {
|
||||
// ignore -- from both compile and runtime arg sets
|
||||
runtime_args_start = i + 1;
|
||||
break;
|
||||
} else if (strcmp(arg, "--release-fast") == 0) {
|
||||
if (strcmp(arg, "--release-fast") == 0) {
|
||||
build_mode = BuildModeFastRelease;
|
||||
} else if (strcmp(arg, "--release-safe") == 0) {
|
||||
build_mode = BuildModeSafeRelease;
|
||||
|
@ -516,7 +540,7 @@ int main(int argc, char **argv) {
|
|||
no_rosegment_workaround = true;
|
||||
} else if (strcmp(arg, "--each-lib-rpath") == 0) {
|
||||
each_lib_rpath = true;
|
||||
} else if (strcmp(arg, "--enable-timing-info") == 0) {
|
||||
} else if (strcmp(arg, "-ftime-report") == 0) {
|
||||
timing_info = true;
|
||||
} else if (strcmp(arg, "--test-cmd-bin") == 0) {
|
||||
test_exec_args.append(nullptr);
|
||||
|
@ -562,6 +586,17 @@ int main(int argc, char **argv) {
|
|||
fprintf(stderr, "--color options are 'auto', 'on', or 'off'\n");
|
||||
return usage(arg0);
|
||||
}
|
||||
} else if (strcmp(arg, "--cache") == 0) {
|
||||
if (strcmp(argv[i], "auto") == 0) {
|
||||
enable_cache = CacheOptAuto;
|
||||
} else if (strcmp(argv[i], "on") == 0) {
|
||||
enable_cache = CacheOptOn;
|
||||
} else if (strcmp(argv[i], "off") == 0) {
|
||||
enable_cache = CacheOptOff;
|
||||
} else {
|
||||
fprintf(stderr, "--cache options are 'auto', 'on', or 'off'\n");
|
||||
return usage(arg0);
|
||||
}
|
||||
} else if (strcmp(arg, "--emit") == 0) {
|
||||
if (strcmp(argv[i], "asm") == 0) {
|
||||
emit_file_type = EmitFileTypeAssembly;
|
||||
|
@ -681,6 +716,10 @@ int main(int argc, char **argv) {
|
|||
case CmdTest:
|
||||
if (!in_file) {
|
||||
in_file = arg;
|
||||
if (cmd == CmdRun) {
|
||||
runtime_args_start = i + 1;
|
||||
break; // rest of the args are for the program
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Unexpected extra parameter: %s\n", arg);
|
||||
return usage(arg0);
|
||||
|
@ -790,32 +829,18 @@ int main(int argc, char **argv) {
|
|||
|
||||
Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf;
|
||||
|
||||
Buf full_cache_dir = BUF_INIT;
|
||||
Buf *run_exec_path = buf_alloc();
|
||||
if (cmd == CmdRun) {
|
||||
if (buf_out_name == nullptr) {
|
||||
buf_out_name = buf_create_from_str("run");
|
||||
}
|
||||
|
||||
Buf *global_cache_dir = buf_alloc();
|
||||
os_get_global_cache_directory(global_cache_dir);
|
||||
os_path_join(global_cache_dir, buf_out_name, run_exec_path);
|
||||
full_cache_dir = os_path_resolve(&global_cache_dir, 1);
|
||||
|
||||
out_file = buf_ptr(run_exec_path);
|
||||
} else {
|
||||
Buf *resolve_paths = buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir);
|
||||
full_cache_dir = os_path_resolve(&resolve_paths, 1);
|
||||
if (cmd == CmdRun && buf_out_name == nullptr) {
|
||||
buf_out_name = buf_create_from_str("run");
|
||||
}
|
||||
|
||||
Buf *zig_lib_dir_buf = resolve_zig_lib_dir();
|
||||
|
||||
CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, zig_lib_dir_buf);
|
||||
g->enable_time_report = timing_info;
|
||||
buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name);
|
||||
codegen_set_out_name(g, buf_out_name);
|
||||
codegen_set_lib_version(g, ver_major, ver_minor, ver_patch);
|
||||
codegen_set_is_test(g, cmd == CmdTest);
|
||||
codegen_set_linker_script(g, linker_script);
|
||||
codegen_set_cache_dir(g, full_cache_dir);
|
||||
if (each_lib_rpath)
|
||||
codegen_set_each_lib_rpath(g, each_lib_rpath);
|
||||
|
||||
|
@ -885,6 +910,8 @@ int main(int argc, char **argv) {
|
|||
codegen_set_test_name_prefix(g, buf_create_from_str(test_name_prefix));
|
||||
}
|
||||
|
||||
if (out_file)
|
||||
codegen_set_output_path(g, buf_create_from_str(out_file));
|
||||
if (out_file_h)
|
||||
codegen_set_output_h_path(g, buf_create_from_str(out_file_h));
|
||||
|
||||
|
@ -904,8 +931,8 @@ int main(int argc, char **argv) {
|
|||
if (cmd == CmdBuild || cmd == CmdRun) {
|
||||
codegen_set_emit_file_type(g, emit_file_type);
|
||||
|
||||
codegen_build(g);
|
||||
codegen_link(g, out_file);
|
||||
g->enable_cache = get_cache_opt(enable_cache, cmd == CmdRun);
|
||||
codegen_build_and_link(g);
|
||||
if (timing_info)
|
||||
codegen_print_timing_report(g, stdout);
|
||||
|
||||
|
@ -915,12 +942,26 @@ int main(int argc, char **argv) {
|
|||
args.append(argv[i]);
|
||||
}
|
||||
|
||||
Termination term;
|
||||
os_spawn_process(buf_ptr(run_exec_path), args, &term);
|
||||
return term.code;
|
||||
}
|
||||
const char *exec_path = buf_ptr(&g->output_file_path);
|
||||
args.append(nullptr);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
os_execv(exec_path, args.items);
|
||||
|
||||
args.pop();
|
||||
Termination term;
|
||||
os_spawn_process(exec_path, args, &term);
|
||||
return term.code;
|
||||
} else if (cmd == CmdBuild) {
|
||||
if (g->enable_cache) {
|
||||
printf("%s\n", buf_ptr(&g->output_file_path));
|
||||
if (g->out_h_path != nullptr) {
|
||||
printf("%s\n", buf_ptr(g->out_h_path));
|
||||
}
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
} else if (cmd == CmdTranslateC) {
|
||||
codegen_translate_c(g, in_file_buf);
|
||||
ast_render(g, stdout, g->root_import->root, 4);
|
||||
|
@ -933,11 +974,16 @@ int main(int argc, char **argv) {
|
|||
ZigTarget native;
|
||||
get_native_target(&native);
|
||||
|
||||
ZigTarget *non_null_target = target ? target : &native;
|
||||
g->enable_cache = get_cache_opt(enable_cache, false);
|
||||
codegen_build_and_link(g);
|
||||
|
||||
Buf *test_exe_name = buf_sprintf("test%s", target_exe_file_ext(non_null_target));
|
||||
if (timing_info) {
|
||||
codegen_print_timing_report(g, stdout);
|
||||
}
|
||||
|
||||
Buf *test_exe_path_unresolved = &g->output_file_path;
|
||||
Buf *test_exe_path = buf_alloc();
|
||||
os_path_join(&full_cache_dir, test_exe_name, test_exe_path);
|
||||
*test_exe_path = os_path_resolve(&test_exe_path_unresolved, 1);
|
||||
|
||||
for (size_t i = 0; i < test_exec_args.length; i += 1) {
|
||||
if (test_exec_args.items[i] == nullptr) {
|
||||
|
@ -945,9 +991,6 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
}
|
||||
|
||||
codegen_build(g);
|
||||
codegen_link(g, buf_ptr(test_exe_path));
|
||||
|
||||
if (!target_can_exec(&native, target)) {
|
||||
fprintf(stderr, "Created %s but skipping execution because it is non-native.\n",
|
||||
buf_ptr(test_exe_path));
|
||||
|
@ -969,8 +1012,6 @@ int main(int argc, char **argv) {
|
|||
if (term.how != TerminationIdClean || term.code != 0) {
|
||||
fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n");
|
||||
fprintf(stderr, "%s\n", buf_ptr(test_exe_path));
|
||||
} else if (timing_info) {
|
||||
codegen_print_timing_report(g, stdout);
|
||||
}
|
||||
return (term.how == TerminationIdClean) ? term.code : -1;
|
||||
} else {
|
||||
|
|
599
src/os.cpp
599
src/os.cpp
|
@ -24,6 +24,7 @@
|
|||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
@ -40,6 +41,10 @@ typedef SSIZE_T ssize_t;
|
|||
|
||||
#endif
|
||||
|
||||
#if defined(ZIG_OS_LINUX)
|
||||
#include <link.h>
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__MACH__)
|
||||
#include <mach/clock.h>
|
||||
|
@ -57,54 +62,6 @@ static clock_serv_t cclock;
|
|||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
// Ported from std/mem.zig.
|
||||
// Coordinate struct fields with memSplit function
|
||||
struct SplitIterator {
|
||||
size_t index;
|
||||
Slice<uint8_t> buffer;
|
||||
Slice<uint8_t> split_bytes;
|
||||
};
|
||||
|
||||
// Ported from std/mem.zig.
|
||||
static bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte) {
|
||||
for (size_t i = 0; i < self->split_bytes.len; i += 1) {
|
||||
if (byte == self->split_bytes.ptr[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ported from std/mem.zig.
|
||||
static Optional<Slice<uint8_t>> SplitIterator_next(SplitIterator *self) {
|
||||
// move to beginning of token
|
||||
while (self->index < self->buffer.len &&
|
||||
SplitIterator_isSplitByte(self, self->buffer.ptr[self->index]))
|
||||
{
|
||||
self->index += 1;
|
||||
}
|
||||
size_t start = self->index;
|
||||
if (start == self->buffer.len) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// move to end of token
|
||||
while (self->index < self->buffer.len &&
|
||||
!SplitIterator_isSplitByte(self, self->buffer.ptr[self->index]))
|
||||
{
|
||||
self->index += 1;
|
||||
}
|
||||
size_t end = self->index;
|
||||
|
||||
return Optional<Slice<uint8_t>>::some(self->buffer.slice(start, end));
|
||||
}
|
||||
|
||||
// Ported from std/mem.zig
|
||||
static SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes) {
|
||||
return SplitIterator{0, buffer, split_bytes};
|
||||
}
|
||||
|
||||
|
||||
#if defined(ZIG_OS_POSIX)
|
||||
static void populate_termination(Termination *term, int status) {
|
||||
if (WIFEXITED(status)) {
|
||||
|
@ -765,7 +722,7 @@ Buf os_path_resolve(Buf **paths_ptr, size_t paths_len) {
|
|||
#endif
|
||||
}
|
||||
|
||||
int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) {
|
||||
Error os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) {
|
||||
static const ssize_t buf_size = 0x2000;
|
||||
buf_resize(out_buf, buf_size);
|
||||
ssize_t actual_buf_len = 0;
|
||||
|
@ -801,7 +758,7 @@ int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) {
|
|||
if (amt_read != buf_size) {
|
||||
if (feof(f)) {
|
||||
buf_resize(out_buf, actual_buf_len);
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
} else {
|
||||
return ErrorFileSystem;
|
||||
}
|
||||
|
@ -813,13 +770,13 @@ int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) {
|
|||
zig_unreachable();
|
||||
}
|
||||
|
||||
int os_file_exists(Buf *full_path, bool *result) {
|
||||
Error os_file_exists(Buf *full_path, bool *result) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
*result = GetFileAttributes(buf_ptr(full_path)) != INVALID_FILE_ATTRIBUTES;
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
#else
|
||||
*result = access(buf_ptr(full_path), F_OK) != -1;
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -878,13 +835,15 @@ static int os_exec_process_posix(const char *exe, ZigList<const char *> &args,
|
|||
|
||||
FILE *stdout_f = fdopen(stdout_pipe[0], "rb");
|
||||
FILE *stderr_f = fdopen(stderr_pipe[0], "rb");
|
||||
os_fetch_file(stdout_f, out_stdout, false);
|
||||
os_fetch_file(stderr_f, out_stderr, false);
|
||||
Error err1 = os_fetch_file(stdout_f, out_stdout, false);
|
||||
Error err2 = os_fetch_file(stderr_f, out_stderr, false);
|
||||
|
||||
fclose(stdout_f);
|
||||
fclose(stderr_f);
|
||||
|
||||
return 0;
|
||||
if (err1) return err1;
|
||||
if (err2) return err2;
|
||||
return ErrorNone;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1016,6 +975,22 @@ static int os_exec_process_windows(const char *exe, ZigList<const char *> &args,
|
|||
}
|
||||
#endif
|
||||
|
||||
Error os_execv(const char *exe, const char **argv) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
return ErrorUnsupportedOperatingSystem;
|
||||
#else
|
||||
execv(exe, (char *const *)argv);
|
||||
switch (errno) {
|
||||
case ENOMEM:
|
||||
return ErrorSystemResources;
|
||||
case EIO:
|
||||
return ErrorFileSystem;
|
||||
default:
|
||||
return ErrorUnexpected;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int os_exec_process(const char *exe, ZigList<const char *> &args,
|
||||
Termination *term, Buf *out_stderr, Buf *out_stdout)
|
||||
{
|
||||
|
@ -1092,7 +1067,7 @@ int os_copy_file(Buf *src_path, Buf *dest_path) {
|
|||
}
|
||||
}
|
||||
|
||||
int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) {
|
||||
Error os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) {
|
||||
FILE *f = fopen(buf_ptr(full_path), "rb");
|
||||
if (!f) {
|
||||
switch (errno) {
|
||||
|
@ -1111,7 +1086,7 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) {
|
|||
return ErrorFileSystem;
|
||||
}
|
||||
}
|
||||
int result = os_fetch_file(f, out_contents, skip_shebang);
|
||||
Error result = os_fetch_file(f, out_contents, skip_shebang);
|
||||
fclose(f);
|
||||
return result;
|
||||
}
|
||||
|
@ -1282,44 +1257,6 @@ int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path) {
|
|||
#endif
|
||||
}
|
||||
|
||||
#if defined(ZIG_OS_POSIX)
|
||||
int os_get_global_cache_directory(Buf *out_tmp_path) {
|
||||
const char *tmp_dir = getenv("TMPDIR");
|
||||
if (!tmp_dir) {
|
||||
tmp_dir = P_tmpdir;
|
||||
}
|
||||
|
||||
Buf *tmp_dir_buf = buf_create_from_str(tmp_dir);
|
||||
Buf *cache_dirname_buf = buf_create_from_str("zig-cache");
|
||||
|
||||
buf_resize(out_tmp_path, 0);
|
||||
os_path_join(tmp_dir_buf, cache_dirname_buf, out_tmp_path);
|
||||
|
||||
buf_deinit(tmp_dir_buf);
|
||||
buf_deinit(cache_dirname_buf);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
int os_get_global_cache_directory(Buf *out_tmp_path) {
|
||||
char tmp_dir[MAX_PATH + 1];
|
||||
if (GetTempPath(MAX_PATH, tmp_dir) == 0) {
|
||||
zig_panic("GetTempPath failed");
|
||||
}
|
||||
|
||||
Buf *tmp_dir_buf = buf_create_from_str(tmp_dir);
|
||||
Buf *cache_dirname_buf = buf_create_from_str("zig-cache");
|
||||
|
||||
buf_resize(out_tmp_path, 0);
|
||||
os_path_join(tmp_dir_buf, cache_dirname_buf, out_tmp_path);
|
||||
|
||||
buf_deinit(tmp_dir_buf);
|
||||
buf_deinit(cache_dirname_buf);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int os_delete_file(Buf *path) {
|
||||
if (remove(buf_ptr(path))) {
|
||||
return ErrorFileSystem;
|
||||
|
@ -1368,16 +1305,16 @@ double os_get_time(void) {
|
|||
#endif
|
||||
}
|
||||
|
||||
int os_make_path(Buf *path) {
|
||||
Error os_make_path(Buf *path) {
|
||||
Buf resolved_path = os_path_resolve(&path, 1);
|
||||
|
||||
size_t end_index = buf_len(&resolved_path);
|
||||
int err;
|
||||
Error err;
|
||||
while (true) {
|
||||
if ((err = os_make_dir(buf_slice(&resolved_path, 0, end_index)))) {
|
||||
if (err == ErrorPathAlreadyExists) {
|
||||
if (end_index == buf_len(&resolved_path))
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
} else if (err == ErrorFileNotFound) {
|
||||
// march end_index backward until next path component
|
||||
while (true) {
|
||||
|
@ -1391,7 +1328,7 @@ int os_make_path(Buf *path) {
|
|||
}
|
||||
}
|
||||
if (end_index == buf_len(&resolved_path))
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
// march end_index forward until next path component
|
||||
while (true) {
|
||||
end_index += 1;
|
||||
|
@ -1399,10 +1336,10 @@ int os_make_path(Buf *path) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
int os_make_dir(Buf *path) {
|
||||
Error os_make_dir(Buf *path) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
if (!CreateDirectory(buf_ptr(path), NULL)) {
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
||||
|
@ -1413,7 +1350,7 @@ int os_make_dir(Buf *path) {
|
|||
return ErrorAccess;
|
||||
return ErrorUnexpected;
|
||||
}
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
#else
|
||||
if (mkdir(buf_ptr(path), 0755) == -1) {
|
||||
if (errno == EEXIST)
|
||||
|
@ -1424,7 +1361,7 @@ int os_make_dir(Buf *path) {
|
|||
return ErrorAccess;
|
||||
return ErrorUnexpected;
|
||||
}
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1447,7 +1384,7 @@ int os_init(void) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int os_self_exe_path(Buf *out_path) {
|
||||
Error os_self_exe_path(Buf *out_path) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
buf_resize(out_path, 256);
|
||||
for (;;) {
|
||||
|
@ -1457,7 +1394,7 @@ int os_self_exe_path(Buf *out_path) {
|
|||
}
|
||||
if (copied_amt < buf_len(out_path)) {
|
||||
buf_resize(out_path, copied_amt);
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
}
|
||||
buf_resize(out_path, buf_len(out_path) * 2);
|
||||
}
|
||||
|
@ -1480,27 +1417,21 @@ int os_self_exe_path(Buf *out_path) {
|
|||
char *real_path = realpath(buf_ptr(tmp), buf_ptr(out_path));
|
||||
if (!real_path) {
|
||||
buf_init_from_buf(out_path, tmp);
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
// Resize out_path for the correct length.
|
||||
buf_resize(out_path, strlen(buf_ptr(out_path)));
|
||||
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
#elif defined(ZIG_OS_LINUX)
|
||||
buf_resize(out_path, 256);
|
||||
for (;;) {
|
||||
ssize_t amt = readlink("/proc/self/exe", buf_ptr(out_path), buf_len(out_path));
|
||||
if (amt == -1) {
|
||||
return ErrorUnexpected;
|
||||
}
|
||||
if (amt == (ssize_t)buf_len(out_path)) {
|
||||
buf_resize(out_path, buf_len(out_path) * 2);
|
||||
continue;
|
||||
}
|
||||
buf_resize(out_path, amt);
|
||||
return 0;
|
||||
buf_resize(out_path, PATH_MAX);
|
||||
ssize_t amt = readlink("/proc/self/exe", buf_ptr(out_path), buf_len(out_path));
|
||||
if (amt == -1) {
|
||||
return ErrorUnexpected;
|
||||
}
|
||||
buf_resize(out_path, amt);
|
||||
return ErrorNone;
|
||||
#endif
|
||||
return ErrorFileNotFound;
|
||||
}
|
||||
|
@ -1685,3 +1616,431 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchTy
|
|||
return ErrorFileNotFound;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
// Ported from std/unicode.zig
|
||||
struct Utf16LeIterator {
|
||||
uint8_t *bytes;
|
||||
size_t i;
|
||||
};
|
||||
|
||||
// Ported from std/unicode.zig
|
||||
static Utf16LeIterator Utf16LeIterator_init(WCHAR *ptr) {
|
||||
return {(uint8_t*)ptr, 0};
|
||||
}
|
||||
|
||||
// Ported from std/unicode.zig
|
||||
static Optional<uint32_t> Utf16LeIterator_nextCodepoint(Utf16LeIterator *it) {
|
||||
if (it->bytes[it->i] == 0 && it->bytes[it->i + 1] == 0)
|
||||
return {};
|
||||
uint32_t c0 = ((uint32_t)it->bytes[it->i]) | (((uint32_t)it->bytes[it->i + 1]) << 8);
|
||||
if (c0 & ~((uint32_t)0x03ff) == 0xd800) {
|
||||
// surrogate pair
|
||||
it->i += 2;
|
||||
assert(it->bytes[it->i] != 0 || it->bytes[it->i + 1] != 0);
|
||||
uint32_t c1 = ((uint32_t)it->bytes[it->i]) | (((uint32_t)it->bytes[it->i + 1]) << 8);
|
||||
assert(c1 & ~((uint32_t)0x03ff) == 0xdc00);
|
||||
it->i += 2;
|
||||
return Optional<uint32_t>::some(0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff)));
|
||||
} else {
|
||||
assert(c0 & ~((uint32_t)0x03ff) != 0xdc00);
|
||||
it->i += 2;
|
||||
return Optional<uint32_t>::some(c0);
|
||||
}
|
||||
}
|
||||
|
||||
// Ported from std/unicode.zig
|
||||
static uint8_t utf8CodepointSequenceLength(uint32_t c) {
|
||||
if (c < 0x80) return 1;
|
||||
if (c < 0x800) return 2;
|
||||
if (c < 0x10000) return 3;
|
||||
if (c < 0x110000) return 4;
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
// Ported from std/unicode.zig
|
||||
static size_t utf8Encode(uint32_t c, Slice<uint8_t> out) {
|
||||
size_t length = utf8CodepointSequenceLength(c);
|
||||
assert(out.len >= length);
|
||||
switch (length) {
|
||||
// The pattern for each is the same
|
||||
// - Increasing the initial shift by 6 each time
|
||||
// - Each time after the first shorten the shifted
|
||||
// value to a max of 0b111111 (63)
|
||||
case 1:
|
||||
out.ptr[0] = c; // Can just do 0 + codepoint for initial range
|
||||
break;
|
||||
case 2:
|
||||
out.ptr[0] = 0b11000000 | (c >> 6);
|
||||
out.ptr[1] = 0b10000000 | (c & 0b111111);
|
||||
break;
|
||||
case 3:
|
||||
assert(!(0xd800 <= c && c <= 0xdfff));
|
||||
out.ptr[0] = 0b11100000 | (c >> 12);
|
||||
out.ptr[1] = 0b10000000 | ((c >> 6) & 0b111111);
|
||||
out.ptr[2] = 0b10000000 | (c & 0b111111);
|
||||
break;
|
||||
case 4:
|
||||
out.ptr[0] = 0b11110000 | (c >> 18);
|
||||
out.ptr[1] = 0b10000000 | ((c >> 12) & 0b111111);
|
||||
out.ptr[2] = 0b10000000 | ((c >> 6) & 0b111111);
|
||||
out.ptr[3] = 0b10000000 | (c & 0b111111);
|
||||
break;
|
||||
default:
|
||||
zig_unreachable();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
// Ported from std.unicode.utf16leToUtf8Alloc
|
||||
static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) {
|
||||
// optimistically guess that it will all be ascii.
|
||||
buf_resize(out, 0);
|
||||
size_t out_index = 0;
|
||||
Utf16LeIterator it = Utf16LeIterator_init(utf16le);
|
||||
for (;;) {
|
||||
Optional<uint32_t> opt_codepoint = Utf16LeIterator_nextCodepoint(&it);
|
||||
if (!opt_codepoint.is_some) break;
|
||||
uint32_t codepoint = opt_codepoint.value;
|
||||
|
||||
size_t utf8_len = utf8CodepointSequenceLength(codepoint);
|
||||
buf_resize(out, buf_len(out) + utf8_len);
|
||||
utf8Encode(codepoint, {(uint8_t*)buf_ptr(out)+out_index, buf_len(out)-out_index});
|
||||
out_index += utf8_len;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Ported from std.os.getAppDataDir
|
||||
Error os_get_app_data_dir(Buf *out_path, const char *appname) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
Error err;
|
||||
WCHAR *dir_path_ptr;
|
||||
switch (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &dir_path_ptr)) {
|
||||
case S_OK:
|
||||
// defer os.windows.CoTaskMemFree(@ptrCast(*c_void, dir_path_ptr));
|
||||
utf16le_ptr_to_utf8(out_path, dir_path_ptr);
|
||||
CoTaskMemFree(dir_path_ptr);
|
||||
buf_appendf(out_path, "\\%s", appname);
|
||||
return ErrorNone;
|
||||
case E_OUTOFMEMORY:
|
||||
return ErrorNoMem;
|
||||
default:
|
||||
return ErrorUnexpected;
|
||||
}
|
||||
zig_unreachable();
|
||||
#elif defined(ZIG_OS_DARWIN)
|
||||
const char *home_dir = getenv("HOME");
|
||||
if (home_dir == nullptr) {
|
||||
// TODO use /etc/passwd
|
||||
return ErrorFileNotFound;
|
||||
}
|
||||
buf_resize(out_path, 0);
|
||||
buf_appendf(out_path, "%s/Library/Application Support/%s", home_dir, appname);
|
||||
return ErrorNone;
|
||||
#elif defined(ZIG_OS_LINUX)
|
||||
const char *home_dir = getenv("HOME");
|
||||
if (home_dir == nullptr) {
|
||||
// TODO use /etc/passwd
|
||||
return ErrorFileNotFound;
|
||||
}
|
||||
buf_resize(out_path, 0);
|
||||
buf_appendf(out_path, "%s/.local/share/%s", home_dir, appname);
|
||||
return ErrorNone;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if defined(ZIG_OS_LINUX)
|
||||
static int self_exe_shared_libs_callback(struct dl_phdr_info *info, size_t size, void *data) {
|
||||
ZigList<Buf *> *libs = reinterpret_cast< ZigList<Buf *> *>(data);
|
||||
if (info->dlpi_name[0] == '/') {
|
||||
libs->append(buf_create_from_str(info->dlpi_name));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
Error os_self_exe_shared_libs(ZigList<Buf *> &paths) {
|
||||
#if defined(ZIG_OS_LINUX)
|
||||
paths.resize(0);
|
||||
dl_iterate_phdr(self_exe_shared_libs_callback, &paths);
|
||||
return ErrorNone;
|
||||
#elif defined(ZIG_OS_DARWIN)
|
||||
paths.resize(0);
|
||||
uint32_t img_count = _dyld_image_count();
|
||||
for (uint32_t i = 0; i != img_count; i += 1) {
|
||||
const char *name = _dyld_get_image_name(i);
|
||||
paths.append(buf_create_from_str(name));
|
||||
}
|
||||
return ErrorNone;
|
||||
#elif defined(ZIG_OS_WINDOWS)
|
||||
// zig is built statically on windows, so we can return an empty list
|
||||
paths.resize(0);
|
||||
return ErrorNone;
|
||||
#else
|
||||
#error unimplemented
|
||||
#endif
|
||||
}
|
||||
|
||||
Error os_file_open_r(Buf *full_path, OsFile *out_file) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
// TODO use CreateFileW
|
||||
HANDLE result = CreateFileA(buf_ptr(full_path), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
|
||||
if (result == INVALID_HANDLE_VALUE) {
|
||||
DWORD err = GetLastError();
|
||||
switch (err) {
|
||||
case ERROR_SHARING_VIOLATION:
|
||||
return ErrorSharingViolation;
|
||||
case ERROR_ALREADY_EXISTS:
|
||||
return ErrorPathAlreadyExists;
|
||||
case ERROR_FILE_EXISTS:
|
||||
return ErrorPathAlreadyExists;
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
return ErrorFileNotFound;
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
return ErrorFileNotFound;
|
||||
case ERROR_ACCESS_DENIED:
|
||||
return ErrorAccess;
|
||||
case ERROR_PIPE_BUSY:
|
||||
return ErrorPipeBusy;
|
||||
default:
|
||||
return ErrorUnexpected;
|
||||
}
|
||||
}
|
||||
|
||||
*out_file = result;
|
||||
return ErrorNone;
|
||||
#else
|
||||
for (;;) {
|
||||
int fd = open(buf_ptr(full_path), O_RDONLY|O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
continue;
|
||||
case EINVAL:
|
||||
zig_unreachable();
|
||||
case EFAULT:
|
||||
zig_unreachable();
|
||||
case EACCES:
|
||||
return ErrorAccess;
|
||||
case EISDIR:
|
||||
return ErrorIsDir;
|
||||
case ENOENT:
|
||||
return ErrorFileNotFound;
|
||||
default:
|
||||
return ErrorFileSystem;
|
||||
}
|
||||
}
|
||||
*out_file = fd;
|
||||
return ErrorNone;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
for (;;) {
|
||||
HANDLE result = CreateFileA(buf_ptr(full_path), GENERIC_READ | GENERIC_WRITE,
|
||||
0, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
|
||||
if (result == INVALID_HANDLE_VALUE) {
|
||||
DWORD err = GetLastError();
|
||||
switch (err) {
|
||||
case ERROR_SHARING_VIOLATION:
|
||||
// TODO wait for the lock instead of sleeping
|
||||
Sleep(10);
|
||||
continue;
|
||||
case ERROR_ALREADY_EXISTS:
|
||||
return ErrorPathAlreadyExists;
|
||||
case ERROR_FILE_EXISTS:
|
||||
return ErrorPathAlreadyExists;
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
return ErrorFileNotFound;
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
return ErrorFileNotFound;
|
||||
case ERROR_ACCESS_DENIED:
|
||||
return ErrorAccess;
|
||||
case ERROR_PIPE_BUSY:
|
||||
return ErrorPipeBusy;
|
||||
default:
|
||||
return ErrorUnexpected;
|
||||
}
|
||||
}
|
||||
*out_file = result;
|
||||
return ErrorNone;
|
||||
}
|
||||
#else
|
||||
int fd;
|
||||
for (;;) {
|
||||
fd = open(buf_ptr(full_path), O_RDWR|O_CLOEXEC|O_CREAT, 0666);
|
||||
if (fd == -1) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
continue;
|
||||
case EINVAL:
|
||||
zig_unreachable();
|
||||
case EFAULT:
|
||||
zig_unreachable();
|
||||
case EACCES:
|
||||
return ErrorAccess;
|
||||
case EISDIR:
|
||||
return ErrorIsDir;
|
||||
case ENOENT:
|
||||
return ErrorFileNotFound;
|
||||
default:
|
||||
return ErrorFileSystem;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (;;) {
|
||||
struct flock lock;
|
||||
lock.l_type = F_WRLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = 0;
|
||||
lock.l_len = 0;
|
||||
if (fcntl(fd, F_SETLKW, &lock) == -1) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
continue;
|
||||
case EBADF:
|
||||
zig_unreachable();
|
||||
case EFAULT:
|
||||
zig_unreachable();
|
||||
case EINVAL:
|
||||
zig_unreachable();
|
||||
default:
|
||||
close(fd);
|
||||
return ErrorFileSystem;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
*out_file = fd;
|
||||
return ErrorNone;
|
||||
#endif
|
||||
}
|
||||
|
||||
Error os_file_mtime(OsFile file, OsTimeStamp *mtime) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
FILETIME last_write_time;
|
||||
if (!GetFileTime(file, nullptr, nullptr, &last_write_time))
|
||||
return ErrorUnexpected;
|
||||
mtime->sec = last_write_time.dwLowDateTime | (last_write_time.dwHighDateTime << 32);
|
||||
mtime->nsec = 0;
|
||||
return ErrorNone;
|
||||
#elif defined(ZIG_OS_LINUX)
|
||||
struct stat statbuf;
|
||||
if (fstat(file, &statbuf) == -1)
|
||||
return ErrorFileSystem;
|
||||
|
||||
mtime->sec = statbuf.st_mtim.tv_sec;
|
||||
mtime->nsec = statbuf.st_mtim.tv_nsec;
|
||||
return ErrorNone;
|
||||
#elif defined(ZIG_OS_DARWIN)
|
||||
struct stat statbuf;
|
||||
if (fstat(file, &statbuf) == -1)
|
||||
return ErrorFileSystem;
|
||||
|
||||
mtime->sec = statbuf.st_mtimespec.tv_sec;
|
||||
mtime->nsec = statbuf.st_mtimespec.tv_nsec;
|
||||
return ErrorNone;
|
||||
#else
|
||||
#error unimplemented
|
||||
#endif
|
||||
}
|
||||
|
||||
Error os_file_read(OsFile file, void *ptr, size_t *len) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
DWORD amt_read;
|
||||
if (ReadFile(file, ptr, *len, &amt_read, nullptr) == 0)
|
||||
return ErrorUnexpected;
|
||||
*len = amt_read;
|
||||
return ErrorNone;
|
||||
#else
|
||||
for (;;) {
|
||||
ssize_t rc = read(file, ptr, *len);
|
||||
if (rc == -1) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
continue;
|
||||
case EBADF:
|
||||
zig_unreachable();
|
||||
case EFAULT:
|
||||
zig_unreachable();
|
||||
case EISDIR:
|
||||
zig_unreachable();
|
||||
default:
|
||||
return ErrorFileSystem;
|
||||
}
|
||||
}
|
||||
*len = rc;
|
||||
return ErrorNone;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Error os_file_read_all(OsFile file, Buf *contents) {
|
||||
Error err;
|
||||
size_t index = 0;
|
||||
for (;;) {
|
||||
size_t amt = buf_len(contents) - index;
|
||||
|
||||
if (amt < 4096) {
|
||||
buf_resize(contents, buf_len(contents) + (4096 - amt));
|
||||
amt = buf_len(contents) - index;
|
||||
}
|
||||
|
||||
if ((err = os_file_read(file, buf_ptr(contents) + index, &amt)))
|
||||
return err;
|
||||
|
||||
if (amt == 0) {
|
||||
buf_resize(contents, index);
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
index += amt;
|
||||
}
|
||||
}
|
||||
|
||||
Error os_file_overwrite(OsFile file, Buf *contents) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
if (SetFilePointer(file, 0, nullptr, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
|
||||
return ErrorFileSystem;
|
||||
if (!SetEndOfFile(file))
|
||||
return ErrorFileSystem;
|
||||
if (!WriteFile(file, buf_ptr(contents), buf_len(contents), nullptr, nullptr))
|
||||
return ErrorFileSystem;
|
||||
return ErrorNone;
|
||||
#else
|
||||
if (lseek(file, 0, SEEK_SET) == -1)
|
||||
return ErrorFileSystem;
|
||||
if (ftruncate(file, 0) == -1)
|
||||
return ErrorFileSystem;
|
||||
for (;;) {
|
||||
if (write(file, buf_ptr(contents), buf_len(contents)) == -1) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
continue;
|
||||
case EINVAL:
|
||||
zig_unreachable();
|
||||
case EBADF:
|
||||
zig_unreachable();
|
||||
default:
|
||||
return ErrorFileSystem;
|
||||
}
|
||||
}
|
||||
return ErrorNone;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void os_file_close(OsFile file) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
CloseHandle(file);
|
||||
#else
|
||||
close(file);
|
||||
#endif
|
||||
}
|
||||
|
|
157
src/os.hpp
157
src/os.hpp
|
@ -13,77 +13,11 @@
|
|||
#include "error.hpp"
|
||||
#include "zig_llvm.h"
|
||||
#include "windows_sdk.h"
|
||||
#include "result.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
enum TermColor {
|
||||
TermColorRed,
|
||||
TermColorGreen,
|
||||
TermColorCyan,
|
||||
TermColorWhite,
|
||||
TermColorBold,
|
||||
TermColorReset,
|
||||
};
|
||||
|
||||
enum TerminationId {
|
||||
TerminationIdClean,
|
||||
TerminationIdSignaled,
|
||||
TerminationIdStopped,
|
||||
TerminationIdUnknown,
|
||||
};
|
||||
|
||||
struct Termination {
|
||||
TerminationId how;
|
||||
int code;
|
||||
};
|
||||
|
||||
int os_init(void);
|
||||
|
||||
void os_spawn_process(const char *exe, ZigList<const char *> &args, Termination *term);
|
||||
int os_exec_process(const char *exe, ZigList<const char *> &args,
|
||||
Termination *term, Buf *out_stderr, Buf *out_stdout);
|
||||
|
||||
void os_path_dirname(Buf *full_path, Buf *out_dirname);
|
||||
void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename);
|
||||
void os_path_extname(Buf *full_path, Buf *out_basename, Buf *out_extname);
|
||||
void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path);
|
||||
int os_path_real(Buf *rel_path, Buf *out_abs_path);
|
||||
Buf os_path_resolve(Buf **paths_ptr, size_t paths_len);
|
||||
bool os_path_is_absolute(Buf *path);
|
||||
|
||||
int os_get_global_cache_directory(Buf *out_tmp_path);
|
||||
|
||||
int os_make_path(Buf *path);
|
||||
int os_make_dir(Buf *path);
|
||||
|
||||
void os_write_file(Buf *full_path, Buf *contents);
|
||||
int os_copy_file(Buf *src_path, Buf *dest_path);
|
||||
|
||||
int os_fetch_file(FILE *file, Buf *out_contents, bool skip_shebang);
|
||||
int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang);
|
||||
|
||||
int os_get_cwd(Buf *out_cwd);
|
||||
|
||||
bool os_stderr_tty(void);
|
||||
void os_stderr_set_color(TermColor color);
|
||||
|
||||
int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path);
|
||||
int os_delete_file(Buf *path);
|
||||
|
||||
int os_file_exists(Buf *full_path, bool *result);
|
||||
|
||||
int os_rename(Buf *src_path, Buf *dest_path);
|
||||
double os_get_time(void);
|
||||
|
||||
bool os_is_sep(uint8_t c);
|
||||
|
||||
int os_self_exe_path(Buf *out_path);
|
||||
|
||||
int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf *output_buf);
|
||||
int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
|
||||
int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define ZIG_OS_DARWIN
|
||||
#elif defined(_WIN32)
|
||||
|
@ -116,4 +50,93 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchTy
|
|||
#define ZIG_OS_SEP_CHAR '/'
|
||||
#endif
|
||||
|
||||
enum TermColor {
|
||||
TermColorRed,
|
||||
TermColorGreen,
|
||||
TermColorCyan,
|
||||
TermColorWhite,
|
||||
TermColorBold,
|
||||
TermColorReset,
|
||||
};
|
||||
|
||||
enum TerminationId {
|
||||
TerminationIdClean,
|
||||
TerminationIdSignaled,
|
||||
TerminationIdStopped,
|
||||
TerminationIdUnknown,
|
||||
};
|
||||
|
||||
struct Termination {
|
||||
TerminationId how;
|
||||
int code;
|
||||
};
|
||||
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
#define OsFile void *
|
||||
#else
|
||||
#define OsFile int
|
||||
#endif
|
||||
|
||||
struct OsTimeStamp {
|
||||
uint64_t sec;
|
||||
uint64_t nsec;
|
||||
};
|
||||
|
||||
int os_init(void);
|
||||
|
||||
void os_spawn_process(const char *exe, ZigList<const char *> &args, Termination *term);
|
||||
int os_exec_process(const char *exe, ZigList<const char *> &args,
|
||||
Termination *term, Buf *out_stderr, Buf *out_stdout);
|
||||
Error os_execv(const char *exe, const char **argv);
|
||||
|
||||
void os_path_dirname(Buf *full_path, Buf *out_dirname);
|
||||
void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename);
|
||||
void os_path_extname(Buf *full_path, Buf *out_basename, Buf *out_extname);
|
||||
void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path);
|
||||
int os_path_real(Buf *rel_path, Buf *out_abs_path);
|
||||
Buf os_path_resolve(Buf **paths_ptr, size_t paths_len);
|
||||
bool os_path_is_absolute(Buf *path);
|
||||
|
||||
Error ATTRIBUTE_MUST_USE os_make_path(Buf *path);
|
||||
Error ATTRIBUTE_MUST_USE os_make_dir(Buf *path);
|
||||
|
||||
Error ATTRIBUTE_MUST_USE os_file_open_r(Buf *full_path, OsFile *out_file);
|
||||
Error ATTRIBUTE_MUST_USE os_file_open_lock_rw(Buf *full_path, OsFile *out_file);
|
||||
Error ATTRIBUTE_MUST_USE os_file_mtime(OsFile file, OsTimeStamp *mtime);
|
||||
Error ATTRIBUTE_MUST_USE os_file_read(OsFile file, void *ptr, size_t *len);
|
||||
Error ATTRIBUTE_MUST_USE os_file_read_all(OsFile file, Buf *contents);
|
||||
Error ATTRIBUTE_MUST_USE os_file_overwrite(OsFile file, Buf *contents);
|
||||
void os_file_close(OsFile file);
|
||||
|
||||
void os_write_file(Buf *full_path, Buf *contents);
|
||||
int os_copy_file(Buf *src_path, Buf *dest_path);
|
||||
|
||||
Error ATTRIBUTE_MUST_USE os_fetch_file(FILE *file, Buf *out_contents, bool skip_shebang);
|
||||
Error ATTRIBUTE_MUST_USE os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang);
|
||||
|
||||
int os_get_cwd(Buf *out_cwd);
|
||||
|
||||
bool os_stderr_tty(void);
|
||||
void os_stderr_set_color(TermColor color);
|
||||
|
||||
int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path);
|
||||
int os_delete_file(Buf *path);
|
||||
|
||||
Error ATTRIBUTE_MUST_USE os_file_exists(Buf *full_path, bool *result);
|
||||
|
||||
int os_rename(Buf *src_path, Buf *dest_path);
|
||||
double os_get_time(void);
|
||||
|
||||
bool os_is_sep(uint8_t c);
|
||||
|
||||
Error ATTRIBUTE_MUST_USE os_self_exe_path(Buf *out_path);
|
||||
|
||||
Error ATTRIBUTE_MUST_USE os_get_app_data_dir(Buf *out_path, const char *appname);
|
||||
|
||||
int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf *output_buf);
|
||||
int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
|
||||
int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
|
||||
|
||||
Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -813,6 +813,22 @@ const char *target_exe_file_ext(ZigTarget *target) {
|
|||
}
|
||||
}
|
||||
|
||||
const char *target_lib_file_ext(ZigTarget *target, bool is_static, size_t version_major, size_t version_minor, size_t version_patch) {
|
||||
if (target->os == OsWindows) {
|
||||
if (is_static) {
|
||||
return ".lib";
|
||||
} else {
|
||||
return ".dll";
|
||||
}
|
||||
} else {
|
||||
if (is_static) {
|
||||
return ".a";
|
||||
} else {
|
||||
return buf_ptr(buf_sprintf(".so.%zu", version_major));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum FloatAbi {
|
||||
FloatAbiHard,
|
||||
FloatAbiSoft,
|
||||
|
|
|
@ -113,6 +113,7 @@ const char *target_o_file_ext(ZigTarget *target);
|
|||
const char *target_asm_file_ext(ZigTarget *target);
|
||||
const char *target_llvm_ir_file_ext(ZigTarget *target);
|
||||
const char *target_exe_file_ext(ZigTarget *target);
|
||||
const char *target_lib_file_ext(ZigTarget *target, bool is_static, size_t version_major, size_t version_minor, size_t version_patch);
|
||||
|
||||
Buf *target_dynamic_linker(ZigTarget *target);
|
||||
|
||||
|
|
39
src/util.cpp
39
src/util.cpp
|
@ -43,3 +43,42 @@ uint32_t ptr_hash(const void *ptr) {
|
|||
bool ptr_eq(const void *a, const void *b) {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
// Ported from std/mem.zig.
|
||||
bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte) {
|
||||
for (size_t i = 0; i < self->split_bytes.len; i += 1) {
|
||||
if (byte == self->split_bytes.ptr[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ported from std/mem.zig.
|
||||
Optional<Slice<uint8_t>> SplitIterator_next(SplitIterator *self) {
|
||||
// move to beginning of token
|
||||
while (self->index < self->buffer.len &&
|
||||
SplitIterator_isSplitByte(self, self->buffer.ptr[self->index]))
|
||||
{
|
||||
self->index += 1;
|
||||
}
|
||||
size_t start = self->index;
|
||||
if (start == self->buffer.len) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// move to end of token
|
||||
while (self->index < self->buffer.len &&
|
||||
!SplitIterator_isSplitByte(self, self->buffer.ptr[self->index]))
|
||||
{
|
||||
self->index += 1;
|
||||
}
|
||||
size_t end = self->index;
|
||||
|
||||
return Optional<Slice<uint8_t>>::some(self->buffer.slice(start, end));
|
||||
}
|
||||
|
||||
// Ported from std/mem.zig
|
||||
SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes) {
|
||||
return SplitIterator{0, buffer, split_bytes};
|
||||
}
|
||||
|
|
12
src/util.hpp
12
src/util.hpp
|
@ -254,4 +254,16 @@ static inline void memCopy(Slice<T> dest, Slice<T> src) {
|
|||
memcpy(dest.ptr, src.ptr, src.len * sizeof(T));
|
||||
}
|
||||
|
||||
// Ported from std/mem.zig.
|
||||
// Coordinate struct fields with memSplit function
|
||||
struct SplitIterator {
|
||||
size_t index;
|
||||
Slice<uint8_t> buffer;
|
||||
Slice<uint8_t> split_bytes;
|
||||
};
|
||||
|
||||
bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte);
|
||||
Optional<Slice<uint8_t>> SplitIterator_next(SplitIterator *self);
|
||||
SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <llvm/PassRegistry.h>
|
||||
#include <llvm/Support/FileSystem.h>
|
||||
#include <llvm/Support/TargetParser.h>
|
||||
#include <llvm/Support/Timer.h>
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
#include <llvm/Target/TargetMachine.h>
|
||||
#include <llvm/Transforms/Coroutines.h>
|
||||
|
@ -81,8 +82,11 @@ static const bool assertions_on = false;
|
|||
#endif
|
||||
|
||||
bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
|
||||
const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug, bool is_small)
|
||||
const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug,
|
||||
bool is_small, bool time_report)
|
||||
{
|
||||
TimePassesIsEnabled = time_report;
|
||||
|
||||
std::error_code EC;
|
||||
raw_fd_ostream dest(filename, EC, sys::fs::F_None);
|
||||
if (EC) {
|
||||
|
@ -182,6 +186,9 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
|
|||
}
|
||||
}
|
||||
|
||||
if (time_report) {
|
||||
TimerGroup::printAll(errs());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,8 @@ enum ZigLLVM_EmitOutputType {
|
|||
};
|
||||
|
||||
ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
|
||||
const char *filename, enum ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug, bool is_small);
|
||||
const char *filename, enum ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug,
|
||||
bool is_small, bool time_report);
|
||||
|
||||
ZIG_EXTERN_C LLVMTypeRef ZigLLVMTokenTypeInContext(LLVMContextRef context_ref);
|
||||
|
||||
|
|
|
@ -232,6 +232,8 @@ pub const Builder = struct {
|
|||
}
|
||||
|
||||
pub fn make(self: *Builder, step_names: []const []const u8) !void {
|
||||
try self.makePath(self.cache_root);
|
||||
|
||||
var wanted_steps = ArrayList(*Step).init(self.allocator);
|
||||
defer wanted_steps.deinit();
|
||||
|
||||
|
@ -1641,6 +1643,7 @@ pub const TestStep = struct {
|
|||
lib_paths: ArrayList([]const u8),
|
||||
object_files: ArrayList([]const u8),
|
||||
no_rosegment: bool,
|
||||
output_path: ?[]const u8,
|
||||
|
||||
pub fn init(builder: *Builder, root_src: []const u8) TestStep {
|
||||
const step_name = builder.fmt("test {}", root_src);
|
||||
|
@ -1659,6 +1662,7 @@ pub const TestStep = struct {
|
|||
.lib_paths = ArrayList([]const u8).init(builder.allocator),
|
||||
.object_files = ArrayList([]const u8).init(builder.allocator),
|
||||
.no_rosegment = false,
|
||||
.output_path = null,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1682,6 +1686,24 @@ pub const TestStep = struct {
|
|||
self.build_mode = mode;
|
||||
}
|
||||
|
||||
pub fn setOutputPath(self: *TestStep, file_path: []const u8) void {
|
||||
self.output_path = file_path;
|
||||
|
||||
// catch a common mistake
|
||||
if (mem.eql(u8, self.builder.pathFromRoot(file_path), self.builder.pathFromRoot("."))) {
|
||||
debug.panic("setOutputPath wants a file path, not a directory\n");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getOutputPath(self: *TestStep) []const u8 {
|
||||
if (self.output_path) |output_path| {
|
||||
return output_path;
|
||||
} else {
|
||||
const basename = self.builder.fmt("test{}", self.target.exeFileExt());
|
||||
return os.path.join(self.builder.allocator, self.builder.cache_root, basename) catch unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn linkSystemLibrary(self: *TestStep, name: []const u8) void {
|
||||
self.link_libs.put(name) catch unreachable;
|
||||
}
|
||||
|
@ -1746,6 +1768,10 @@ pub const TestStep = struct {
|
|||
builtin.Mode.ReleaseSmall => try zig_args.append("--release-small"),
|
||||
}
|
||||
|
||||
const output_path = builder.pathFromRoot(self.getOutputPath());
|
||||
try zig_args.append("--output");
|
||||
try zig_args.append(output_path);
|
||||
|
||||
switch (self.target) {
|
||||
Target.Native => {},
|
||||
Target.Cross => |cross_target| {
|
||||
|
|
Loading…
Reference in New Issue