diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-02-25 16:30:40 -0500 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-02-25 16:30:40 -0500 |
| commit | f33bf48af7d9c99d532864f8a6c3f695ad5bbd21 (patch) | |
| tree | fa39bd6b654178e653d06e1c79f22ad1d29cd526 /src/main.cpp | |
| parent | 64365bc5d7b1e2c507806ee8976acc3479ad7862 (diff) | |
| parent | 416a547cdb8dbbf3d2e7ce32132f0a25f2a8607e (diff) | |
| download | zig-f33bf48af7d9c99d532864f8a6c3f695ad5bbd21.tar.gz zig-f33bf48af7d9c99d532864f8a6c3f695ad5bbd21.zip | |
Merge remote-tracking branch 'origin/master' into llvm10
Diffstat (limited to 'src/main.cpp')
| -rw-r--r-- | src/main.cpp | 239 |
1 files changed, 151 insertions, 88 deletions
diff --git a/src/main.cpp b/src/main.cpp index 9e16b516bd..299b9cf9fe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,8 +14,7 @@ #include "heap.hpp" #include "os.hpp" #include "target.hpp" -#include "libc_installation.hpp" -#include "userland.h" +#include "stage2.h" #include "glibc.hpp" #include "dump_analysis.hpp" #include "mem_profile.hpp" @@ -63,17 +62,21 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " -fno-stack-check disable stack probing in safe builds\n" " -fsanitize-c enable C undefined behavior detection in unsafe builds\n" " -fno-sanitize-c disable C undefined behavior detection in safe builds\n" - " --emit [asm|bin|llvm-ir] emit a specific file format as compilation output\n" + " --emit [asm|bin|llvm-ir] (deprecated) emit a specific file format as compilation output\n" " -fPIC enable Position Independent Code\n" " -fno-PIC disable Position Independent Code\n" " -ftime-report print timing diagnostics\n" " -fstack-report print stack size diagnostics\n" -#ifdef ZIG_ENABLE_MEM_PROFILE " -fmem-report print memory usage diagnostics\n" -#endif " -fdump-analysis write analysis.json file with type information\n" " -femit-docs create a docs/ dir with html documentation\n" - " -fno-emit-bin skip emitting machine code\n" + " -fno-emit-docs do not produce docs/ dir with html documentation\n" + " -femit-bin (default) output machine code\n" + " -fno-emit-bin do not output machine code\n" + " -femit-asm output .s (assembly code)\n" + " -fno-emit-asm (default) do not output .s (assembly code)\n" + " -femit-llvm-ir produce a .ll file with LLVM IR\n" + " -fno-emit-llvm-ir (default) do not produce a .ll file with LLVM IR\n" " --libc [file] Provide a file which specifies libc paths\n" " --name [name] override output name\n" " --output-dir [dir] override output directory (defaults to cwd)\n" @@ -103,8 +106,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " --override-lib-dir [arg] override path to Zig lib directory\n" " -ffunction-sections places each function in a separate section\n" " -D[macro]=[value] define C [macro] to [value] (1 if [value] omitted)\n" - " -target-cpu [cpu] target one specific CPU by name\n" - " -target-feature [features] specify the set of CPU features to target\n" + " -mcpu [cpu] specify target CPU and feature set\n" " -code-model [default|tiny| set target code model\n" " small|kernel|\n" " medium|large]\n" @@ -235,6 +237,14 @@ static int zig_error_no_build_file(void) { return EXIT_FAILURE; } +static bool str_starts_with(const char *s1, const char *s2) { + size_t s2_len = strlen(s2); + if (strlen(s1) < s2_len) { + return false; + } + return memcmp(s1, s2, s2_len) == 0; +} + extern "C" int ZigClang_main(int argc, char **argv); #ifdef ZIG_ENABLE_MEM_PROFILE @@ -378,7 +388,6 @@ static int main0(int argc, char **argv) { } Cmd cmd = CmdNone; - EmitFileType emit_file_type = EmitFileTypeBinary; const char *in_file = nullptr; Buf *output_dir = nullptr; bool strip = false; @@ -426,7 +435,9 @@ static int main0(int argc, char **argv) { bool stack_report = false; bool enable_dump_analysis = false; bool enable_doc_generation = false; - bool disable_bin_generation = false; + bool emit_bin = true; + bool emit_asm = false; + bool emit_llvm_ir = false; const char *cache_dir = nullptr; CliPkg *cur_pkg = heap::c_allocator.create<CliPkg>(); BuildMode build_mode = BuildModeDebug; @@ -444,8 +455,7 @@ static int main0(int argc, char **argv) { WantStackCheck want_stack_check = WantStackCheckAuto; WantCSanitize want_sanitize_c = WantCSanitizeAuto; bool function_sections = false; - const char *cpu = nullptr; - const char *features = nullptr; + const char *mcpu = nullptr; CodeModel code_model = CodeModelDefault; ZigList<const char *> llvm_argv = {0}; @@ -554,7 +564,7 @@ static int main0(int argc, char **argv) { } Termination term; - args.items[0] = buf_ptr(&g->output_file_path); + args.items[0] = buf_ptr(&g->bin_file_output_path); os_spawn_process(args, &term); if (term.how != TerminationIdClean || term.code != 0) { fprintf(stderr, "\nBuild failed. The following command failed:\n"); @@ -633,8 +643,6 @@ static int main0(int argc, char **argv) { enable_dump_analysis = true; } else if (strcmp(arg, "-femit-docs") == 0) { enable_doc_generation = true; - } else if (strcmp(arg, "-fno-emit-bin") == 0) { - disable_bin_generation = true; } else if (strcmp(arg, "--enable-valgrind") == 0) { valgrind_support = ValgrindSupportEnabled; } else if (strcmp(arg, "--disable-valgrind") == 0) { @@ -703,6 +711,20 @@ static int main0(int argc, char **argv) { function_sections = true; } else if (strcmp(arg, "--test-evented-io") == 0) { test_evented_io = true; + } else if (strcmp(arg, "-femit-bin") == 0) { + emit_bin = true; + } else if (strcmp(arg, "-fno-emit-bin") == 0) { + emit_bin = false; + } else if (strcmp(arg, "-femit-asm") == 0) { + emit_asm = true; + } else if (strcmp(arg, "-fno-emit-asm") == 0) { + emit_asm = false; + } else if (strcmp(arg, "-femit-llvm-ir") == 0) { + emit_llvm_ir = true; + } else if (strcmp(arg, "-fno-emit-llvm-ir") == 0) { + emit_llvm_ir = false; + } else if (str_starts_with(arg, "-mcpu=")) { + mcpu = arg + strlen("-mcpu="); } else if (i + 1 >= argc) { fprintf(stderr, "Expected another argument after %s\n", arg); return print_error_usage(arg0); @@ -734,11 +756,13 @@ static int main0(int argc, char **argv) { } } else if (strcmp(arg, "--emit") == 0) { if (strcmp(argv[i], "asm") == 0) { - emit_file_type = EmitFileTypeAssembly; + emit_asm = true; + emit_bin = false; } else if (strcmp(argv[i], "bin") == 0) { - emit_file_type = EmitFileTypeBinary; + emit_bin = true; } else if (strcmp(argv[i], "llvm-ir") == 0) { - emit_file_type = EmitFileTypeLLVMIr; + emit_llvm_ir = true; + emit_bin = false; } else { fprintf(stderr, "--emit options are 'asm', 'bin', or 'llvm-ir'\n"); return print_error_usage(arg0); @@ -877,10 +901,8 @@ static int main0(int argc, char **argv) { , argv[i]); return EXIT_FAILURE; } - } else if (strcmp(arg, "-target-cpu") == 0) { - cpu = argv[i]; - } else if (strcmp(arg, "-target-feature") == 0) { - features = argv[i]; + } else if (strcmp(arg, "-mcpu") == 0) { + mcpu = argv[i]; } else { fprintf(stderr, "Invalid argument: %s\n", arg); return print_error_usage(arg0); @@ -956,58 +978,54 @@ static int main0(int argc, char **argv) { init_all_targets(); ZigTarget target; - if (target_string == nullptr) { - get_native_target(&target); + if ((err = target_parse_triple(&target, target_string, mcpu))) { + fprintf(stderr, "invalid target: %s\n" + "See `%s targets` to display valid targets.\n", err_str(err), arg0); + return print_error_usage(arg0); + } + if (target_is_glibc(&target)) { + target.glibc_version = heap::c_allocator.create<ZigGLibCVersion>(); + if (target_glibc != nullptr) { - fprintf(stderr, "-target-glibc provided but no -target parameter\n"); - return print_error_usage(arg0); - } - } else { - if ((err = target_parse_triple(&target, target_string))) { - if (err == ErrorUnknownArchitecture && target.arch != ZigLLVM_UnknownArch) { - fprintf(stderr, "'%s' requires a sub-architecture. Try one of these:\n", - target_arch_name(target.arch)); - SubArchList sub_arch_list = target_subarch_list(target.arch); - size_t subarch_count = target_subarch_count(sub_arch_list); - for (size_t sub_i = 0; sub_i < subarch_count; sub_i += 1) { - ZigLLVM_SubArchType sub = target_subarch_enum(sub_arch_list, sub_i); - fprintf(stderr, " %s%s\n", target_arch_name(target.arch), target_subarch_name(sub)); - } - return print_error_usage(arg0); - } else { - fprintf(stderr, "invalid target: %s\n", err_str(err)); + if ((err = target_parse_glibc_version(target.glibc_version, target_glibc))) { + fprintf(stderr, "invalid glibc version '%s': %s\n", target_glibc, err_str(err)); return print_error_usage(arg0); } - } - if (target_is_glibc(&target)) { - target.glibc_version = heap::c_allocator.create<ZigGLibCVersion>(); - - if (target_glibc != nullptr) { - if ((err = target_parse_glibc_version(target.glibc_version, target_glibc))) { - fprintf(stderr, "invalid glibc version '%s': %s\n", target_glibc, err_str(err)); - return print_error_usage(arg0); + } else { + target_init_default_glibc_version(&target); +#if defined(ZIG_OS_LINUX) + if (target.is_native) { + // TODO self-host glibc version detection, and then this logic can go away + if ((err = glibc_detect_native_version(target.glibc_version))) { + // Fall back to the default version. } - } else { - target_init_default_glibc_version(&target); } - } else if (target_glibc != nullptr) { - fprintf(stderr, "'%s' is not a glibc-compatible target", target_string); - return print_error_usage(arg0); +#endif } + } else if (target_glibc != nullptr) { + fprintf(stderr, "'%s' is not a glibc-compatible target", target_string); + return print_error_usage(arg0); } Buf zig_triple_buf = BUF_INIT; target_triple_zig(&zig_triple_buf, &target); - const char *stage2_triple_arg = target.is_native ? nullptr : buf_ptr(&zig_triple_buf); - if ((err = stage2_cpu_features_parse(&target.cpu_features, stage2_triple_arg, cpu, features))) { - fprintf(stderr, "unable to initialize CPU features: %s\n", err_str(err)); - return main_exit(root_progress_node, EXIT_FAILURE); - } - + // If both output_dir and enable_cache are provided, and doing build-lib, we + // will just do a file copy at the end. This helps when bootstrapping zig from zig0 + // because we want to pass something like this: + // zig0 build-lib --cache on --output-dir ${CMAKE_BINARY_DIR} + // And we don't have access to `zig0 build` because that would require detecting native libc + // on systems where we are not able to build a libc from source for them. + // But that's the only reason this works, so otherwise we give an error here. + Buf *final_output_dir_step = nullptr; if (output_dir != nullptr && enable_cache == CacheOptOn) { - fprintf(stderr, "`--output-dir` is incompatible with --cache on.\n"); - return print_error_usage(arg0); + if (cmd == CmdBuild && out_type == OutTypeLib) { + final_output_dir_step = output_dir; + output_dir = nullptr; + } else { + fprintf(stderr, "`--output-dir` is incompatible with --cache on.\n"); + return print_error_usage(arg0); + } } if (target_requires_pic(&target, have_libc) && want_pic == WantPICDisabled) { @@ -1015,8 +1033,8 @@ static int main0(int argc, char **argv) { return print_error_usage(arg0); } - if (emit_file_type != EmitFileTypeBinary && in_file == nullptr) { - fprintf(stderr, "A root source file is required when using `--emit asm` or `--emit llvm-ir`\n"); + if ((emit_asm || emit_llvm_ir) && in_file == nullptr) { + fprintf(stderr, "A root source file is required when using `-femit-asm` or `-femit-llvm-ir`\n"); return print_error_usage(arg0); } @@ -1028,15 +1046,22 @@ static int main0(int argc, char **argv) { switch (cmd) { case CmdLibC: { if (in_file) { - ZigLibCInstallation libc; - if ((err = zig_libc_parse(&libc, buf_create_from_str(in_file), &target, true))) + Stage2LibCInstallation libc; + if ((err = stage2_libc_parse(&libc, in_file))) { + fprintf(stderr, "unable to parse libc file: %s\n", err_str(err)); return main_exit(root_progress_node, EXIT_FAILURE); + } return main_exit(root_progress_node, EXIT_SUCCESS); } - ZigLibCInstallation libc; - if ((err = zig_libc_find_native(&libc, true))) + Stage2LibCInstallation libc; + if ((err = stage2_libc_find_native(&libc))) { + fprintf(stderr, "unable to find native libc file: %s\n", err_str(err)); return main_exit(root_progress_node, EXIT_FAILURE); - zig_libc_render(&libc, stdout); + } + if ((err = stage2_libc_render(&libc, stdout))) { + fprintf(stderr, "unable to print libc file: %s\n", err_str(err)); + return main_exit(root_progress_node, EXIT_FAILURE); + } return main_exit(root_progress_node, EXIT_SUCCESS); } case CmdBuiltin: { @@ -1080,11 +1105,38 @@ static int main0(int argc, char **argv) { { fprintf(stderr, "Expected source file argument.\n"); return print_error_usage(arg0); - } else if (cmd == CmdRun && emit_file_type != EmitFileTypeBinary) { - fprintf(stderr, "Cannot run non-executable file.\n"); + } else if (cmd == CmdRun && !emit_bin) { + fprintf(stderr, "Cannot run without emitting a binary file.\n"); return print_error_usage(arg0); } + if (target.is_native && link_libs.length != 0) { + Error err; + Stage2NativePaths paths; + if ((err = stage2_detect_native_paths(&paths))) { + fprintf(stderr, "unable to detect native system paths: %s\n", err_str(err)); + exit(1); + } + for (size_t i = 0; i < paths.warnings_len; i += 1) { + const char *warning = paths.warnings_ptr[i]; + fprintf(stderr, "warning: %s\n", warning); + } + for (size_t i = 0; i < paths.include_dirs_len; i += 1) { + const char *include_dir = paths.include_dirs_ptr[i]; + clang_argv.append("-I"); + clang_argv.append(include_dir); + } + for (size_t i = 0; i < paths.lib_dirs_len; i += 1) { + const char *lib_dir = paths.lib_dirs_ptr[i]; + lib_dirs.append(lib_dir); + } + for (size_t i = 0; i < paths.rpaths_len; i += 1) { + const char *rpath = paths.rpaths_ptr[i]; + rpath_list.append(rpath); + } + } + + assert(cmd != CmdBuild || out_type != OutTypeUnknown); bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC); @@ -1126,10 +1178,10 @@ static int main0(int argc, char **argv) { if (cmd == CmdRun && buf_out_name == nullptr) { buf_out_name = buf_create_from_str("run"); } - ZigLibCInstallation *libc = nullptr; + Stage2LibCInstallation *libc = nullptr; if (libc_txt != nullptr) { - libc = heap::c_allocator.create<ZigLibCInstallation>(); - if ((err = zig_libc_parse(libc, buf_create_from_str(libc_txt), &target, true))) { + libc = heap::c_allocator.create<Stage2LibCInstallation>(); + if ((err = stage2_libc_parse(libc, libc_txt))) { fprintf(stderr, "Unable to parse --libc text file: %s\n", err_str(err)); return main_exit(root_progress_node, EXIT_FAILURE); } @@ -1158,7 +1210,10 @@ static int main0(int argc, char **argv) { g->enable_stack_report = stack_report; g->enable_dump_analysis = enable_dump_analysis; g->enable_doc_generation = enable_doc_generation; - g->disable_bin_generation = disable_bin_generation; + g->emit_bin = emit_bin; + g->emit_asm = emit_asm; + g->emit_llvm_ir = emit_llvm_ir; + codegen_set_out_name(g, buf_out_name); codegen_set_lib_version(g, ver_major, ver_minor, ver_patch); g->want_single_threaded = want_single_threaded; @@ -1188,7 +1243,6 @@ static int main0(int argc, char **argv) { g->function_sections = function_sections; g->code_model = code_model; - for (size_t i = 0; i < lib_dirs.length; i += 1) { codegen_add_lib_dir(g, lib_dirs.at(i)); } @@ -1244,8 +1298,6 @@ static int main0(int argc, char **argv) { if (cmd == CmdBuild || cmd == CmdRun) { - codegen_set_emit_file_type(g, emit_file_type); - g->enable_cache = get_cache_opt(enable_cache, cmd == CmdRun); codegen_build_and_link(g); if (root_progress_node != nullptr) { @@ -1263,7 +1315,7 @@ static int main0(int argc, char **argv) { mem::print_report(); #endif - const char *exec_path = buf_ptr(&g->output_file_path); + const char *exec_path = buf_ptr(&g->bin_file_output_path); ZigList<const char*> args = {0}; args.append(exec_path); @@ -1283,10 +1335,23 @@ static int main0(int argc, char **argv) { } else if (cmd == CmdBuild) { if (g->enable_cache) { #if defined(ZIG_OS_WINDOWS) - buf_replace(&g->output_file_path, '/', '\\'); + buf_replace(&g->bin_file_output_path, '/', '\\'); #endif - if (printf("%s\n", buf_ptr(&g->output_file_path)) < 0) - return main_exit(root_progress_node, EXIT_FAILURE); + if (final_output_dir_step != nullptr) { + Buf *dest_basename = buf_alloc(); + os_path_split(&g->bin_file_output_path, nullptr, dest_basename); + Buf *dest_path = buf_alloc(); + os_path_join(final_output_dir_step, dest_basename, dest_path); + + if ((err = os_update_file(&g->bin_file_output_path, dest_path))) { + fprintf(stderr, "unable to copy %s to %s: %s\n", buf_ptr(&g->bin_file_output_path), + buf_ptr(dest_path), err_str(err)); + return main_exit(root_progress_node, EXIT_FAILURE); + } + } else { + if (printf("%s\n", buf_ptr(&g->bin_file_output_path)) < 0) + return main_exit(root_progress_node, EXIT_FAILURE); + } } return main_exit(root_progress_node, EXIT_SUCCESS); } else { @@ -1299,8 +1364,6 @@ static int main0(int argc, char **argv) { codegen_print_timing_report(g, stderr); return main_exit(root_progress_node, EXIT_SUCCESS); } else if (cmd == CmdTest) { - codegen_set_emit_file_type(g, emit_file_type); - ZigTarget native; get_native_target(&native); @@ -1319,17 +1382,17 @@ static int main0(int argc, char **argv) { zig_print_stack_report(g, stdout); } - if (g->disable_bin_generation) { + if (!g->emit_bin) { fprintf(stderr, "Semantic analysis complete. No binary produced due to -fno-emit-bin.\n"); return main_exit(root_progress_node, EXIT_SUCCESS); } - Buf *test_exe_path_unresolved = &g->output_file_path; + Buf *test_exe_path_unresolved = &g->bin_file_output_path; Buf *test_exe_path = buf_alloc(); *test_exe_path = os_path_resolve(&test_exe_path_unresolved, 1); - if (emit_file_type != EmitFileTypeBinary) { - fprintf(stderr, "Created %s but skipping execution because it is non executable.\n", + if (!g->emit_bin) { + fprintf(stderr, "Created %s but skipping execution because no binary generated.\n", buf_ptr(test_exe_path)); return main_exit(root_progress_node, EXIT_SUCCESS); } |
