From 7b204649e3af348a7831837d5a36219733b505ca Mon Sep 17 00:00:00 2001 From: Jay Weisskopf Date: Tue, 25 Sep 2018 20:13:02 -0400 Subject: stage1: Added `zig help` to show usage on stdout This will make it easier to do things like `zig help | grep something`. Invalid arguments will now display a short notice for `zig help` instead of showing the full usage information. This will make it easier to see the actual error. --- src/main.cpp | 74 +++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 28 deletions(-) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index 95fba8d59e..cdb68ec529 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,14 +16,22 @@ #include -static int usage(const char *arg0) { - fprintf(stderr, "Usage: %s [command] [options]\n" +static int print_error_usage(const char *arg0) { + fprintf(stderr, "See `%s help` for detailed usage information\n", arg0); + return EXIT_FAILURE; +} + +static int print_full_usage(const char *arg0) { + fprintf(stdout, + "Usage: %s [command] [options]\n" + "\n" "Commands:\n" " build build project from build.zig\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" " builtin show the source code of that @import(\"builtin\")\n" + " help show this usage information\n" " id print the base64-encoded compiler id\n" " init-exe initialize a `zig build` application in the cwd\n" " init-lib initialize a `zig build` library in the cwd\n" @@ -33,6 +41,7 @@ static int usage(const char *arg0) { " test [source] create and run a test build\n" " version print version number and exit\n" " zen print zen of zig and exit\n" + "\n" "Compile Options:\n" " --assembly [source] add assembly file to build\n" " --cache-dir [path] override the cache directory\n" @@ -63,6 +72,7 @@ static int usage(const char *arg0) { " -dirafter [dir] same as -isystem but do it last\n" " -isystem [dir] add additional search path for other .h files\n" " -mllvm [arg] forward an arg to LLVM's option processing\n" + "\n" "Link Options:\n" " --dynamic-linker [path] set the path to ld.so\n" " --each-lib-rpath add rpath for each used dynamic library\n" @@ -87,13 +97,14 @@ static int usage(const char *arg0) { " --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" + "\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" " --test-cmd [arg] specify test execution command one arg at a time\n" " --test-cmd-bin appends test binary path to test cmd args\n" , arg0); - return EXIT_FAILURE; + return EXIT_SUCCESS; } static const char *ZIG_ZEN = "\n" @@ -144,15 +155,16 @@ static int print_target_list(FILE *f) { } enum Cmd { - CmdInvalid, + CmdNone, CmdBuild, CmdBuiltin, + CmdHelp, CmdRun, + CmdTargets, CmdTest, + CmdTranslateC, CmdVersion, CmdZen, - CmdTranslateC, - CmdTargets, }; static const char *default_zig_cache_name = "zig-cache"; @@ -251,7 +263,7 @@ int main(int argc, char **argv) { if (init_kind != InitKindNone) { if (argc >= 3) { fprintf(stderr, "Unexpected extra argument: %s\n", argv[2]); - return usage(arg0); + return print_error_usage(arg0); } Buf *cmd_template_path = buf_alloc(); os_path_join(get_zig_special_dir(), buf_create_from_str(init_cmd), cmd_template_path); @@ -326,7 +338,7 @@ int main(int argc, char **argv) { } } - Cmd cmd = CmdInvalid; + Cmd cmd = CmdNone; EmitFileType emit_file_type = EmitFileTypeBinary; const char *in_file = nullptr; const char *out_file = nullptr; @@ -547,7 +559,7 @@ int main(int argc, char **argv) { } else if (strcmp(arg, "--pkg-begin") == 0) { if (i + 2 >= argc) { fprintf(stderr, "Expected 2 arguments after --pkg-begin\n"); - return usage(arg0); + return print_error_usage(arg0); } CliPkg *new_cur_pkg = allocate(1); i += 1; @@ -565,7 +577,7 @@ int main(int argc, char **argv) { cur_pkg = cur_pkg->parent; } else if (i + 1 >= argc) { fprintf(stderr, "Expected another argument after %s\n", arg); - return usage(arg0); + return print_error_usage(arg0); } else { i += 1; if (strcmp(arg, "--output") == 0) { @@ -581,7 +593,7 @@ int main(int argc, char **argv) { color = ErrColorOff; } else { fprintf(stderr, "--color options are 'auto', 'on', or 'off'\n"); - return usage(arg0); + return print_error_usage(arg0); } } else if (strcmp(arg, "--cache") == 0) { if (strcmp(argv[i], "auto") == 0) { @@ -592,7 +604,7 @@ int main(int argc, char **argv) { enable_cache = CacheOptOff; } else { fprintf(stderr, "--cache options are 'auto', 'on', or 'off'\n"); - return usage(arg0); + return print_error_usage(arg0); } } else if (strcmp(arg, "--emit") == 0) { if (strcmp(argv[i], "asm") == 0) { @@ -603,7 +615,7 @@ int main(int argc, char **argv) { emit_file_type = EmitFileTypeLLVMIr; } else { fprintf(stderr, "--emit options are 'asm', 'bin', or 'llvm-ir'\n"); - return usage(arg0); + return print_error_usage(arg0); } } else if (strcmp(arg, "--name") == 0) { out_name = argv[i]; @@ -672,10 +684,10 @@ int main(int argc, char **argv) { test_exec_args.append(argv[i]); } else { fprintf(stderr, "Invalid argument: %s\n", arg); - return usage(arg0); + return print_error_usage(arg0); } } - } else if (cmd == CmdInvalid) { + } else if (cmd == CmdNone) { if (strcmp(arg, "build-exe") == 0) { cmd = CmdBuild; out_type = OutTypeExe; @@ -685,6 +697,8 @@ int main(int argc, char **argv) { } else if (strcmp(arg, "build-lib") == 0) { cmd = CmdBuild; out_type = OutTypeLib; + } else if (strcmp(arg, "help") == 0) { + cmd = CmdHelp; } else if (strcmp(arg, "run") == 0) { cmd = CmdRun; out_type = OutTypeExe; @@ -703,7 +717,7 @@ int main(int argc, char **argv) { cmd = CmdBuiltin; } else { fprintf(stderr, "Unrecognized command: %s\n", arg); - return usage(arg0); + return print_error_usage(arg0); } } else { switch (cmd) { @@ -719,16 +733,17 @@ int main(int argc, char **argv) { } } else { fprintf(stderr, "Unexpected extra parameter: %s\n", arg); - return usage(arg0); + return print_error_usage(arg0); } break; case CmdBuiltin: + case CmdHelp: case CmdVersion: case CmdZen: case CmdTargets: fprintf(stderr, "Unexpected extra parameter: %s\n", arg); - return usage(arg0); - case CmdInvalid: + return print_error_usage(arg0); + case CmdNone: zig_unreachable(); } } @@ -751,19 +766,19 @@ int main(int argc, char **argv) { if (target_arch) { if (parse_target_arch(target_arch, &target->arch)) { fprintf(stderr, "invalid --target-arch argument\n"); - return usage(arg0); + return print_error_usage(arg0); } } if (target_os) { if (parse_target_os(target_os, &target->os)) { fprintf(stderr, "invalid --target-os argument\n"); - return usage(arg0); + return print_error_usage(arg0); } } if (target_environ) { if (parse_target_environ(target_environ, &target->env_type)) { fprintf(stderr, "invalid --target-environ argument\n"); - return usage(arg0); + return print_error_usage(arg0); } } } @@ -785,13 +800,13 @@ int main(int argc, char **argv) { { 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); + return print_error_usage(arg0); } else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) { fprintf(stderr, "Expected source file argument.\n"); - return usage(arg0); + return print_error_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); + return print_error_usage(arg0); } assert(cmd != CmdBuild || out_type != OutTypeUnknown); @@ -820,7 +835,7 @@ int main(int argc, char **argv) { if (need_name && buf_out_name == nullptr) { fprintf(stderr, "--name [name] not provided and unable to infer\n\n"); - return usage(arg0); + return print_error_usage(arg0); } Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf; @@ -1012,6 +1027,8 @@ int main(int argc, char **argv) { zig_unreachable(); } } + case CmdHelp: + return print_full_usage(arg0); case CmdVersion: printf("%s\n", ZIG_VERSION_STRING); return EXIT_SUCCESS; @@ -1020,7 +1037,8 @@ int main(int argc, char **argv) { return EXIT_SUCCESS; case CmdTargets: return print_target_list(stdout); - case CmdInvalid: - return usage(arg0); + case CmdNone: + fprintf(stderr, "Zig programming language\n"); + return print_error_usage(arg0); } } -- cgit v1.2.3 From 779881b978e1275eef2e3b247ec0909260f4219e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 28 Sep 2018 16:41:23 -0400 Subject: zig build: use os_self_exe_path to determine exe path not arg0 --- src/main.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index cdb68ec529..5c1e107362 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -394,7 +394,12 @@ int main(int argc, char **argv) { bool no_rosegment_workaround = false; if (argc >= 2 && strcmp(argv[1], "build") == 0) { - const char *zig_exe_path = arg0; + Buf zig_exe_path_buf = BUF_INIT; + if ((err = os_self_exe_path(&zig_exe_path_buf))) { + fprintf(stderr, "Unable to determine path to zig's own executable\n"); + return EXIT_FAILURE; + } + const char *zig_exe_path = buf_ptr(&zig_exe_path_buf); const char *build_file = "build.zig"; bool asked_for_help = false; -- cgit v1.2.3 From ba78ae0ae73ac38a2bb32c618cd145b4d2f9602e Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Sun, 30 Sep 2018 22:59:45 +0200 Subject: Fixes --emit asm on windows and makes C header file generation explicit. (#1612) * build: only do codegen_link when emitting an actual binary. Fixes #1371 * build: only output C header file when explicitely asked to --- src/all_types.hpp | 1 - src/codegen.cpp | 16 ++-------------- src/link.cpp | 2 +- src/main.cpp | 4 ++-- 4 files changed, 5 insertions(+), 18 deletions(-) (limited to 'src/main.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 89c117ce82..30d941354a 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1713,7 +1713,6 @@ struct CodeGen { uint32_t target_environ_index; uint32_t target_oformat_index; bool is_big_endian; - bool want_h_file; bool have_pub_main; bool have_c_main; bool have_winmain; diff --git a/src/codegen.cpp b/src/codegen.cpp index 70310641c4..de69b53388 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -118,7 +118,6 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out g->string_literals_table.init(16); g->type_info_cache.init(32); g->is_test_build = false; - g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib); buf_resize(&g->global_asm, 0); for (size_t i = 0; i < array_length(symbols_that_llvm_depends_on); i += 1) { @@ -8127,17 +8126,6 @@ static void resolve_out_paths(CodeGen *g) { } 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; - } - } } @@ -8193,11 +8181,11 @@ void codegen_build_and_link(CodeGen *g) { codegen_add_time_event(g, "LLVM Emit Output"); zig_llvm_emit_output(g); - if (g->want_h_file) { + if (g->out_h_path != nullptr) { codegen_add_time_event(g, "Generate .h"); gen_h_file(g); } - if (g->out_type != OutTypeObj) { + if (g->out_type != OutTypeObj && g->emit_file_type == EmitFileTypeBinary) { codegen_link(g); } } diff --git a/src/link.cpp b/src/link.cpp index aa0edde61b..a280c31f74 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -34,7 +34,7 @@ static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path) CodeGen *child_gen = codegen_create(full_path, child_target, OutTypeObj, parent_gen->build_mode, parent_gen->zig_lib_dir); - child_gen->want_h_file = false; + child_gen->out_h_path = nullptr; child_gen->verbose_tokenize = parent_gen->verbose_tokenize; child_gen->verbose_ast = parent_gen->verbose_ast; child_gen->verbose_link = parent_gen->verbose_link; diff --git a/src/main.cpp b/src/main.cpp index 5c1e107362..f9df802cb3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -52,7 +52,7 @@ static int print_full_usage(const char *arg0) { " --libc-include-dir [path] directory where libc stdlib.h resides\n" " --name [name] override output name\n" " --output [file] override destination path\n" - " --output-h [file] override generated header file path\n" + " --output-h [file] generate header file\n" " --pkg-begin [name] [path] make pkg available to import and push current pkg\n" " --pkg-end pop current pkg\n" " --release-fast build with optimizations on and safety off\n" @@ -926,7 +926,7 @@ int main(int argc, char **argv) { if (out_file) codegen_set_output_path(g, buf_create_from_str(out_file)); - if (out_file_h) + if (out_file_h != nullptr && (out_type == OutTypeObj || out_type == OutTypeLib)) codegen_set_output_h_path(g, buf_create_from_str(out_file_h)); -- cgit v1.2.3 From 6b93495792678bd00a6205967bb2704a9a35e9c7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 9 Oct 2018 12:18:09 -0400 Subject: more efficient builtin library code generation * introduce --disable-pic option which can generally be allowed to be the default. compiler_rt.a and builtin.a get this option when you build a static executable. * compiler_rt and builtin libraries are not built for build-lib --static * posix_spawn instead of fork/execv * disable the error limit on LLD. Fixes the blank lines printed --- src/all_types.hpp | 1 + src/codegen.cpp | 6 +++++- src/link.cpp | 19 ++++++++++--------- src/main.cpp | 12 ++++++++++++ src/os.cpp | 34 ++++++++++++++++------------------ 5 files changed, 44 insertions(+), 28 deletions(-) (limited to 'src/main.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index d7071590d8..a144013947 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1763,6 +1763,7 @@ struct CodeGen { bool linker_rdynamic; bool no_rosegment_workaround; bool each_lib_rpath; + bool disable_pic; Buf *mmacosx_version_min; Buf *mios_version_min; diff --git a/src/codegen.cpp b/src/codegen.cpp index fd7a386078..02105b4d2a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7228,7 +7228,10 @@ static void init(CodeGen *g) { bool is_optimized = g->build_mode != BuildModeDebug; LLVMCodeGenOptLevel opt_level = is_optimized ? LLVMCodeGenLevelAggressive : LLVMCodeGenLevelNone; - LLVMRelocMode reloc_mode = g->is_static ? LLVMRelocStatic : LLVMRelocPIC; + if (g->out_type == OutTypeExe && g->is_static) { + g->disable_pic = true; + } + LLVMRelocMode reloc_mode = g->disable_pic ? LLVMRelocStatic : LLVMRelocPIC; const char *target_specific_cpu_args; const char *target_specific_features; @@ -8047,6 +8050,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_bool(ch, g->linker_rdynamic); cache_bool(ch, g->no_rosegment_workaround); cache_bool(ch, g->each_lib_rpath); + cache_bool(ch, g->disable_pic); cache_buf_opt(ch, g->mmacosx_version_min); cache_buf_opt(ch, g->mios_version_min); cache_usize(ch, g->version_major); diff --git a/src/link.cpp b/src/link.cpp index c961042324..095d3d79d7 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -44,6 +44,7 @@ static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path) codegen_set_strip(child_gen, parent_gen->strip_debug_symbols); codegen_set_is_static(child_gen, true); + child_gen->disable_pic = parent_gen->disable_pic; codegen_set_out_name(child_gen, buf_create_from_str(aname)); @@ -209,10 +210,9 @@ static void construct_linker_job_elf(LinkJob *lj) { lj->args.append(getLDMOption(&g->zig_target)); bool is_lib = g->out_type == OutTypeLib; - bool is_static = g->is_static || (!is_lib && g->link_libs_list.length == 0); - bool shared = !is_static && is_lib; + bool shared = !g->is_static && is_lib; Buf *soname = nullptr; - if (is_static) { + if (g->is_static) { if (g->zig_target.arch.arch == ZigLLVM_arm || g->zig_target.arch.arch == ZigLLVM_armeb || g->zig_target.arch.arch == ZigLLVM_thumb || g->zig_target.arch.arch == ZigLLVM_thumbeb) { @@ -236,7 +236,7 @@ static void construct_linker_job_elf(LinkJob *lj) { if (lj->link_in_crt) { const char *crt1o; const char *crtbegino; - if (is_static) { + if (g->is_static) { crt1o = "crt1.o"; crtbegino = "crtbeginT.o"; } else { @@ -287,7 +287,7 @@ static void construct_linker_job_elf(LinkJob *lj) { lj->args.append(buf_ptr(g->libc_static_lib_dir)); } - if (!is_static) { + if (!g->is_static) { if (g->dynamic_linker != nullptr) { assert(buf_len(g->dynamic_linker) != 0); lj->args.append("-dynamic-linker"); @@ -309,7 +309,7 @@ static void construct_linker_job_elf(LinkJob *lj) { lj->args.append((const char *)buf_ptr(g->link_objects.at(i))); } - if (g->out_type == OutTypeExe || g->out_type == OutTypeLib) { + if (g->out_type == OutTypeExe || (g->out_type == OutTypeLib && !g->is_static)) { if (g->libc_link_lib == nullptr) { Buf *builtin_a_path = build_a(g, "builtin"); lj->args.append(buf_ptr(builtin_a_path)); @@ -339,7 +339,7 @@ static void construct_linker_job_elf(LinkJob *lj) { // libc dep if (g->libc_link_lib != nullptr) { - if (is_static) { + if (g->is_static) { lj->args.append("--start-group"); lj->args.append("-lgcc"); lj->args.append("-lgcc_eh"); @@ -540,7 +540,7 @@ static void construct_linker_job_coff(LinkJob *lj) { lj->args.append((const char *)buf_ptr(g->link_objects.at(i))); } - if (g->out_type == OutTypeExe || g->out_type == OutTypeLib) { + if (g->out_type == OutTypeExe || (g->out_type == OutTypeLib && !g->is_static)) { if (g->libc_link_lib == nullptr) { Buf *builtin_a_path = build_a(g, "builtin"); lj->args.append(buf_ptr(builtin_a_path)); @@ -872,7 +872,7 @@ static void construct_linker_job_macho(LinkJob *lj) { } // compiler_rt on darwin is missing some stuff, so we still build it and rely on LinkOnce - if (g->out_type == OutTypeExe || g->out_type == OutTypeLib) { + if (g->out_type == OutTypeExe || (g->out_type == OutTypeLib && !g->is_static)) { Buf *compiler_rt_o_path = build_compiler_rt(g); lj->args.append(buf_ptr(compiler_rt_o_path)); } @@ -969,6 +969,7 @@ void codegen_link(CodeGen *g) { lj.link_in_crt = (g->libc_link_lib != nullptr && g->out_type == OutTypeExe); + lj.args.append("-error-limit=0"); construct_linker_job(&lj); diff --git a/src/main.cpp b/src/main.cpp index f9df802cb3..5e827b5ba6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -47,6 +47,7 @@ static int print_full_usage(const char *arg0) { " --cache-dir [path] override the cache directory\n" " --cache [auto|off|on] build in global cache, print out paths to stdout\n" " --color [auto|off|on] enable or disable colored error messages\n" + " --disable-pic disable Position Independent Code for libraries\n" " --emit [asm|bin|llvm-ir] emit a specific file format as compilation output\n" " -ftime-report print timing diagnostics\n" " --libc-include-dir [path] directory where libc stdlib.h resides\n" @@ -386,6 +387,7 @@ int main(int argc, char **argv) { size_t ver_minor = 0; size_t ver_patch = 0; bool timing_info = false; + bool disable_pic = false; const char *cache_dir = nullptr; CliPkg *cur_pkg = allocate(1); BuildMode build_mode = BuildModeDebug; @@ -556,6 +558,8 @@ int main(int argc, char **argv) { each_lib_rpath = true; } else if (strcmp(arg, "-ftime-report") == 0) { timing_info = true; + } else if (strcmp(arg, "--disable-pic") == 0) { + disable_pic = true; } else if (strcmp(arg, "--test-cmd-bin") == 0) { test_exec_args.append(nullptr); } else if (arg[1] == 'L' && arg[2] != 0) { @@ -849,6 +853,14 @@ int main(int argc, char **argv) { buf_out_name = buf_create_from_str("run"); } CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, get_zig_lib_dir()); + if (disable_pic) { + if (out_type != OutTypeLib || !is_static) { + fprintf(stderr, "--disable-pic only applies to static libraries"); + return EXIT_FAILURE; + } + g->disable_pic = true; + } + 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); diff --git a/src/os.cpp b/src/os.cpp index ed069b2ff8..e1bd6bd479 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -46,6 +46,7 @@ typedef SSIZE_T ssize_t; #include #include #include +#include #endif @@ -88,25 +89,22 @@ static void populate_termination(Termination *term, int status) { } static void os_spawn_process_posix(const char *exe, ZigList &args, Termination *term) { - pid_t pid = fork(); - if (pid == -1) - zig_panic("fork failed: %s", strerror(errno)); - if (pid == 0) { - // child - const char **argv = allocate(args.length + 2); - argv[0] = exe; - argv[args.length + 1] = nullptr; - for (size_t i = 0; i < args.length; i += 1) { - argv[i + 1] = args.at(i); - } - execvp(exe, const_cast(argv)); - zig_panic("execvp failed: %s", strerror(errno)); - } else { - // parent - int status; - waitpid(pid, &status, 0); - populate_termination(term, status); + const char **argv = allocate(args.length + 2); + argv[0] = exe; + argv[args.length + 1] = nullptr; + for (size_t i = 0; i < args.length; i += 1) { + argv[i + 1] = args.at(i); } + + pid_t pid; + int rc = posix_spawn(&pid, exe, nullptr, nullptr, const_cast(argv), environ); + if (rc != 0) { + zig_panic("posix_spawn failed: %s", strerror(rc)); + } + + int status; + waitpid(pid, &status, 0); + populate_termination(term, status); } #endif -- cgit v1.2.3 From 1554dd9697b77b4fe4a309247982c3e29048f124 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 2 Nov 2018 00:07:43 -0400 Subject: support building static self hosted compiler on macos * add a --system-linker-hack command line parameter to work around poor LLD macho code. See #1535 * build.zig correctly handles static as well as dynamic dependencies when building the self hosted compiler. - no more unnecessary libxml2 dependency - a static build on macos produces a completely static self-hosted compiler for macos (except for libSystem as intended). --- build.zig | 122 +++++++++++++++++++++++++++++++++++++----------------- src/all_types.hpp | 1 + src/link.cpp | 15 ++++++- src/main.cpp | 4 ++ src/os.cpp | 2 +- std/build.zig | 19 +++++++++ 6 files changed, 122 insertions(+), 41 deletions(-) (limited to 'src/main.cpp') diff --git a/build.zig b/build.zig index c2a20015a7..c4a95bb0a9 100644 --- a/build.zig +++ b/build.zig @@ -121,12 +121,23 @@ pub fn build(b: *Builder) !void { test_step.dependOn(docs_step); } -fn dependOnLib(lib_exe_obj: var, dep: LibraryDep) void { +fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void { for (dep.libdirs.toSliceConst()) |lib_dir| { lib_exe_obj.addLibPath(lib_dir); } + const lib_dir = os.path.join(b.allocator, dep.prefix, "lib") catch unreachable; for (dep.system_libs.toSliceConst()) |lib| { - lib_exe_obj.linkSystemLibrary(lib); + const static_bare_name = if (mem.eql(u8, lib, "curses")) + ([]const u8)("libncurses.a") + else + b.fmt("lib{}.a", lib); + const static_lib_name = os.path.join(b.allocator, lib_dir, static_bare_name) catch unreachable; + const have_static = fileExists(static_lib_name) catch unreachable; + if (have_static) { + lib_exe_obj.addObjectFile(static_lib_name); + } else { + lib_exe_obj.linkSystemLibrary(lib); + } } for (dep.libs.toSliceConst()) |lib| { lib_exe_obj.addObjectFile(lib); @@ -136,12 +147,23 @@ fn dependOnLib(lib_exe_obj: var, dep: LibraryDep) void { } } +fn fileExists(filename: []const u8) !bool { + os.File.access(filename) catch |err| switch (err) { + error.PermissionDenied, + error.FileNotFound, + => return false, + else => return err, + }; + return true; +} + fn addCppLib(b: *Builder, lib_exe_obj: var, cmake_binary_dir: []const u8, lib_name: []const u8) void { const lib_prefix = if (lib_exe_obj.target.isWindows()) "" else "lib"; lib_exe_obj.addObjectFile(os.path.join(b.allocator, cmake_binary_dir, "zig_cpp", b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt())) catch unreachable); } const LibraryDep = struct.{ + prefix: []const u8, libdirs: ArrayList([]const u8), libs: ArrayList([]const u8), system_libs: ArrayList([]const u8), @@ -149,21 +171,25 @@ const LibraryDep = struct.{ }; fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep { - const libs_output = try b.exec([][]const u8.{ - llvm_config_exe, - "--libs", - "--system-libs", - }); - const includes_output = try b.exec([][]const u8.{ - llvm_config_exe, - "--includedir", - }); - const libdir_output = try b.exec([][]const u8.{ - llvm_config_exe, - "--libdir", - }); + const shared_mode = try b.exec([][]const u8.{ llvm_config_exe, "--shared-mode" }); + const is_static = mem.startsWith(u8, shared_mode, "static"); + const libs_output = if (is_static) + try b.exec([][]const u8.{ + llvm_config_exe, + "--libfiles", + "--system-libs", + }) + else + try b.exec([][]const u8.{ + llvm_config_exe, + "--libs", + }); + const includes_output = try b.exec([][]const u8.{ llvm_config_exe, "--includedir" }); + const libdir_output = try b.exec([][]const u8.{ llvm_config_exe, "--libdir" }); + const prefix_output = try b.exec([][]const u8.{ llvm_config_exe, "--prefix" }); var result = LibraryDep.{ + .prefix = mem.split(prefix_output, " \r\n").next().?, .libs = ArrayList([]const u8).init(b.allocator), .system_libs = ArrayList([]const u8).init(b.allocator), .includes = ArrayList([]const u8).init(b.allocator), @@ -244,10 +270,6 @@ fn nextValue(index: *usize, build_info: []const u8) []const u8 { } fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { - // This is for finding /lib/libz.a on alpine linux. - // TODO turn this into -Dextra-lib-path=/lib option - exe.addLibPath("/lib"); - exe.setNoRoSegment(ctx.no_rosegment); exe.addIncludeDir("src"); @@ -265,39 +287,63 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_coff"); addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_lib"); } - dependOnLib(exe, ctx.llvm); + dependOnLib(b, exe, ctx.llvm); if (exe.target.getOs() == builtin.Os.linux) { - const libstdcxx_path_padded = try b.exec([][]const u8.{ - ctx.cxx_compiler, - "-print-file-name=libstdc++.a", - }); - const libstdcxx_path = mem.split(libstdcxx_path_padded, "\r\n").next().?; - if (mem.eql(u8, libstdcxx_path, "libstdc++.a")) { - warn( - \\Unable to determine path to libstdc++.a - \\On Fedora, install libstdc++-static and try again. - \\ - ); - return error.RequiredLibraryNotFound; - } - exe.addObjectFile(libstdcxx_path); + try addCxxKnownPath(b, ctx, exe, "libstdc++.a", + \\Unable to determine path to libstdc++.a + \\On Fedora, install libstdc++-static and try again. + \\ + ); exe.linkSystemLibrary("pthread"); } else if (exe.target.isDarwin()) { - exe.linkSystemLibrary("c++"); + if (addCxxKnownPath(b, ctx, exe, "libgcc_eh.a", "")) { + // Compiler is GCC. + try addCxxKnownPath(b, ctx, exe, "libstdc++.a", null); + exe.linkSystemLibrary("pthread"); + // TODO LLD cannot perform this link. + // See https://github.com/ziglang/zig/issues/1535 + exe.enableSystemLinkerHack(); + } else |err| switch (err) { + error.RequiredLibraryNotFound => { + // System compiler, not gcc. + exe.linkSystemLibrary("c++"); + }, + else => return err, + } } if (ctx.dia_guids_lib.len != 0) { exe.addObjectFile(ctx.dia_guids_lib); } - if (exe.target.getOs() != builtin.Os.windows) { - exe.linkSystemLibrary("xml2"); - } exe.linkSystemLibrary("c"); } +fn addCxxKnownPath( + b: *Builder, + ctx: Context, + exe: var, + objname: []const u8, + errtxt: ?[]const u8, +) !void { + const path_padded = try b.exec([][]const u8.{ + ctx.cxx_compiler, + b.fmt("-print-file-name={}", objname), + }); + const path_unpadded = mem.split(path_padded, "\r\n").next().?; + if (mem.eql(u8, path_unpadded, objname)) { + if (errtxt) |msg| { + warn("{}", msg); + } else { + warn("Unable to determine path to {}\n", objname); + } + return error.RequiredLibraryNotFound; + } + exe.addObjectFile(path_unpadded); +} + const Context = struct.{ cmake_binary_dir: []const u8, cxx_compiler: []const u8, diff --git a/src/all_types.hpp b/src/all_types.hpp index c490999a2b..0276d6212e 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1731,6 +1731,7 @@ struct CodeGen { bool generate_error_name_table; bool enable_cache; bool enable_time_report; + bool system_linker_hack; //////////////////////////// Participates in Input Parameter Cache Hash ZigList link_libs_list; diff --git a/src/link.cpp b/src/link.cpp index 424b06169e..0e729fa918 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -778,7 +778,8 @@ static bool darwin_version_lt(DarwinPlatform *platform, int major, int minor) { static void construct_linker_job_macho(LinkJob *lj) { CodeGen *g = lj->codegen; - lj->args.append("-error-limit=0"); + // LLD MACH-O has no error limit option. + //lj->args.append("-error-limit=0"); lj->args.append("-demangle"); if (g->linker_rdynamic) { @@ -1007,7 +1008,17 @@ void codegen_link(CodeGen *g) { Buf diag = BUF_INIT; codegen_add_time_event(g, "LLVM Link"); - if (!zig_lld_link(g->zig_target.oformat, lj.args.items, lj.args.length, &diag)) { + if (g->system_linker_hack && g->zig_target.os == OsMacOSX) { + Termination term; + ZigList args = {}; + for (size_t i = 1; i < lj.args.length; i += 1) { + args.append(lj.args.at(i)); + } + os_spawn_process("ld", args, &term); + if (term.how != TerminationIdClean || term.code != 0) { + exit(1); + } + } else if (!zig_lld_link(g->zig_target.oformat, lj.args.items, lj.args.length, &diag)) { fprintf(stderr, "%s\n", buf_ptr(&diag)); exit(1); } diff --git a/src/main.cpp b/src/main.cpp index 5e827b5ba6..84ff2fb4b2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -394,6 +394,7 @@ int main(int argc, char **argv) { ZigList test_exec_args = {0}; int runtime_args_start = -1; bool no_rosegment_workaround = false; + bool system_linker_hack = false; if (argc >= 2 && strcmp(argv[1], "build") == 0) { Buf zig_exe_path_buf = BUF_INIT; @@ -560,6 +561,8 @@ int main(int argc, char **argv) { timing_info = true; } else if (strcmp(arg, "--disable-pic") == 0) { disable_pic = true; + } else if (strcmp(arg, "--system-linker-hack") == 0) { + system_linker_hack = true; } else if (strcmp(arg, "--test-cmd-bin") == 0) { test_exec_args.append(nullptr); } else if (arg[1] == 'L' && arg[2] != 0) { @@ -893,6 +896,7 @@ int main(int argc, char **argv) { g->verbose_llvm_ir = verbose_llvm_ir; g->verbose_cimport = verbose_cimport; codegen_set_errmsg_color(g, color); + g->system_linker_hack = system_linker_hack; for (size_t i = 0; i < lib_dirs.length; i += 1) { codegen_add_lib_dir(g, lib_dirs.at(i)); diff --git a/src/os.cpp b/src/os.cpp index 6df463d8a5..f01a99fc23 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -103,7 +103,7 @@ static void os_spawn_process_posix(const char *exe, ZigList &args, } pid_t pid; - int rc = posix_spawn(&pid, exe, nullptr, nullptr, const_cast(argv), environ); + int rc = posix_spawnp(&pid, exe, nullptr, nullptr, const_cast(argv), environ); if (rc != 0) { zig_panic("posix_spawn failed: %s", strerror(rc)); } diff --git a/std/build.zig b/std/build.zig index a80580a383..1d90aa90e6 100644 --- a/std/build.zig +++ b/std/build.zig @@ -836,6 +836,7 @@ pub const LibExeObjStep = struct.{ assembly_files: ArrayList([]const u8), packages: ArrayList(Pkg), build_options_contents: std.Buffer, + system_linker_hack: bool, // C only stuff source_files: ArrayList([]const u8), @@ -930,6 +931,7 @@ pub const LibExeObjStep = struct.{ .disable_libc = true, .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable, .c_std = Builder.CStd.C99, + .system_linker_hack = false, }; self.computeOutFileNames(); return self; @@ -965,6 +967,7 @@ pub const LibExeObjStep = struct.{ .is_zig = false, .linker_script = null, .c_std = Builder.CStd.C99, + .system_linker_hack = false, .root_src = undefined, .verbose_link = false, @@ -1162,6 +1165,10 @@ pub const LibExeObjStep = struct.{ self.disable_libc = disable; } + pub fn enableSystemLinkerHack(self: *LibExeObjStep) void { + self.system_linker_hack = true; + } + fn make(step: *Step) !void { const self = @fieldParentPtr(LibExeObjStep, "step", step); return if (self.is_zig) self.makeZig() else self.makeC(); @@ -1338,6 +1345,9 @@ pub const LibExeObjStep = struct.{ if (self.no_rosegment) { try zig_args.append("--no-rosegment"); } + if (self.system_linker_hack) { + try zig_args.append("--system-linker-hack"); + } try builder.spawnChild(zig_args.toSliceConst()); @@ -1646,6 +1656,7 @@ pub const TestStep = struct.{ object_files: ArrayList([]const u8), no_rosegment: bool, output_path: ?[]const u8, + system_linker_hack: bool, pub fn init(builder: *Builder, root_src: []const u8) TestStep { const step_name = builder.fmt("test {}", root_src); @@ -1665,6 +1676,7 @@ pub const TestStep = struct.{ .object_files = ArrayList([]const u8).init(builder.allocator), .no_rosegment = false, .output_path = null, + .system_linker_hack = false, }; } @@ -1747,6 +1759,10 @@ pub const TestStep = struct.{ self.exec_cmd_args = args; } + pub fn enableSystemLinkerHack(self: *TestStep) void { + self.system_linker_hack = true; + } + fn make(step: *Step) !void { const self = @fieldParentPtr(TestStep, "step", step); const builder = self.builder; @@ -1851,6 +1867,9 @@ pub const TestStep = struct.{ if (self.no_rosegment) { try zig_args.append("--no-rosegment"); } + if (self.system_linker_hack) { + try zig_args.append("--system-linker-hack"); + } try builder.spawnChild(zig_args.toSliceConst()); } -- cgit v1.2.3