aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-02-25 16:30:40 -0500
committerAndrew Kelley <andrew@ziglang.org>2020-02-25 16:30:40 -0500
commitf33bf48af7d9c99d532864f8a6c3f695ad5bbd21 (patch)
treefa39bd6b654178e653d06e1c79f22ad1d29cd526 /src/main.cpp
parent64365bc5d7b1e2c507806ee8976acc3479ad7862 (diff)
parent416a547cdb8dbbf3d2e7ce32132f0a25f2a8607e (diff)
downloadzig-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.cpp239
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);
}