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 {...@@ -508,7 +508,7 @@ pub const ChildProcess = struct {
508 // it, that's the error code returned by the child process.508 // it, that's the error code returned by the child process.
509 _ = std.os.poll(&fd, 0) catch unreachable;509 _ = std.os.poll(&fd, 0) catch unreachable;
510510
511 // According to eventfd(2) the descriptro is readable if the counter511 // According to eventfd(2) the descriptor is readable if the counter
512 // has a value greater than 0512 // has a value greater than 0
513 if ((fd[0].revents & std.os.POLL.IN) != 0) {513 if ((fd[0].revents & std.os.POLL.IN) != 0) {
514 const err_int = try readIntFd(err_pipe[0]);514 const err_int = try readIntFd(err_pipe[0]);
src/Compilation.zig+86-62
...@@ -4549,74 +4549,29 @@ fn detectLibCIncludeDirs(...@@ -4549,74 +4549,29 @@ fn detectLibCIncludeDirs(
4549 getZigShippedLibCIncludeDirsDarwin(arena, zig_lib_dir, target);4549 getZigShippedLibCIncludeDirsDarwin(arena, zig_lib_dir, target);
4550 }4550 }
4551 const libc = try arena.create(LibCInstallation);4551 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 };
4553 return detectLibCFromLibCInstallation(arena, target, libc);4568 return detectLibCFromLibCInstallation(arena, target, libc);
4554 }4569 }
45554570
4556 // If not linking system libraries, build and provide our own libc by4571 // If not linking system libraries, build and provide our own libc by
4557 // default if possible.4572 // default if possible.
4558 if (target_util.canBuildLibC(target)) {4573 if (target_util.canBuildLibC(target)) {
4559 switch (target.os.tag) {4574 return detectLibCFromBuilding(arena, zig_lib_dir, target, has_macos_sdk);
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 }
4620 }4575 }
46214576
4622 // If zig can't build the libc for the target and we are targeting the4577 // 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...@@ -4675,6 +4630,75 @@ fn detectLibCFromLibCInstallation(arena: Allocator, target: Target, lci: *const
4675 };4630 };
4676}4631}
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
4678pub fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const u8) ![]const u8 {4702pub fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const u8) ![]const u8 {
4679 if (comp.wantBuildGLibCFromSource() or4703 if (comp.wantBuildGLibCFromSource() or
4680 comp.wantBuildMuslFromSource() or4704 comp.wantBuildMuslFromSource() or
src/glibc.zig+4-5
...@@ -719,17 +719,16 @@ pub fn buildSharedObjects(comp: *Compilation) !void {...@@ -719,17 +719,16 @@ pub fn buildSharedObjects(comp: *Compilation) !void {
719 .lt => continue,719 .lt => continue,
720 .gt => {720 .gt => {
721 // TODO Expose via compile error mechanism instead of log.721 // 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});
723 return error.InvalidTargetGLibCVersion;723 return error.InvalidTargetGLibCVersion;
724 },724 },
725 }725 }
726 } else {726 } else blk: {
727 const latest_index = metadata.all_versions.len - 1;727 const latest_index = metadata.all_versions.len - 1;
728 // TODO Expose via compile error mechanism instead of log.728 log.warn("zig cannot build new glibc version {}; providing instead {}", .{
729 log.err("zig does not yet provide glibc version {}, the max provided version is {}", .{
730 target_version, metadata.all_versions[latest_index],729 target_version, metadata.all_versions[latest_index],
731 });730 });
732 return error.InvalidTargetGLibCVersion;731 break :blk latest_index;
733 };732 };
734733
735 {734 {