diff --git a/src/Compilation.zig b/src/Compilation.zig index 343b22d2b1..412798e09a 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -188,6 +188,9 @@ libunwind_static_lib: ?CRTFile = null, /// Populated when we build the TSAN static library. A Job to build this is placed in the queue /// and resolved before calling linker.flush(). tsan_static_lib: ?CRTFile = null, +/// Populated when we build the TSAN dynamic library. A Job to build this is placed in the queue +/// and resolved before calling linker.flush(). +tsan_dynamic_lib: ?CRTFile = null, /// Populated when we build the libc static library. A Job to build this is placed in the queue /// and resolved before calling linker.flush(). libc_static_lib: ?CRTFile = null, diff --git a/src/libtsan.zig b/src/libtsan.zig index 1aa32e6ff0..4164200b47 100644 --- a/src/libtsan.zig +++ b/src/libtsan.zig @@ -25,10 +25,20 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - const root_name = "tsan"; - const output_mode = .Lib; - const link_mode = .static; const target = comp.getTarget(); + const root_name = switch (target.os.tag) { + // On Apple platforms, we use the same name as LLVM and Apple so that we correctly + // mark the images as instrumented when traversing them when TSAN dylib is + // initialized. + .macos => "clang_rt.tsan_osx_dynamic", + .ios => switch (target.abi) { + .simulator => "clang_rt.tsan_iossim_dynamic", + else => "clang_rt.tsan_ios_dynamic", + }, + else => "tsan", + }; + const link_mode: std.builtin.LinkMode = if (target.isDarwin()) .dynamic else .static; + const output_mode = .Lib; const basename = try std.zig.binNameAlloc(arena, .{ .root_name = root_name, .target = target, @@ -43,6 +53,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo const optimize_mode = comp.compilerRtOptMode(); const strip = comp.compilerRtStrip(); + const link_libcpp = target.isDarwin(); const config = Compilation.Config.resolve(.{ .output_mode = output_mode, @@ -54,6 +65,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo .root_optimize_mode = optimize_mode, .root_strip = strip, .link_libc = true, + .link_libcpp = link_libcpp, }) catch |err| { comp.setMiscFailure( .libtsan, @@ -272,6 +284,12 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo }); } + const skip_linker_dependencies = !target.isDarwin(); + const linker_allow_shlib_undefined = target.isDarwin(); + const install_name = if (target.isDarwin()) + try std.fmt.allocPrintZ(arena, "@rpath/{s}", .{basename}) + else + null; const sub_compilation = Compilation.create(comp.gpa, arena, .{ .local_cache_directory = comp.global_cache_directory, .global_cache_directory = comp.global_cache_directory, @@ -294,7 +312,9 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo .verbose_cimport = comp.verbose_cimport, .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, - .skip_linker_dependencies = true, + .skip_linker_dependencies = skip_linker_dependencies, + .linker_allow_shlib_undefined = linker_allow_shlib_undefined, + .install_name = install_name, }) catch |err| { comp.setMiscFailure( .libtsan, @@ -317,8 +337,13 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo }, }; - assert(comp.tsan_static_lib == null); - comp.tsan_static_lib = try sub_compilation.toCrtFile(); + assert(comp.tsan_static_lib == null and comp.tsan_dynamic_lib == null); + + if (target.isDarwin()) { + comp.tsan_dynamic_lib = try sub_compilation.toCrtFile(); + } else { + comp.tsan_static_lib = try sub_compilation.toCrtFile(); + } } const tsan_sources = [_][]const u8{