diff --git a/src/all_types.hpp b/src/all_types.hpp index 607efbdf68..c701529bf9 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1296,6 +1296,7 @@ struct CodeGen { LLVMBuilderRef builder; ZigLLVMDIBuilder *dbuilder; ZigLLVMDICompileUnit *compile_unit; + ZigLLVMDIFile *compile_unit_file; ZigList link_libs; // non-libc link libs // add -framework [name] args to linker @@ -1468,6 +1469,7 @@ struct CodeGen { Buf global_asm; ZigList link_objects; + ZigList assembly_files; ZigList name_table_enums; diff --git a/src/analyze.cpp b/src/analyze.cpp index ebbb3e0689..77edddb31c 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2851,9 +2851,7 @@ void preview_use_decl(CodeGen *g, AstNode *node) { node->data.use.value = result; } -ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, - Buf *abs_full_path, Buf *src_dirname, Buf *src_basename, Buf *source_code) -{ +ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code) { if (g->verbose) { fprintf(stderr, "\nOriginal Source (%s):\n", buf_ptr(abs_full_path)); fprintf(stderr, "----------------\n"); @@ -2894,7 +2892,10 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, ast_print(stderr, import_entry->root, 0); } - // TODO: assert that src_basename has no '/' in it + Buf *src_dirname = buf_alloc(); + Buf *src_basename = buf_alloc(); + os_path_split(abs_full_path, src_dirname, src_basename); + import_entry->di_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname)); g->import_table.put(abs_full_path, import_entry); g->import_queue.append(import_entry); diff --git a/src/analyze.hpp b/src/analyze.hpp index f42c742d99..cbcab31e62 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -40,8 +40,7 @@ void find_libc_lib_path(CodeGen *g); bool type_has_bits(TypeTableEntry *type_entry); -ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, - Buf *abs_full_path, Buf *src_dirname, Buf *src_basename, Buf *source_code); +ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code); // TODO move these over, these used to be static diff --git a/src/codegen.cpp b/src/codegen.cpp index 12cff60a17..d779eb158e 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -55,7 +55,7 @@ PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_pa return entry; } -CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) { +CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target) { CodeGen *g = allocate(1); codegen_add_time_event(g, "Initialize"); @@ -81,9 +81,17 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) { // reserve index 0 to indicate no error g->error_decls.append(nullptr); - g->root_package = new_package(buf_ptr(root_source_dir), ""); - g->std_package = new_package(ZIG_STD_DIR, "index.zig"); - g->root_package->package_table.put(buf_create_from_str("std"), g->std_package); + if (root_src_path) { + Buf *src_basename = buf_alloc(); + Buf *src_dir = buf_alloc(); + os_path_split(root_src_path, src_dir, src_basename); + + g->root_package = new_package(buf_ptr(src_dir), buf_ptr(src_basename)); + g->std_package = new_package(ZIG_STD_DIR, "index.zig"); + g->root_package->package_table.put(buf_create_from_str("std"), g->std_package); + } else { + g->root_package = new_package(".", ""); + } g->zig_std_dir = buf_create_from_str(ZIG_STD_DIR); g->zig_std_special_dir = buf_alloc(); @@ -757,7 +765,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) { LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g); - LLVMBuildCall(g->builder, safety_crash_err_fn, &err_val, 1, ""); + ZigLLVMBuildCall(g->builder, safety_crash_err_fn, &err_val, 1, LLVMFastCallConv, false, ""); LLVMBuildUnreachable(g->builder); } @@ -3655,6 +3663,10 @@ static LLVMValueRef build_alloca(CodeGen *g, TypeTableEntry *type_entry, const c } static void do_code_gen(CodeGen *g) { + if (g->verbose) { + fprintf(stderr, "\nCode Generation:\n"); + fprintf(stderr, "------------------\n"); + } assert(!g->errors.length); codegen_add_time_event(g, "Code Generation"); @@ -4602,8 +4614,9 @@ static void define_builtin_compile_vars(CodeGen *g) { add_compile_var(g, "panic_implementation_provided", create_const_bool(g, false)); } -static void init(CodeGen *g, Buf *source_path) { - g->module = LLVMModuleCreateWithName(buf_ptr(source_path)); +static void init(CodeGen *g) { + assert(g->root_out_name); + g->module = LLVMModuleCreateWithName(buf_ptr(g->root_out_name)); get_target_triple(&g->triple_str, &g->zig_target); @@ -4674,23 +4687,25 @@ static void init(CodeGen *g, Buf *source_path) { g->const_void_val.type = g->builtin_types.entry_void; } -void codegen_parseh(CodeGen *g, Buf *src_dirname, Buf *src_basename, Buf *source_code) { +void codegen_parseh(CodeGen *g, Buf *full_path) { find_libc_include_path(g); - Buf *full_path = buf_alloc(); - os_path_join(src_dirname, src_basename, full_path); + + Buf *src_basename = buf_alloc(); + Buf *src_dirname = buf_alloc(); + os_path_split(full_path, src_dirname, src_basename); ImportTableEntry *import = allocate(1); - import->source_code = source_code; + import->source_code = nullptr; import->path = full_path; g->root_import = import; import->decls_scope = create_decls_scope(nullptr, nullptr, nullptr, import); - init(g, full_path); + init(g); import->di_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname)); ZigList errors = {0}; - int err = parse_h_buf(import, &errors, source_code, g, nullptr); + int err = parse_h_file(import, &errors, buf_ptr(full_path), g, nullptr); if (err) { fprintf(stderr, "unable to parse .h file: %s\n", err_str(err)); exit(1); @@ -4719,7 +4734,7 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err)); } - return add_source_file(g, package, abs_full_path, g->zig_std_special_dir, code_basename, import_code); + return add_source_file(g, package, abs_full_path, import_code); } static PackageTableEntry *create_bootstrap_pkg(CodeGen *g) { @@ -4736,23 +4751,27 @@ static PackageTableEntry *create_zigrt_pkg(CodeGen *g) { return package; } -void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *source_code) { +static void gen_root_source(CodeGen *g) { + if (buf_len(&g->root_package->root_src_path) == 0) + return; + codegen_add_time_event(g, "Semantic Analysis"); - Buf source_path = BUF_INIT; - os_path_join(src_dir, src_basename, &source_path); - - buf_init_from_buf(&g->root_package->root_src_path, src_basename); - - init(g, &source_path); + 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 *abs_full_path = buf_alloc(); int err; - if ((err = os_path_real(&source_path, abs_full_path))) { - zig_panic("unable to open '%s': %s", buf_ptr(&source_path), err_str(err)); + if ((err = os_path_real(rel_full_path, abs_full_path))) { + zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err)); } - g->root_import = add_source_file(g, g->root_package, abs_full_path, src_dir, src_basename, source_code); + Buf *source_code = buf_alloc(); + if ((err = os_fetch_file_path(rel_full_path, source_code))) { + zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err)); + } + + g->root_import = add_source_file(g, g->root_package, abs_full_path, source_code); assert(g->root_out_name); assert(g->out_type != OutTypeUnknown); @@ -4787,27 +4806,33 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou exit(1); } - if (g->verbose) { - fprintf(stderr, "\nCode Generation:\n"); - fprintf(stderr, "------------------\n"); - - } - - do_code_gen(g); } -void codegen_add_root_assembly(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *source_code) { - Buf source_path = BUF_INIT; - os_path_join(src_dir, src_basename, &source_path); +void codegen_add_assembly(CodeGen *g, Buf *path) { + g->assembly_files.append(path); +} - init(g, &source_path); +static void gen_global_asm(CodeGen *g) { + Buf contents = BUF_INIT; + int err; + for (size_t i = 0; i < g->assembly_files.length; i += 1) { + Buf *asm_file = g->assembly_files.at(i); + if ((err = os_fetch_file_path(asm_file, &contents))) { + zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err)); + } + if (g->zig_target.arch.arch == ZigLLVM_x86 || g->zig_target.arch.arch == ZigLLVM_x86_64) { + buf_append_str(&g->global_asm, ".intel_syntax noprefix\n"); + } + buf_append_buf(&g->global_asm, &contents); + } +} - assert(g->root_out_name); +void codegen_build(CodeGen *g) { assert(g->out_type != OutTypeUnknown); + init(g); - buf_init_from_str(&g->global_asm, ".intel_syntax noprefix\n"); - buf_append_buf(&g->global_asm, source_code); - + gen_global_asm(g); + gen_root_source(g); do_code_gen(g); } diff --git a/src/codegen.hpp b/src/codegen.hpp index 4646f5008e..0eac029a06 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -14,7 +14,7 @@ #include -CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target); +CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target); void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len); void codegen_set_is_release(CodeGen *codegen, bool is_release); @@ -49,13 +49,13 @@ 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_add_time_event(CodeGen *g, const char *name); void codegen_print_timing_report(CodeGen *g, FILE *f); +void codegen_build(CodeGen *g); PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_path); -void codegen_add_root_code(CodeGen *g, Buf *source_dir, Buf *source_basename, Buf *source_code); -void codegen_add_root_assembly(CodeGen *g, Buf *source_dir, Buf *source_basename, Buf *source_code); +void codegen_add_assembly(CodeGen *g, Buf *path); void codegen_add_object(CodeGen *g, Buf *object_path); -void codegen_parseh(CodeGen *g, Buf *src_dirname, Buf *src_basename, Buf *source_code); +void codegen_parseh(CodeGen *g, Buf *path); void codegen_render_ast(CodeGen *g, FILE *f, int indent_size); void codegen_generate_h_file(CodeGen *g); diff --git a/src/ir.cpp b/src/ir.cpp index ba0aba6a1f..94c5490b28 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -6043,6 +6043,21 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, } } + // implicit [N]T to ?[]const N + if (expected_type->id == TypeTableEntryIdMaybe && + is_slice(expected_type->data.maybe.child_type) && + actual_type->id == TypeTableEntryIdArray) + { + TypeTableEntry *ptr_type = + expected_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry; + assert(ptr_type->id == TypeTableEntryIdPointer); + if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && + types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type)) + { + return ImplicitCastMatchResultYes; + } + } + // implicit number literal to typed number // implicit number literal to &const integer if (actual_type->id == TypeTableEntryIdNumLitFloat || @@ -7093,6 +7108,29 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } } + // explicit cast from [N]T to ?[]const N + if (wanted_type->id == TypeTableEntryIdMaybe && + is_slice(wanted_type->data.maybe.child_type) && + actual_type->id == TypeTableEntryIdArray) + { + TypeTableEntry *ptr_type = + wanted_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry; + assert(ptr_type->id == TypeTableEntryIdPointer); + if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && + types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type)) + { + IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value); + if (type_is_invalid(cast1->value.type)) + return ira->codegen->invalid_instruction; + + IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); + if (type_is_invalid(cast2->value.type)) + return ira->codegen->invalid_instruction; + + return cast2; + } + } + // explicit cast from []T to []u8 or []u8 to []T if (is_slice(wanted_type) && is_slice(actual_type) && (is_u8(wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type) || @@ -10880,8 +10918,7 @@ static TypeTableEntry *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructi return ira->codegen->builtin_types.entry_invalid; } } - ImportTableEntry *target_import = add_source_file(ira->codegen, target_package, - abs_full_path, search_dir, import_target_path, import_code); + ImportTableEntry *target_import = add_source_file(ira->codegen, target_package, abs_full_path, import_code); scan_decls(ira->codegen, target_import->decls_scope, target_import->root); diff --git a/src/link.cpp b/src/link.cpp index 59aa19e5db..81c4f3506a 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -33,9 +33,11 @@ static const char *get_libc_static_file(CodeGen *g, const char *file) { static Buf *build_o(CodeGen *parent_gen, const char *oname) { Buf *source_basename = buf_sprintf("%s.zig", oname); + Buf *full_path = buf_alloc(); + os_path_join(parent_gen->zig_std_special_dir, source_basename, full_path); ZigTarget *child_target = parent_gen->is_native_target ? nullptr : &parent_gen->zig_target; - CodeGen *child_gen = codegen_create(parent_gen->zig_std_special_dir, child_target); + CodeGen *child_gen = codegen_create(full_path, child_target); child_gen->link_libc = parent_gen->link_libc; child_gen->link_libs.resize(parent_gen->link_libs.length); @@ -60,15 +62,7 @@ static Buf *build_o(CodeGen *parent_gen, const char *oname) { codegen_set_mmacosx_version_min(child_gen, parent_gen->mmacosx_version_min); codegen_set_mios_version_min(child_gen, parent_gen->mios_version_min); - Buf *full_path = buf_alloc(); - os_path_join(parent_gen->zig_std_special_dir, source_basename, full_path); - - Buf source_code = BUF_INIT; - if (os_fetch_file_path(full_path, &source_code)) { - zig_panic("unable to fetch file: %s\n", buf_ptr(full_path)); - } - - codegen_add_root_code(child_gen, parent_gen->zig_std_special_dir, source_basename, &source_code); + codegen_build(child_gen); const char *o_ext = target_o_file_ext(&child_gen->zig_target); Buf *o_out = buf_sprintf("%s%s", oname, o_ext); codegen_link(child_gen, buf_ptr(o_out)); diff --git a/src/main.cpp b/src/main.cpp index 542606c9a1..ee4d542e12 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,29 +19,19 @@ static int usage(const char *arg0) { fprintf(stderr, "Usage: %s [command] [options]\n" "Commands:\n" - " asm [source] create object from assembly\n" " build build project from build.zig\n" - " build_exe [source] create executable from source\n" - " build_lib [source] create library from source\n" - " build_obj [source] create object from source\n" - " link_exe [objects] create executable from objects\n" - " link_lib [objects] create library from objects\n" + " build_exe [source] create executable from source or object files\n" + " build_lib [source] create library from source or object files\n" + " build_obj [source] create object from source or assembly\n" " parseh [source] convert a c header file to zig extern declarations\n" " targets list available compilation targets\n" " test [source] create and run a test build\n" " version print version number and exit\n" - "Options:\n" - " --ar-path [path] set the path to ar\n" + "Compile Options:\n" + " --assembly [source] add assembly file to build\n" " --color [auto|off|on] enable or disable colored error messages\n" - " --dynamic-linker [path] set the path to ld.so\n" - " --each-lib-rpath add rpath for each used dynamic library\n" - " --ld-path [path] set the path to the linker\n" + " --enable-timing-info print timing diagnostics\n" " --libc-include-dir [path] directory where libc stdlib.h resides\n" - " --libc-lib-dir [path] directory where libc crt1.o resides\n" - " --libc-static-lib-dir [path] directory where libc crtbegin.o resides\n" - " --library [lib] link against lib\n" - " --library-path [dir] add a directory to the library search path\n" - " --linker-script [path] use a custom linker script\n" " --name [name] override output name\n" " --output [file] override destination path\n" " --release build with optimizations on and debug protection off\n" @@ -52,26 +42,34 @@ static int usage(const char *arg0) { " --target-os [name] specify target operating system\n" " --verbose turn on compiler debug output\n" " --zig-std-dir [path] directory where zig standard library resides\n" - " -L[dir] alias for --library-path\n" " -dirafter [dir] same as -isystem but do it last\n" - " -framework [name] (darwin only) link against framework\n" " -isystem [dir] add additional search path for other .h files\n" - " -mconsole (windows only) --subsystem console to the linker\n" - " -mios-version-min [ver] (darwin only) set iOS deployment target\n" - " -mlinker-version [ver] (darwin only) override linker version\n" - " -mmacosx-version-min [ver] (darwin only) set Mac OS X deployment target\n" - " -municode (windows only) link with unicode\n" - " -mwindows (windows only) --subsystem windows to the linker\n" + "Link Options:\n" + " --ar-path [path] set the path to ar\n" + " --dynamic-linker [path] set the path to ld.so\n" + " --each-lib-rpath add rpath for each used dynamic library\n" + " --libc-lib-dir [path] directory where libc crt1.o resides\n" + " --libc-static-lib-dir [path] directory where libc crtbegin.o resides\n" + " --library [lib] link against lib\n" + " --library-path [dir] add a directory to the library search path\n" + " --linker-script [path] use a custom linker script\n" + " --object [obj] add object file to build\n" + " -L[dir] alias for --library-path\n" " -rdynamic add all symbols to the dynamic symbol table\n" " -rpath [path] add directory to the runtime library search path\n" - " --enable-timing-info print timing diagnostics\n" + " -mconsole (windows) --subsystem console to the linker\n" + " -mwindows (windows) --subsystem windows to the linker\n" + " -municode (windows) link with unicode\n" + " -framework [name] (darwin) link against framework\n" + " -mios-version-min [ver] (darwin) set iOS deployment target\n" + " -mlinker-version [ver] (darwin) override linker version\n" + " -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target\n" + " --ver-major [ver] dynamic library semver major version\n" + " --ver-minor [ver] dynamic library semver minor version\n" + " --ver-patch [ver] dynamic library semver patch version\n" "Test Options:\n" " --test-filter [text] skip tests that do not match filter\n" " --test-name-prefix [text] add prefix to all tests\n" - "Dynamic Library Options:\n" - " --ver-major [ver] semver major version\n" - " --ver-minor [ver] semver minor version\n" - " --ver-patch [ver] semver patch version\n" , arg0); return EXIT_FAILURE; } @@ -117,8 +115,6 @@ enum Cmd { CmdVersion, CmdParseH, CmdTargets, - CmdAsm, - CmdLink, }; int main(int argc, char **argv) { @@ -159,6 +155,7 @@ int main(int argc, char **argv) { ZigList rpath_list = {0}; bool each_lib_rpath = false; ZigList objects = {0}; + ZigList asm_files = {0}; const char *test_filter = nullptr; const char *test_name_prefix = nullptr; size_t ver_major = 0; @@ -197,16 +194,7 @@ int main(int argc, char **argv) { } } - - Buf root_source_dir = BUF_INIT; - Buf root_source_code = BUF_INIT; - Buf root_source_name = BUF_INIT; - os_path_split(build_runner_path, &root_source_dir, &root_source_name); - if ((err = os_fetch_file_path(build_runner_path, &root_source_code))) { - fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(build_runner_path), err_str(err)); - return 1; - } - CodeGen *g = codegen_create(&root_source_dir, nullptr); + CodeGen *g = codegen_create(build_runner_path, nullptr); codegen_set_out_name(g, buf_create_from_str("build")); codegen_set_out_type(g, OutTypeExe); codegen_set_verbose(g, verbose); @@ -256,7 +244,7 @@ int main(int argc, char **argv) { PackageTableEntry *build_pkg = new_package(buf_ptr(&build_file_dirname), buf_ptr(&build_file_basename)); build_pkg->package_table.put(buf_create_from_str("std"), g->std_package); g->root_package->package_table.put(buf_create_from_str("@build"), build_pkg); - codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code); + codegen_build(g); codegen_link(g, "build"); Termination term; @@ -339,6 +327,10 @@ int main(int argc, char **argv) { lib_dirs.append(argv[i]); } else if (strcmp(arg, "--library") == 0) { link_libs.append(argv[i]); + } else if (strcmp(arg, "--object") == 0) { + objects.append(argv[i]); + } else if (strcmp(arg, "--assembly") == 0) { + asm_files.append(argv[i]); } else if (strcmp(arg, "--target-arch") == 0) { target_arch = argv[i]; } else if (strcmp(arg, "--target-os") == 0) { @@ -382,12 +374,6 @@ int main(int argc, char **argv) { } else if (strcmp(arg, "build_lib") == 0) { cmd = CmdBuild; out_type = OutTypeLib; - } else if (strcmp(arg, "link_lib") == 0) { - cmd = CmdLink; - out_type = OutTypeLib; - } else if (strcmp(arg, "link_exe") == 0) { - cmd = CmdLink; - out_type = OutTypeExe; } else if (strcmp(arg, "version") == 0) { cmd = CmdVersion; } else if (strcmp(arg, "parseh") == 0) { @@ -396,8 +382,6 @@ int main(int argc, char **argv) { cmd = CmdTest; } else if (strcmp(arg, "targets") == 0) { cmd = CmdTargets; - } else if (strcmp(arg, "asm") == 0) { - cmd = CmdAsm; } else { fprintf(stderr, "Unrecognized command: %s\n", arg); return usage(arg0); @@ -407,16 +391,12 @@ int main(int argc, char **argv) { case CmdBuild: case CmdParseH: case CmdTest: - case CmdAsm: if (!in_file) { in_file = arg; } else { return usage(arg0); } break; - case CmdLink: - objects.append(arg); - break; case CmdVersion: case CmdTargets: return usage(arg0); @@ -430,25 +410,19 @@ int main(int argc, char **argv) { case CmdBuild: case CmdParseH: case CmdTest: - case CmdAsm: - case CmdLink: { - bool one_source_input = (cmd == CmdBuild || cmd == CmdParseH || cmd == CmdTest || cmd == CmdAsm); - if (one_source_input) { - if (!in_file) { - fprintf(stderr, "Expected source file argument.\n"); - return usage(arg0); - } - } else if (cmd == CmdLink) { - if (objects.length == 0) { - fprintf(stderr, "Expected one or more object arguments.\n"); - return usage(arg0); - } - } else { - zig_unreachable(); + if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) { + fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n"); + return usage(arg0); + } else if ((cmd == CmdParseH || cmd == CmdTest) && !in_file) { + fprintf(stderr, "Expected source file argument.\n"); + return usage(arg0); + } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) { + fprintf(stderr, "When building an object file, --object arguments are invalid.\n"); + return usage(arg0); } - assert((cmd != CmdBuild && cmd != CmdLink) || out_type != OutTypeUnknown); + assert(cmd != CmdBuild || out_type != OutTypeUnknown); init_all_targets(); @@ -479,45 +453,22 @@ int main(int argc, char **argv) { } } - bool need_name = (cmd == CmdBuild || cmd == CmdAsm || cmd == CmdLink || cmd == CmdParseH); + bool need_name = (cmd == CmdBuild || cmd == CmdParseH); - Buf in_file_buf = BUF_INIT; - - Buf root_source_dir = BUF_INIT; - Buf root_source_code = BUF_INIT; - Buf root_source_name = BUF_INIT; + Buf *in_file_buf = nullptr; Buf *buf_out_name = (cmd == CmdTest) ? buf_create_from_str("test") : (out_name == nullptr) ? nullptr : buf_create_from_str(out_name); - if (one_source_input) { - buf_init_from_str(&in_file_buf, in_file); + if (in_file) { + in_file_buf = buf_create_from_str(in_file); - if (buf_eql_str(&in_file_buf, "-")) { - os_get_cwd(&root_source_dir); - if ((err = os_fetch_file(stdin, &root_source_code))) { - fprintf(stderr, "unable to read stdin: %s\n", err_str(err)); - return 1; - } - buf_init_from_str(&root_source_name, ""); - - } else { - os_path_split(&in_file_buf, &root_source_dir, &root_source_name); - if ((err = os_fetch_file_path(buf_create_from_str(in_file), &root_source_code))) { - fprintf(stderr, "unable to open '%s': %s\n", in_file, err_str(err)); - return 1; - } - - if (need_name && buf_out_name == nullptr) { - buf_out_name = buf_alloc(); - Buf ext_name = BUF_INIT; - os_path_extname(&root_source_name, buf_out_name, &ext_name); - } + if (need_name && buf_out_name == nullptr) { + Buf basename = BUF_INIT; + os_path_split(in_file_buf, nullptr, &basename); + buf_out_name = buf_alloc(); + os_path_extname(&basename, buf_out_name, nullptr); } - } else if (cmd == CmdLink) { - os_get_cwd(&root_source_dir); - } else { - zig_unreachable(); } if (need_name && buf_out_name == nullptr) { @@ -525,7 +476,10 @@ int main(int argc, char **argv) { return usage(arg0); } - CodeGen *g = codegen_create(&root_source_dir, target); + Buf *zig_root_source_file = (cmd == CmdParseH) ? nullptr : in_file_buf; + + CodeGen *g = codegen_create(zig_root_source_file, target); + codegen_set_out_name(g, buf_out_name); codegen_set_lib_version(g, ver_major, ver_minor, ver_patch); codegen_set_is_release(g, is_release_build); codegen_set_is_test(g, cmd == CmdTest); @@ -536,14 +490,11 @@ int main(int argc, char **argv) { codegen_set_clang_argv(g, clang_argv.items, clang_argv.length); codegen_set_strip(g, strip); codegen_set_is_static(g, is_static); - if (cmd == CmdAsm) { - codegen_set_out_type(g, OutTypeObj); - } else if (out_type != OutTypeUnknown) { + if (out_type != OutTypeUnknown) { codegen_set_out_type(g, out_type); } else if (cmd == CmdTest) { codegen_set_out_type(g, OutTypeExe); } - codegen_set_out_name(g, buf_out_name); if (libc_lib_dir) codegen_set_libc_lib_dir(g, buf_create_from_str(libc_lib_dir)); if (libc_static_lib_dir) @@ -598,33 +549,25 @@ int main(int argc, char **argv) { } if (cmd == CmdBuild) { - codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code); - codegen_link(g, out_file); - if (timing_info) - codegen_print_timing_report(g, stderr); - return EXIT_SUCCESS; - } else if (cmd == CmdLink) { for (size_t i = 0; i < objects.length; i += 1) { codegen_add_object(g, buf_create_from_str(objects.at(i))); } - codegen_link(g, out_file); - if (timing_info) - codegen_print_timing_report(g, stderr); - return EXIT_SUCCESS; - } else if (cmd == CmdAsm) { - codegen_add_root_assembly(g, &root_source_dir, &root_source_name, &root_source_code); + for (size_t i = 0; i < asm_files.length; i += 1) { + codegen_add_assembly(g, buf_create_from_str(asm_files.at(i))); + } + codegen_build(g); codegen_link(g, out_file); if (timing_info) codegen_print_timing_report(g, stderr); return EXIT_SUCCESS; } else if (cmd == CmdParseH) { - codegen_parseh(g, &root_source_dir, &root_source_name, &root_source_code); + codegen_parseh(g, in_file_buf); ast_render_decls(g, stdout, 4, g->root_import); if (timing_info) codegen_print_timing_report(g, stderr); return EXIT_SUCCESS; } else if (cmd == CmdTest) { - codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code); + codegen_build(g); codegen_link(g, "./test"); ZigList args = {0}; Termination term; diff --git a/src/os.cpp b/src/os.cpp index 472a572e3b..adf723c445 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -146,24 +146,28 @@ 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) { if (buf_len(full_path) == 0) { - buf_init_from_str(out_basename, ""); - buf_init_from_str(out_extname, ""); + if (out_basename) buf_init_from_str(out_basename, ""); + if (out_extname) buf_init_from_str(out_extname, ""); return; } size_t i = buf_len(full_path) - 1; while (true) { if (buf_ptr(full_path)[i] == '.') { - buf_resize(out_basename, 0); - buf_append_mem(out_basename, buf_ptr(full_path), i); + if (out_basename) { + buf_resize(out_basename, 0); + buf_append_mem(out_basename, buf_ptr(full_path), i); + } - buf_resize(out_extname, 0); - buf_append_mem(out_extname, buf_ptr(full_path) + i, buf_len(full_path) - i); + if (out_extname) { + buf_resize(out_extname, 0); + buf_append_mem(out_extname, buf_ptr(full_path) + i, buf_len(full_path) - i); + } return; } if (i == 0) { - buf_init_from_buf(out_basename, full_path); - buf_init_from_str(out_extname, ""); + if (out_basename) buf_init_from_buf(out_basename, full_path); + if (out_extname) buf_init_from_str(out_extname, ""); return; } i -= 1; diff --git a/std/build.zig b/std/build.zig index 09297c05ca..46155ade3f 100644 --- a/std/build.zig +++ b/std/build.zig @@ -120,28 +120,22 @@ pub const Builder = struct { self.lib_dir = %%os.path.join(self.allocator, self.prefix, "lib"); } - pub fn addExecutable(self: &Builder, name: []const u8, root_src: []const u8) -> &LibOrExeStep { - const exe = %%self.allocator.create(LibOrExeStep); - *exe = LibOrExeStep.initExecutable(self, name, root_src); - return exe; + pub fn addExecutable(self: &Builder, name: []const u8, root_src: ?[]const u8) -> &LibExeObjStep { + return LibExeObjStep.createExecutable(self, name, root_src); } - pub fn addObject(self: &Builder, name: []const u8, root_src: []const u8) -> &ObjectStep { - const obj_step = %%self.allocator.create(ObjectStep); - *obj_step = ObjectStep.init(self, name, root_src); - return obj_step; + pub fn addObject(self: &Builder, name: []const u8, root_src: []const u8) -> &LibExeObjStep { + return LibExeObjStep.createObject(self, name, root_src); } - pub fn addSharedLibrary(self: &Builder, name: []const u8, root_src: []const u8, ver: &const Version) -> &LibOrExeStep { - const lib_step = %%self.allocator.create(LibOrExeStep); - *lib_step = LibOrExeStep.initSharedLibrary(self, name, root_src, ver); - return lib_step; + pub fn addSharedLibrary(self: &Builder, name: []const u8, root_src: ?[]const u8, + ver: &const Version) -> &LibExeObjStep + { + return LibExeObjStep.createSharedLibrary(self, name, root_src, ver); } - pub fn addStaticLibrary(self: &Builder, name: []const u8, root_src: []const u8) -> &LibOrExeStep { - const lib_step = %%self.allocator.create(LibOrExeStep); - *lib_step = LibOrExeStep.initStaticLibrary(self, name, root_src); - return lib_step; + pub fn addStaticLibrary(self: &Builder, name: []const u8, root_src: ?[]const u8) -> &LibExeObjStep { + return LibExeObjStep.createStaticLibrary(self, name, root_src); } pub fn addTest(self: &Builder, root_src: []const u8) -> &TestStep { @@ -150,28 +144,10 @@ pub const Builder = struct { return test_step; } - pub fn addAssemble(self: &Builder, name: []const u8, src: []const u8) -> &AsmStep { - const asm_step = %%self.allocator.create(AsmStep); - *asm_step = AsmStep.init(self, name, src); - return asm_step; - } - - pub fn addLinkExecutable(self: &Builder, name: []const u8) -> &LinkStep { - const exe = %%self.allocator.create(LinkStep); - *exe = LinkStep.initExecutable(self, name); - return exe; - } - - pub fn addLinkStaticLibrary(self: &Builder, name: []const u8) -> &LinkStep { - const exe = %%self.allocator.create(LinkStep); - *exe = LinkStep.initStaticLibrary(self, name); - return exe; - } - - pub fn addLinkSharedLibrary(self: &Builder, name: []const u8, ver: &const Version) -> &LinkStep { - const exe = %%self.allocator.create(LinkStep); - *exe = LinkStep.initSharedLibrary(self, name, ver); - return exe; + pub fn addAssemble(self: &Builder, name: []const u8, src: []const u8) -> &LibExeObjStep { + const obj_step = LibExeObjStep.createObject(self, name, null); + obj_step.addAssemblyFile(src); + return obj_step; } pub fn addCStaticLibrary(self: &Builder, name: []const u8) -> &CLibrary { @@ -635,10 +611,10 @@ const LinkerScript = enum { Path: []const u8, }; -pub const LibOrExeStep = struct { +pub const LibExeObjStep = struct { step: Step, builder: &Builder, - root_src: []const u8, + root_src: ?[]const u8, name: []const u8, target: Target, linker_script: LinkerScript, @@ -652,30 +628,45 @@ pub const LibOrExeStep = struct { out_filename: []const u8, out_filename_major_only: []const u8, out_filename_name_only: []const u8, + object_files: List([]const u8), + assembly_files: List([]const u8), const Kind = enum { Exe, Lib, + Obj, }; - pub fn initExecutable(builder: &Builder, name: []const u8, root_src: []const u8) -> LibOrExeStep { - return initExtraArgs(builder, name, root_src, Kind.Exe, false, builder.version(0, 0, 0)); - } - - pub fn initSharedLibrary(builder: &Builder, name: []const u8, root_src: []const u8, - ver: &const Version) -> LibOrExeStep + pub fn createSharedLibrary(builder: &Builder, name: []const u8, root_src: ?[]const u8, + ver: &const Version) -> &LibExeObjStep { - return initExtraArgs(builder, name, root_src, Kind.Lib, false, ver); + const self = %%builder.allocator.create(LibExeObjStep); + *self = initExtraArgs(builder, name, root_src, Kind.Lib, false, ver); + return self; } - pub fn initStaticLibrary(builder: &Builder, name: []const u8, root_src: []const u8) -> LibOrExeStep { - return initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0)); + pub fn createStaticLibrary(builder: &Builder, name: []const u8, root_src: ?[]const u8) -> &LibExeObjStep { + const self = %%builder.allocator.create(LibExeObjStep); + *self = initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0)); + return self; } - fn initExtraArgs(builder: &Builder, name: []const u8, root_src: []const u8, kind: Kind, - static: bool, ver: &const Version) -> LibOrExeStep + pub fn createObject(builder: &Builder, name: []const u8, root_src: []const u8) -> &LibExeObjStep { + const self = %%builder.allocator.create(LibExeObjStep); + *self = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0)); + return self; + } + + pub fn createExecutable(builder: &Builder, name: []const u8, root_src: ?[]const u8) -> &LibExeObjStep { + const self = %%builder.allocator.create(LibExeObjStep); + *self = initExtraArgs(builder, name, root_src, Kind.Exe, false, builder.version(0, 0, 0)); + return self; + } + + fn initExtraArgs(builder: &Builder, name: []const u8, root_src: ?[]const u8, kind: Kind, + static: bool, ver: &const Version) -> LibExeObjStep { - var self = LibOrExeStep { + var self = LibExeObjStep { .builder = builder, .verbose = false, .release = false, @@ -692,13 +683,18 @@ pub const LibOrExeStep = struct { .out_filename = undefined, .out_filename_major_only = undefined, .out_filename_name_only = undefined, + .object_files = List([]const u8).init(builder.allocator), + .assembly_files = List([]const u8).init(builder.allocator), }; self.computeOutFileNames(); return self; } - fn computeOutFileNames(self: &LibOrExeStep) { + fn computeOutFileNames(self: &LibExeObjStep) { switch (self.kind) { + Kind.Obj => { + self.out_filename = self.builder.fmt("{}{}", self.name, self.target.oFileExt()); + }, Kind.Exe => { self.out_filename = self.builder.fmt("{}{}", self.name, self.target.exeFileExt()); }, @@ -715,7 +711,7 @@ pub const LibOrExeStep = struct { } } - pub fn setTarget(self: &LibOrExeStep, target_arch: Arch, target_os: Os, target_environ: Environ) { + pub fn setTarget(self: &LibExeObjStep, target_arch: Arch, target_os: Os, target_environ: Environ) { self.target = Target.Cross { CrossTarget { .arch = target_arch, @@ -723,47 +719,93 @@ pub const LibOrExeStep = struct { .environ = target_environ, } }; + self.computeOutFileNames(); } - /// LibOrExeStep keeps a reference to script for its lifetime or until this function + /// LibExeObjStep keeps a reference to script for its lifetime or until this function /// is called again. - pub fn setLinkerScriptContents(self: &LibOrExeStep, script: []const u8) { + pub fn setLinkerScriptContents(self: &LibExeObjStep, script: []const u8) { self.linker_script = LinkerScript.Embed { script }; } - pub fn setLinkerScriptPath(self: &LibOrExeStep, path: []const u8) { + pub fn setLinkerScriptPath(self: &LibExeObjStep, path: []const u8) { self.linker_script = LinkerScript.Path { path }; } - pub fn linkSystemLibrary(self: &LibOrExeStep, name: []const u8) { + pub fn linkSystemLibrary(self: &LibExeObjStep, name: []const u8) { %%self.link_libs.put(name); } - pub fn setVerbose(self: &LibOrExeStep, value: bool) { + pub fn setVerbose(self: &LibExeObjStep, value: bool) { self.verbose = value; } - pub fn setRelease(self: &LibOrExeStep, value: bool) { + pub fn setRelease(self: &LibExeObjStep, value: bool) { self.release = value; } - pub fn setOutputPath(self: &LibOrExeStep, value: []const u8) { + pub fn setOutputPath(self: &LibExeObjStep, value: []const u8) { self.output_path = value; } + pub fn addAssemblyFile(self: &LibExeObjStep, path: []const u8) { + %%self.assembly_files.append(path); + } + + pub fn addObjectFile(self: &LibExeObjStep, path: []const u8) { + assert(self.kind != Kind.Obj); + + %%self.object_files.append(path); + } + + pub fn addObject(self: &LibExeObjStep, obj: &LibExeObjStep) { + assert(obj.kind == Kind.Obj); + assert(self.kind != Kind.Obj); + + self.step.dependOn(&obj.step); + + const path_to_obj = test (obj.output_path) |explicit_out_path| { + explicit_out_path + } else { + // TODO make it so we always know where this will be + %%os.path.join(self.builder.allocator, self.builder.out_dir, + self.builder.fmt("{}{}", obj.name, obj.target.oFileExt())) + }; + %%self.object_files.append(path_to_obj); + } + fn make(step: &Step) -> %void { - const self = @fieldParentPtr(LibOrExeStep, "step", step); + const self = @fieldParentPtr(LibExeObjStep, "step", step); const builder = self.builder; + if (self.root_src == null and self.object_files.len == 0 and self.assembly_files.len == 0) { + %%io.stderr.printf("{}: linker needs 1 or more objects to link\n", step.name); + return error.NeedAnObject; + } + var zig_args = List([]const u8).init(builder.allocator); defer zig_args.deinit(); const cmd = switch (self.kind) { Kind.Lib => "build_lib", Kind.Exe => "build_exe", + Kind.Obj => "build_obj", }; %%zig_args.append(cmd); - %%zig_args.append(builder.pathFromRoot(self.root_src)); + + test (self.root_src) |root_src| { + %%zig_args.append(builder.pathFromRoot(root_src)); + } + + for (self.object_files.toSliceConst()) |object_file| { + %%zig_args.append("--object"); + %%zig_args.append(builder.pathFromRoot(object_file)); + } + + for (self.assembly_files.toSliceConst()) |asm_file| { + %%zig_args.append("--assembly"); + %%zig_args.append(builder.pathFromRoot(asm_file)); + } if (self.verbose) { %%zig_args.append("--verbose"); @@ -856,437 +898,6 @@ pub const LibOrExeStep = struct { } }; -pub const ObjectStep = struct { - step: Step, - builder: &Builder, - root_src: []const u8, - name: []const u8, - target: Target, - verbose: bool, - release: bool, - output_path: ?[]const u8, - - pub fn init(builder: &Builder, name: []const u8, root_src: []const u8) -> ObjectStep { - ObjectStep { - .builder = builder, - .verbose = false, - .release = false, - .root_src = root_src, - .name = name, - .target = Target.Native, - .step = Step.init(name, builder.allocator, make), - .output_path = null, - } - } - - pub fn setTarget(self: &ObjectStep, target_arch: Arch, target_os: Os, target_environ: Environ) { - self.target = Target.Cross { - CrossTarget { - .arch = target_arch, - .os = target_os, - .environ = target_environ, - } - }; - } - - pub fn setVerbose(self: &ObjectStep, value: bool) { - self.verbose = value; - } - - pub fn setRelease(self: &ObjectStep, value: bool) { - self.release = value; - } - - pub fn setOutputPath(self: &ObjectStep, value: []const u8) { - self.output_path = value; - } - - fn make(step: &Step) -> %void { - const self = @fieldParentPtr(ObjectStep, "step", step); - const builder = self.builder; - - var zig_args = List([]const u8).init(builder.allocator); - defer zig_args.deinit(); - - %%zig_args.append("build_obj"); - %%zig_args.append(builder.pathFromRoot(self.root_src)); - - if (self.verbose) { - %%zig_args.append("--verbose"); - } - - if (self.release) { - %%zig_args.append("--release"); - } - - test (self.output_path) |output_path| { - %%zig_args.append("--output"); - %%zig_args.append(builder.pathFromRoot(output_path)); - } - - %%zig_args.append("--name"); - %%zig_args.append(self.name); - - switch (self.target) { - Target.Native => {}, - Target.Cross => |cross_target| { - %%zig_args.append("--target-arch"); - %%zig_args.append(@enumTagName(cross_target.arch)); - - %%zig_args.append("--target-os"); - %%zig_args.append(@enumTagName(cross_target.os)); - - %%zig_args.append("--target-environ"); - %%zig_args.append(@enumTagName(cross_target.environ)); - }, - } - - for (builder.include_paths.toSliceConst()) |include_path| { - %%zig_args.append("-isystem"); - %%zig_args.append(include_path); - } - - for (builder.rpaths.toSliceConst()) |rpath| { - %%zig_args.append("-rpath"); - %%zig_args.append(rpath); - } - - for (builder.lib_paths.toSliceConst()) |lib_path| { - %%zig_args.append("--library-path"); - %%zig_args.append(lib_path); - } - - %%builder.spawnChild(builder.zig_exe, zig_args.toSliceConst()); - } -}; - -pub const AsmStep = struct { - step: Step, - builder: &Builder, - name: []const u8, - target: Target, - verbose: bool, - release: bool, - output_path: ?[]const u8, - src_path: []const u8, - - pub fn init(builder: &Builder, name: []const u8, src_path: []const u8) -> AsmStep { - var self = AsmStep { - .step = Step.init(name, builder.allocator, make), - .builder = builder, - .name = name, - .target = Target.Native, - .verbose = false, - .release = false, - .output_path = null, - .src_path = src_path, - }; - return self; - } - - pub fn setTarget(self: &AsmStep, target_arch: Arch, target_os: Os, target_environ: Environ) { - self.target = Target.Cross { - CrossTarget { - .arch = target_arch, - .os = target_os, - .environ = target_environ, - } - }; - } - - pub fn setVerbose(self: &AsmStep, value: bool) { - self.verbose = value; - } - - pub fn setRelease(self: &AsmStep, value: bool) { - self.release = value; - } - - pub fn setOutputPath(self: &AsmStep, value: []const u8) { - self.output_path = value; - } - - fn make(step: &Step) -> %void { - const self = @fieldParentPtr(AsmStep, "step", step); - const builder = self.builder; - - var zig_args = List([]const u8).init(builder.allocator); - defer zig_args.deinit(); - - %%zig_args.append("asm"); - %%zig_args.append(builder.pathFromRoot(self.src_path)); - - if (self.verbose) { - %%zig_args.append("--verbose"); - } - - if (self.release) { - %%zig_args.append("--release"); - } - - test (self.output_path) |output_path| { - %%zig_args.append("--output"); - %%zig_args.append(builder.pathFromRoot(output_path)); - } - - %%zig_args.append("--name"); - %%zig_args.append(self.name); - - switch (self.target) { - Target.Native => {}, - Target.Cross => |cross_target| { - %%zig_args.append("--target-arch"); - %%zig_args.append(@enumTagName(cross_target.arch)); - - %%zig_args.append("--target-os"); - %%zig_args.append(@enumTagName(cross_target.os)); - - %%zig_args.append("--target-environ"); - %%zig_args.append(@enumTagName(cross_target.environ)); - }, - } - - %%builder.spawnChild(builder.zig_exe, zig_args.toSliceConst()); - } -}; - -pub const LinkStep = struct { - step: Step, - builder: &Builder, - name: []const u8, - target: Target, - linker_script: LinkerScript, - link_libs: BufSet, - verbose: bool, - release: bool, - output_path: ?[]const u8, - object_files: List([]const u8), - static: bool, - out_filename: []const u8, - out_type: OutType, - version: Version, - major_only_filename: []const u8, - name_only_filename: []const u8, - - const OutType = enum { - Exe, - Lib, - }; - - pub fn initExecutable(builder: &Builder, name: []const u8) -> LinkStep { - return init(builder, name, OutType.Exe, builder.version(0, 0, 0), false) - } - - pub fn initSharedLibrary(builder: &Builder, name: []const u8, version: &const Version) -> LinkStep { - return init(builder, name, OutType.Lib, version, false) - } - - pub fn initStaticLibrary(builder: &Builder, name: []const u8) -> LinkStep { - return init(builder, name, OutType.Lib, builder.version(0, 0, 0), true) - } - - fn init(builder: &Builder, name: []const u8, out_type: OutType, version: &const Version, static: bool) -> LinkStep { - var self = LinkStep { - .builder = builder, - .verbose = false, - .release = false, - .name = name, - .target = Target.Native, - .linker_script = LinkerScript.None, - .link_libs = BufSet.init(builder.allocator), - .step = Step.init(name, builder.allocator, make), - .output_path = null, - .object_files = List([]const u8).init(builder.allocator), - .out_type = out_type, - .version = *version, - .static = static, - .out_filename = undefined, - .major_only_filename = undefined, - .name_only_filename = undefined, - }; - self.computeOutFileName(); - return self; - } - - fn computeOutFileName(self: &LinkStep) { - switch (self.out_type) { - OutType.Exe => { - self.out_filename = self.builder.fmt("{}{}", self.name, self.target.exeFileExt()); - }, - OutType.Lib => { - if (self.static) { - self.out_filename = self.builder.fmt("lib{}.a", self.name); - } else { - self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}", - self.name, self.version.major, self.version.minor, self.version.patch); - self.major_only_filename = self.builder.fmt("lib{}.so.{d}", self.name, self.version.major); - self.name_only_filename = self.builder.fmt("lib{}.so", self.name); - } - }, - } - } - - pub fn addObjectFile(self: &LinkStep, file: []const u8) { - %%self.object_files.append(file); - } - - pub fn addObject(self: &LinkStep, obj: &ObjectStep) { - self.step.dependOn(&obj.step); - - const path_to_obj = test (obj.output_path) |explicit_out_path| { - explicit_out_path - } else { - // TODO make it so we always know where this will be - %%os.path.join(self.builder.allocator, self.builder.out_dir, - self.builder.fmt("{}{}", obj.name, obj.target.oFileExt())) - }; - %%self.object_files.append(path_to_obj); - } - - pub fn addAssembly(self: &LinkStep, assembly: &AsmStep) { - self.step.dependOn(&assembly.step); - - const path_to_obj = test (assembly.output_path) |explicit_out_path| { - explicit_out_path - } else { - // TODO make it so we always know where this will be - %%os.path.join(self.builder.allocator, self.builder.out_dir, - self.builder.fmt("{}{}", assembly.name, assembly.target.oFileExt())) - }; - %%self.object_files.append(path_to_obj); - } - - pub fn setTarget(self: &LinkStep, target_arch: Arch, target_os: Os, target_environ: Environ) { - self.target = Target.Cross { - CrossTarget { - .arch = target_arch, - .os = target_os, - .environ = target_environ, - } - }; - self.computeOutFileName(); - } - - /// LinkStep keeps a reference to script for its lifetime or until this function - /// is called again. - pub fn setLinkerScriptContents(self: &LinkStep, script: []const u8) { - self.linker_script = LinkerScript.Embed { script }; - } - - pub fn setLinkerScriptPath(self: &LinkStep, path: []const u8) { - self.linker_script = LinkerScript.Path { path }; - } - - pub fn linkSystemLibrary(self: &LinkStep, name: []const u8) { - %%self.link_libs.put(name); - } - - pub fn setVerbose(self: &LinkStep, value: bool) { - self.verbose = value; - } - - pub fn setRelease(self: &LinkStep, value: bool) { - self.release = value; - } - - pub fn setOutputPath(self: &LinkStep, value: []const u8) { - self.output_path = value; - } - - fn make(step: &Step) -> %void { - const self = @fieldParentPtr(LinkStep, "step", step); - const builder = self.builder; - - if (self.object_files.len == 0) { - %%io.stderr.printf("{}: linker needs 1 or more objects to link\n", step.name); - return error.NeedAnObject; - } - - var zig_args = List([]const u8).init(builder.allocator); - defer zig_args.deinit(); - - const cmd = switch (self.out_type) { - OutType.Exe => "link_exe", - OutType.Lib => "link_lib", - }; - %%zig_args.append(cmd); - - for (self.object_files.toSliceConst()) |object_file| { - %%zig_args.append(builder.pathFromRoot(object_file)); - } - - if (self.verbose) { - %%zig_args.append("--verbose"); - } - - if (self.release) { - %%zig_args.append("--release"); - } - - if (self.static) { - %%zig_args.append("--static"); - } - - test (self.output_path) |output_path| { - %%zig_args.append("--output"); - %%zig_args.append(builder.pathFromRoot(output_path)); - } - - %%zig_args.append("--name"); - %%zig_args.append(self.name); - - switch (self.target) { - Target.Native => {}, - Target.Cross => |cross_target| { - %%zig_args.append("--target-arch"); - %%zig_args.append(@enumTagName(cross_target.arch)); - - %%zig_args.append("--target-os"); - %%zig_args.append(@enumTagName(cross_target.os)); - - %%zig_args.append("--target-environ"); - %%zig_args.append(@enumTagName(cross_target.environ)); - }, - } - - switch (self.linker_script) { - LinkerScript.None => {}, - LinkerScript.Embed => |script| { - const tmp_file_name = "linker.ld.tmp"; // TODO issue #298 - io.writeFile(tmp_file_name, script, builder.allocator) - %% |err| debug.panic("unable to write linker script: {}\n", @errorName(err)); - %%zig_args.append("--linker-script"); - %%zig_args.append(tmp_file_name); - }, - LinkerScript.Path => |path| { - %%zig_args.append("--linker-script"); - %%zig_args.append(path); - }, - } - - { - var it = self.link_libs.iterator(); - while (true) { - const entry = it.next() ?? break; - %%zig_args.append("--library"); - %%zig_args.append(entry.key); - } - } - - for (builder.rpaths.toSliceConst()) |rpath| { - %%zig_args.append("-rpath"); - %%zig_args.append(rpath); - } - - for (builder.lib_paths.toSliceConst()) |lib_path| { - %%zig_args.append("--library-path"); - %%zig_args.append(lib_path); - } - - %%builder.spawnChild(builder.zig_exe, zig_args.toSliceConst()); - } -}; - pub const TestStep = struct { step: Step, builder: &Builder, @@ -1592,15 +1203,17 @@ pub const CExecutable = struct { %%self.full_path_libs.append(clib.out_filename); } - pub fn linkLibrary(self: &CExecutable, lib: &LibOrExeStep) { - assert(lib.kind == LibOrExeStep.Kind.Lib); + pub fn linkLibrary(self: &CExecutable, lib: &LibExeObjStep) { + assert(lib.kind == LibExeObjStep.Kind.Lib); self.step.dependOn(&lib.step); %%self.full_path_libs.append(lib.out_filename); // TODO should be some kind of isolated directory that only has this header in it %%self.include_dirs.append(self.builder.out_dir); } - pub fn addObject(self: &CExecutable, obj: &ObjectStep) { + pub fn addObject(self: &CExecutable, obj: &LibExeObjStep) { + assert(obj.kind == LibExeObjStep.Kind.Obj); + self.step.dependOn(&obj.step); // TODO make it so we always know where this will be diff --git a/std/debug.zig b/std/debug.zig index 862a7d96b8..cbd12dc639 100644 --- a/std/debug.zig +++ b/std/debug.zig @@ -90,7 +90,11 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty // at compile time. I'll call it issue #313 const ptr_hex = if (@sizeOf(usize) == 4) "0x{x8}" else "0x{x16}"; - const compile_unit = findCompileUnit(st, return_address) ?? return error.MissingDebugInfo; + const compile_unit = findCompileUnit(st, return_address) ?? { + %return out_stream.print(DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n\n\n", return_address); + %return out_stream.flush(); + continue; + }; const compile_unit_name = %return compile_unit.die.getAttrString(st, DW.AT_name); try (getLineNumberInfo(st, compile_unit, usize(return_address) - 1)) |line_info| { defer line_info.deinit(); diff --git a/test/cases/cast.zig b/test/cases/cast.zig index f6425ee464..a9c7b068a4 100644 --- a/test/cases/cast.zig +++ b/test/cases/cast.zig @@ -150,3 +150,12 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) -> []const u8 { return slice[0...1]; } + +test "implicitly cast from [N]T to ?[]const T" { + assert(mem.eql(u8, ??castToMaybeSlice(), "hi")); + comptime assert(mem.eql(u8, ??castToMaybeSlice(), "hi")); +} + +fn castToMaybeSlice() -> ?[]const u8 { + return "hi"; +} diff --git a/test/tests.zig b/test/tests.zig index d115ed037a..b89a47eff7 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -355,18 +355,16 @@ pub const CompareOutputContext = struct { return; } - const assembly = b.addAssemble("test", root_src); + const exe = b.addExecutable("test", null); + exe.addAssemblyFile(root_src); + exe.setOutputPath(exe_path); for (case.sources.toSliceConst()) |src_file| { const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename); const write_src = b.addWriteFile(expanded_src_path, src_file.source); - assembly.step.dependOn(&write_src.step); + exe.step.dependOn(&write_src.step); } - const exe = b.addLinkExecutable("test"); - exe.addAssembly(assembly); - exe.setOutputPath(exe_path); - const run_and_cmp_output = RunCompareOutputStep.create(self, exe_path, annotated_case_name, case.expected_output); run_and_cmp_output.step.dependOn(&exe.step);