authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-09-11 16:37:03-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-09-11 16:37:03-07:00
log65bea514ae3860a5169d044d22ece7170c445bd3
tree64bc55e984c908f1056fdfd101757612d119d2fc
parentaec0e595f2a679f10e927ea4531b8f58ced7080a

Compilation: handle system C compiler not found

When linking libc and compiling natively, Zig tries to integrate with the system C compiler. However, this caused Zig to fail when no system C compiler is installed, despite the fact that Zig is perfectly capable of compiling & linking libc without one. This commit makes Zig fall back to using its own ability to provide libc in the case that no C compiler is installed. For glibc, it means sometimes getting the warning "zig cannot build new glibc version abc, providing instead xyz". Ideally, Zig would do some more validation about the system libraries being linked against, and report an error in case it could not provide the exact correct libc version of the system libraries (or that the system libraries themselves conflict with each other), however, I think it is fair to call that a separate enhancement.

3 files changed, 91 insertions(+), 68 deletions(-)

lib/std/child_process.zig+1-1
......@@ -508,7 +508,7 @@ pub const ChildProcess = struct {
508508 // it, that's the error code returned by the child process.
509509 _ = std.os.poll(&fd, 0) catch unreachable;
510510
511 // According to eventfd(2) the descriptro is readable if the counter
511 // According to eventfd(2) the descriptor is readable if the counter
512512 // has a value greater than 0
513513 if ((fd[0].revents & std.os.POLL.IN) != 0) {
514514 const err_int = try readIntFd(err_pipe[0]);
src/Compilation.zig+86-62
......@@ -4549,74 +4549,29 @@ fn detectLibCIncludeDirs(
45494549 getZigShippedLibCIncludeDirsDarwin(arena, zig_lib_dir, target);
45504550 }
45514551 const libc = try arena.create(LibCInstallation);
4552 libc.* = try LibCInstallation.findNative(.{ .allocator = arena, .verbose = true });
4552 libc.* = LibCInstallation.findNative(.{ .allocator = arena }) catch |err| switch (err) {
4553 error.CCompilerExitCode,
4554 error.CCompilerCrashed,
4555 error.CCompilerCannotFindHeaders,
4556 error.UnableToSpawnCCompiler,
4557 => |e| {
4558 // We tried to integrate with the native system C compiler,
4559 // however, it is not installed. So we must rely on our bundled
4560 // libc files.
4561 if (target_util.canBuildLibC(target)) {
4562 return detectLibCFromBuilding(arena, zig_lib_dir, target, has_macos_sdk);
4563 }
4564 return e;
4565 },
4566 else => |e| return e,
4567 };
45534568 return detectLibCFromLibCInstallation(arena, target, libc);
45544569 }
45554570
45564571 // If not linking system libraries, build and provide our own libc by
45574572 // default if possible.
45584573 if (target_util.canBuildLibC(target)) {
4559 switch (target.os.tag) {
4560 .macos => return if (has_macos_sdk)
4561 // For Darwin/macOS, we are all set with getDarwinSDK found earlier.
4562 LibCDirs{
4563 .libc_include_dir_list = &[0][]u8{},
4564 .libc_installation = null,
4565 }
4566 else
4567 getZigShippedLibCIncludeDirsDarwin(arena, zig_lib_dir, target),
4568 else => {
4569 const generic_name = target_util.libCGenericName(target);
4570 // Some architectures are handled by the same set of headers.
4571 const arch_name = if (target.abi.isMusl())
4572 musl.archName(target.cpu.arch)
4573 else if (target.cpu.arch.isThumb())
4574 // ARM headers are valid for Thumb too.
4575 switch (target.cpu.arch) {
4576 .thumb => "arm",
4577 .thumbeb => "armeb",
4578 else => unreachable,
4579 }
4580 else
4581 @tagName(target.cpu.arch);
4582 const os_name = @tagName(target.os.tag);
4583 // Musl's headers are ABI-agnostic and so they all have the "musl" ABI name.
4584 const abi_name = if (target.abi.isMusl()) "musl" else @tagName(target.abi);
4585 const s = std.fs.path.sep_str;
4586 const arch_include_dir = try std.fmt.allocPrint(
4587 arena,
4588 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-{s}",
4589 .{ zig_lib_dir, arch_name, os_name, abi_name },
4590 );
4591 const generic_include_dir = try std.fmt.allocPrint(
4592 arena,
4593 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "generic-{s}",
4594 .{ zig_lib_dir, generic_name },
4595 );
4596 const generic_arch_name = target_util.osArchName(target);
4597 const arch_os_include_dir = try std.fmt.allocPrint(
4598 arena,
4599 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-any",
4600 .{ zig_lib_dir, generic_arch_name, os_name },
4601 );
4602 const generic_os_include_dir = try std.fmt.allocPrint(
4603 arena,
4604 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "any-{s}-any",
4605 .{ zig_lib_dir, os_name },
4606 );
4607
4608 const list = try arena.alloc([]const u8, 4);
4609 list[0] = arch_include_dir;
4610 list[1] = generic_include_dir;
4611 list[2] = arch_os_include_dir;
4612 list[3] = generic_os_include_dir;
4613
4614 return LibCDirs{
4615 .libc_include_dir_list = list,
4616 .libc_installation = null,
4617 };
4618 },
4619 }
4574 return detectLibCFromBuilding(arena, zig_lib_dir, target, has_macos_sdk);
46204575 }
46214576
46224577 // If zig can't build the libc for the target and we are targeting the
......@@ -4675,6 +4630,75 @@ fn detectLibCFromLibCInstallation(arena: Allocator, target: Target, lci: *const
46754630 };
46764631}
46774632
4633fn detectLibCFromBuilding(
4634 arena: Allocator,
4635 zig_lib_dir: []const u8,
4636 target: std.Target,
4637 has_macos_sdk: bool,
4638) !LibCDirs {
4639 switch (target.os.tag) {
4640 .macos => return if (has_macos_sdk)
4641 // For Darwin/macOS, we are all set with getDarwinSDK found earlier.
4642 LibCDirs{
4643 .libc_include_dir_list = &[0][]u8{},
4644 .libc_installation = null,
4645 }
4646 else
4647 getZigShippedLibCIncludeDirsDarwin(arena, zig_lib_dir, target),
4648 else => {
4649 const generic_name = target_util.libCGenericName(target);
4650 // Some architectures are handled by the same set of headers.
4651 const arch_name = if (target.abi.isMusl())
4652 musl.archName(target.cpu.arch)
4653 else if (target.cpu.arch.isThumb())
4654 // ARM headers are valid for Thumb too.
4655 switch (target.cpu.arch) {
4656 .thumb => "arm",
4657 .thumbeb => "armeb",
4658 else => unreachable,
4659 }
4660 else
4661 @tagName(target.cpu.arch);
4662 const os_name = @tagName(target.os.tag);
4663 // Musl's headers are ABI-agnostic and so they all have the "musl" ABI name.
4664 const abi_name = if (target.abi.isMusl()) "musl" else @tagName(target.abi);
4665 const s = std.fs.path.sep_str;
4666 const arch_include_dir = try std.fmt.allocPrint(
4667 arena,
4668 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-{s}",
4669 .{ zig_lib_dir, arch_name, os_name, abi_name },
4670 );
4671 const generic_include_dir = try std.fmt.allocPrint(
4672 arena,
4673 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "generic-{s}",
4674 .{ zig_lib_dir, generic_name },
4675 );
4676 const generic_arch_name = target_util.osArchName(target);
4677 const arch_os_include_dir = try std.fmt.allocPrint(
4678 arena,
4679 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-any",
4680 .{ zig_lib_dir, generic_arch_name, os_name },
4681 );
4682 const generic_os_include_dir = try std.fmt.allocPrint(
4683 arena,
4684 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "any-{s}-any",
4685 .{ zig_lib_dir, os_name },
4686 );
4687
4688 const list = try arena.alloc([]const u8, 4);
4689 list[0] = arch_include_dir;
4690 list[1] = generic_include_dir;
4691 list[2] = arch_os_include_dir;
4692 list[3] = generic_os_include_dir;
4693
4694 return LibCDirs{
4695 .libc_include_dir_list = list,
4696 .libc_installation = null,
4697 };
4698 },
4699 }
4700}
4701
46784702pub fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const u8) ![]const u8 {
46794703 if (comp.wantBuildGLibCFromSource() or
46804704 comp.wantBuildMuslFromSource() or
src/glibc.zig+4-5
......@@ -719,17 +719,16 @@ pub fn buildSharedObjects(comp: *Compilation) !void {
719719 .lt => continue,
720720 .gt => {
721721 // TODO Expose via compile error mechanism instead of log.
722 log.err("invalid target glibc version: {}", .{target_version});
722 log.warn("invalid target glibc version: {}", .{target_version});
723723 return error.InvalidTargetGLibCVersion;
724724 },
725725 }
726 } else {
726 } else blk: {
727727 const latest_index = metadata.all_versions.len - 1;
728 // TODO Expose via compile error mechanism instead of log.
729 log.err("zig does not yet provide glibc version {}, the max provided version is {}", .{
728 log.warn("zig cannot build new glibc version {}; providing instead {}", .{
730729 target_version, metadata.all_versions[latest_index],
731730 });
732 return error.InvalidTargetGLibCVersion;
731 break :blk latest_index;
733732 };
734733
735734 {