From fdeb8765f0dd0d147371b22a28b442c6f19fa36d Mon Sep 17 00:00:00 2001 From: Shawn Landden Date: Fri, 31 Aug 2018 19:29:06 -0700 Subject: use vfork in stage1 compiler to avoid OOM --- src/os.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/os.cpp') diff --git a/src/os.cpp b/src/os.cpp index 0e62d84a48..8f1e335a27 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -125,7 +125,7 @@ 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"); + zig_panic("fork failed: %s", strerror(errno)); if (pid == 0) { // child const char **argv = allocate(args.length + 2); @@ -839,9 +839,9 @@ static int os_exec_process_posix(const char *exe, ZigList &args, if ((err = pipe(stderr_pipe))) zig_panic("pipe failed"); - pid_t pid = fork(); + pid_t pid = vfork(); if (pid == -1) - zig_panic("fork failed"); + zig_panic("fork failed: %s", strerror(errno)); if (pid == 0) { // child if (dup2(stdin_pipe[0], STDIN_FILENO) == -1) -- cgit v1.2.3 From f9558444354b5b3367536a7389790c87ea9a94f0 Mon Sep 17 00:00:00 2001 From: Jeff Fowler Date: Sat, 22 Sep 2018 12:32:54 +0200 Subject: rm extraneous macro --- src/os.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/os.cpp') diff --git a/src/os.cpp b/src/os.cpp index b682429884..54df5568b7 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -1378,8 +1378,6 @@ int os_init(void) { #if defined(ZIG_OS_WINDOWS) _setmode(fileno(stdout), _O_BINARY); _setmode(fileno(stderr), _O_BINARY); -#endif -#if defined(ZIG_OS_WINDOWS) unsigned __int64 frequency; if (QueryPerformanceFrequency((LARGE_INTEGER*) &frequency)) { win32_time_resolution = 1.0 / (double) frequency; -- cgit v1.2.3 From 2d2734172484871eb56705e77acca50a8c83d8ae Mon Sep 17 00:00:00 2001 From: Shawn Landden Date: Fri, 5 Oct 2018 11:32:31 -0700 Subject: arm64: respond to code review --- src/os.cpp | 2 +- std/fmt/index.zig | 7 +++++++ std/os/index.zig | 2 +- std/os/linux/arm64.zig | 48 +++++++++++++++++++++++++++++++++++++++++++++++ std/os/linux/index.zig | 50 +------------------------------------------------ std/os/linux/x86_64.zig | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 106 insertions(+), 51 deletions(-) (limited to 'src/os.cpp') diff --git a/src/os.cpp b/src/os.cpp index 8f1e335a27..5c6d4fd5b0 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -839,7 +839,7 @@ static int os_exec_process_posix(const char *exe, ZigList &args, if ((err = pipe(stderr_pipe))) zig_panic("pipe failed"); - pid_t pid = vfork(); + pid_t pid = fork(); if (pid == -1) zig_panic("fork failed: %s", strerror(errno)); if (pid == 0) { diff --git a/std/fmt/index.zig b/std/fmt/index.zig index f859c6fd1d..6c076e7f0b 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -1034,6 +1034,13 @@ test "fmt.format" { const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64); assert(mem.eql(u8, result, "f64: nan\n")); } + if (builtin.arch != builtin.Arch.armv8) { + // negative nan is not defined by IEE 754, + // and ARM thus normalizes it to positive nan + var buf1: [32]u8 = undefined; + const result = try bufPrint(buf1[0..], "f64: {}\n", -math.nan_f64); + assert(mem.eql(u8, result, "f64: -nan\n")); + } { var buf1: [32]u8 = undefined; const result = try bufPrint(buf1[0..], "f64: {}\n", math.inf_f64); diff --git a/std/os/index.zig b/std/os/index.zig index 7635386fbb..7089ff8f15 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -633,7 +633,7 @@ fn posixExecveErrnoToErr(err: usize) PosixExecveError { }; } -pub var linux_elf_aux_maybe: ?[*]std.elf.Auxv = undefined; +pub var linux_elf_aux_maybe: ?[*]std.elf.Auxv = null; pub var posix_environ_raw: [][*]u8 = undefined; /// See std.elf for the constants. diff --git a/std/os/linux/arm64.zig b/std/os/linux/arm64.zig index 95095bad4d..91e4a49679 100644 --- a/std/os/linux/arm64.zig +++ b/std/os/linux/arm64.zig @@ -281,6 +281,54 @@ pub const SYS_statx = 291; pub const SYS_io_pgetevents = 292; pub const SYS_syscalls = 293; +pub const O_CREAT = 0o100; +pub const O_EXCL = 0o200; +pub const O_NOCTTY = 0o400; +pub const O_TRUNC = 0o1000; +pub const O_APPEND = 0o2000; +pub const O_NONBLOCK = 0o4000; +pub const O_DSYNC = 0o10000; +pub const O_SYNC = 0o4010000; +pub const O_RSYNC = 0o4010000; +pub const O_DIRECTORY = 0o200000; +pub const O_NOFOLLOW = 0o400000; +pub const O_CLOEXEC = 0o2000000; + +pub const O_ASYNC = 0o20000; +pub const O_DIRECT = 0o40000; +pub const O_LARGEFILE = 0; +pub const O_NOATIME = 0o1000000; +pub const O_PATH = 0o10000000; +pub const O_TMPFILE = 0o20200000; +pub const O_NDELAY = O_NONBLOCK; + +pub const F_DUPFD = 0; +pub const F_GETFD = 1; +pub const F_SETFD = 2; +pub const F_GETFL = 3; +pub const F_SETFL = 4; + +pub const F_SETOWN = 8; +pub const F_GETOWN = 9; +pub const F_SETSIG = 10; +pub const F_GETSIG = 11; + +pub const F_GETLK = 5; +pub const F_SETLK = 6; +pub const F_SETLKW = 7; + +pub const F_SETOWN_EX = 15; +pub const F_GETOWN_EX = 16; + +pub const F_GETOWNER_UIDS = 17; + +pub const AT_FDCWD = -100; +pub const AT_SYMLINK_NOFOLLOW = 0x100; +pub const AT_REMOVEDIR = 0x200; +pub const AT_SYMLINK_FOLLOW = 0x400; +pub const AT_NO_AUTOMOUNT = 0x800; +pub const AT_EMPTY_PATH = 0x1000; + pub const VDSO_USEFUL = true; pub const VDSO_CGT_SYM = "__kernel_clock_gettime"; pub const VDSO_CGT_VER = "LINUX_2.6.39"; diff --git a/std/os/linux/index.zig b/std/os/linux/index.zig index b30260768e..5f0912cf8f 100644 --- a/std/os/linux/index.zig +++ b/std/os/linux/index.zig @@ -625,54 +625,6 @@ pub const S_IWOTH = 0o002; pub const S_IXOTH = 0o001; pub const S_IRWXO = 0o007; -pub const O_CREAT = 0o100; -pub const O_EXCL = 0o200; -pub const O_NOCTTY = 0o400; -pub const O_TRUNC = 0o1000; -pub const O_APPEND = 0o2000; -pub const O_NONBLOCK = 0o4000; -pub const O_DSYNC = 0o10000; -pub const O_SYNC = 0o4010000; -pub const O_RSYNC = 0o4010000; -pub const O_DIRECTORY = 0o200000; -pub const O_NOFOLLOW = 0o400000; -pub const O_CLOEXEC = 0o2000000; - -pub const O_ASYNC = 0o20000; -pub const O_DIRECT = 0o40000; -pub const O_LARGEFILE = 0; -pub const O_NOATIME = 0o1000000; -pub const O_PATH = 0o10000000; -pub const O_TMPFILE = 0o20200000; -pub const O_NDELAY = O_NONBLOCK; - -pub const F_DUPFD = 0; -pub const F_GETFD = 1; -pub const F_SETFD = 2; -pub const F_GETFL = 3; -pub const F_SETFL = 4; - -pub const F_SETOWN = 8; -pub const F_GETOWN = 9; -pub const F_SETSIG = 10; -pub const F_GETSIG = 11; - -pub const F_GETLK = 5; -pub const F_SETLK = 6; -pub const F_SETLKW = 7; - -pub const F_SETOWN_EX = 15; -pub const F_GETOWN_EX = 16; - -pub const F_GETOWNER_UIDS = 17; - -pub const AT_FDCWD = -100; -pub const AT_SYMLINK_NOFOLLOW = 0x100; -pub const AT_REMOVEDIR = 0x200; -pub const AT_SYMLINK_FOLLOW = 0x400; -pub const AT_NO_AUTOMOUNT = 0x800; -pub const AT_EMPTY_PATH = 0x1000; - pub fn S_ISREG(m: u32) bool { return m & S_IFMT == S_IFREG; } @@ -1272,7 +1224,7 @@ pub fn accept4(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t, flags: } pub fn fstat(fd: i32, stat_buf: *Stat) usize { - return fstatat(fd, c"", stat_buf, AT_EMPTY_PATH); + return syscall2(SYS_fstat, @intCast(usize, fd), @ptrToInt(stat_buf)); } // TODO https://github.com/ziglang/zig/issues/265 diff --git a/std/os/linux/x86_64.zig b/std/os/linux/x86_64.zig index aa8c1c95a1..2ea369d9f2 100644 --- a/std/os/linux/x86_64.zig +++ b/std/os/linux/x86_64.zig @@ -332,6 +332,54 @@ pub const SYS_userfaultfd = 323; pub const SYS_membarrier = 324; pub const SYS_mlock2 = 325; +pub const O_CREAT = 0o100; +pub const O_EXCL = 0o200; +pub const O_NOCTTY = 0o400; +pub const O_TRUNC = 0o1000; +pub const O_APPEND = 0o2000; +pub const O_NONBLOCK = 0o4000; +pub const O_DSYNC = 0o10000; +pub const O_SYNC = 0o4010000; +pub const O_RSYNC = 0o4010000; +pub const O_DIRECTORY = 0o200000; +pub const O_NOFOLLOW = 0o400000; +pub const O_CLOEXEC = 0o2000000; + +pub const O_ASYNC = 0o20000; +pub const O_DIRECT = 0o40000; +pub const O_LARGEFILE = 0; +pub const O_NOATIME = 0o1000000; +pub const O_PATH = 0o10000000; +pub const O_TMPFILE = 0o20200000; +pub const O_NDELAY = O_NONBLOCK; + +pub const F_DUPFD = 0; +pub const F_GETFD = 1; +pub const F_SETFD = 2; +pub const F_GETFL = 3; +pub const F_SETFL = 4; + +pub const F_SETOWN = 8; +pub const F_GETOWN = 9; +pub const F_SETSIG = 10; +pub const F_GETSIG = 11; + +pub const F_GETLK = 5; +pub const F_SETLK = 6; +pub const F_SETLKW = 7; + +pub const F_SETOWN_EX = 15; +pub const F_GETOWN_EX = 16; + +pub const F_GETOWNER_UIDS = 17; + +pub const AT_FDCWD = -100; +pub const AT_SYMLINK_NOFOLLOW = 0x100; +pub const AT_REMOVEDIR = 0x200; +pub const AT_SYMLINK_FOLLOW = 0x400; +pub const AT_NO_AUTOMOUNT = 0x800; +pub const AT_EMPTY_PATH = 0x1000; + pub const VDSO_USEFUL = true; pub const VDSO_CGT_SYM = "__vdso_clock_gettime"; pub const VDSO_CGT_VER = "LINUX_2.6"; -- 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/os.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 05e608a0c72a5da8cc92a50dd6f79bad046fb977 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 9 Oct 2018 12:58:13 -0400 Subject: stage1 os: workaround for macos not having environ variable --- src/os.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/os.cpp') diff --git a/src/os.cpp b/src/os.cpp index e1bd6bd479..6df463d8a5 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -71,6 +71,12 @@ static clock_serv_t cclock; #include #include +// Apple doesn't provide the environ global variable +#if defined(__APPLE__) && !defined(environ) +#include +#define environ (*_NSGetEnviron()) +#endif + #if defined(ZIG_OS_POSIX) static void populate_termination(Termination *term, int status) { if (WIFEXITED(status)) { -- 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/os.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