aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/clang.zig3
-rw-r--r--src/link/Elf.zig9
-rw-r--r--src/main.zig19
-rw-r--r--src/zig_clang.cpp28
-rw-r--r--src/zig_clang.h1
5 files changed, 59 insertions, 1 deletions
diff --git a/src/clang.zig b/src/clang.zig
index ef90ddebce..40dacc5df8 100644
--- a/src/clang.zig
+++ b/src/clang.zig
@@ -1913,3 +1913,6 @@ extern fn ZigClangLoadFromCommandLine(
errors_len: *usize,
resources_path: [*:0]const u8,
) ?*ASTUnit;
+
+pub const isLLVMUsingSeparateLibcxx = ZigClangIsLLVMUsingSeparateLibcxx;
+extern fn ZigClangIsLLVMUsingSeparateLibcxx() bool;
diff --git a/src/link/Elf.zig b/src/link/Elf.zig
index 3e9b1ab3ed..917e4c18d1 100644
--- a/src/link/Elf.zig
+++ b/src/link/Elf.zig
@@ -1592,6 +1592,15 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
}
}
}
+ for (self.base.options.objects) |obj| {
+ if (Compilation.classifyFileExt(obj.path) == .shared_library) {
+ const lib_dir_path = std.fs.path.dirname(obj.path).?;
+ if ((try rpath_table.fetchPut(lib_dir_path, {})) == null) {
+ try argv.append("-rpath");
+ try argv.append(lib_dir_path);
+ }
+ }
+ }
}
for (self.base.options.lib_dirs) |lib_dir| {
diff --git a/src/main.zig b/src/main.zig
index f2291a0646..f192137b3c 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -174,6 +174,17 @@ pub fn main() anyerror!void {
return mainArgs(gpa, arena, args);
}
+/// Check that LLVM and Clang have been linked properly so that they are using the same
+/// libc++ and can safely share objects with pointers to static variables in libc++
+fn verifyLibcxxCorrectlyLinked() void {
+ if (build_options.have_llvm and ZigClangIsLLVMUsingSeparateLibcxx()) {
+ fatal(
+ \\Zig was built/linked incorrectly: LLVM and Clang have separate copies of libc++
+ \\ If you are dynamically linking LLVM, make sure you dynamically link libc++ too
+ , .{});
+ }
+}
+
pub fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
if (args.len <= 1) {
std.log.info("{s}", .{usage});
@@ -261,8 +272,12 @@ pub fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
const stdout = io.getStdOut().writer();
return @import("print_targets.zig").cmdTargets(arena, cmd_args, stdout, info.target);
} else if (mem.eql(u8, cmd, "version")) {
- return std.io.getStdOut().writeAll(build_options.version ++ "\n");
+ try std.io.getStdOut().writeAll(build_options.version ++ "\n");
+ // Check libc++ linkage to make sure Zig was built correctly, but only for "env" and "version"
+ // to avoid affecting the startup time for build-critical commands (check takes about ~10 μs)
+ return verifyLibcxxCorrectlyLinked();
} else if (mem.eql(u8, cmd, "env")) {
+ verifyLibcxxCorrectlyLinked();
return @import("print_env.zig").cmdEnv(arena, cmd_args, io.getStdOut().writer());
} else if (mem.eql(u8, cmd, "zen")) {
return io.getStdOut().writeAll(info_zen);
@@ -4487,6 +4502,8 @@ pub const info_zen =
\\
;
+extern fn ZigClangIsLLVMUsingSeparateLibcxx() bool;
+
extern "c" fn ZigClang_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
extern "c" fn ZigLlvmAr_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp
index 1c0ff7bf09..7b79f8e985 100644
--- a/src/zig_clang.cpp
+++ b/src/zig_clang.cpp
@@ -3432,3 +3432,31 @@ const struct ZigClangAPSInt *ZigClangEnumConstantDecl_getInitVal(const struct Zi
const llvm::APSInt *result = &casted->getInitVal();
return reinterpret_cast<const ZigClangAPSInt *>(result);
}
+
+// Get a pointer to a static variable in libc++ from LLVM and make sure that
+// it matches our own.
+//
+// This check is needed because if static/dynamic linking is mixed incorrectly,
+// it's possible for Clang and LLVM to end up with duplicate "copies" of libc++.
+//
+// This is not benign: Static variables are not shared, so equality comparisons
+// that depend on pointers to static variables will fail. One such failure is
+// std::generic_category(), which causes POSIX error codes to compare as unequal
+// when passed between LLVM and Clang.
+//
+// See also: https://github.com/ziglang/zig/issues/11168
+bool ZigClangIsLLVMUsingSeparateLibcxx() {
+
+ // Temporarily create an InMemoryFileSystem, so that we can perform a file
+ // lookup that is guaranteed to fail.
+ auto FS = new llvm::vfs::InMemoryFileSystem(true);
+ auto StatusOrErr = FS->status("foo.txt");
+ delete FS;
+
+ // This should return a POSIX (generic_category) error code, but if LLVM has
+ // its own copy of libc++ this will actually be a separate category instance.
+ assert(!StatusOrErr);
+ auto EC = StatusOrErr.getError();
+ return EC.category() != std::generic_category();
+}
+
diff --git a/src/zig_clang.h b/src/zig_clang.h
index 6babb21bfe..3da57d4301 100644
--- a/src/zig_clang.h
+++ b/src/zig_clang.h
@@ -1418,4 +1418,5 @@ ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangFieldDecl_getParent(const
ZIG_EXTERN_C unsigned ZigClangFieldDecl_getFieldIndex(const struct ZigClangFieldDecl *);
ZIG_EXTERN_C const struct ZigClangAPSInt *ZigClangEnumConstantDecl_getInitVal(const struct ZigClangEnumConstantDecl *);
+ZIG_EXTERN_C bool ZigClangIsLLVMUsingSeparateLibcxx();
#endif