mirror of
https://github.com/ziglang/zig.git
synced 2024-11-27 07:32:44 +00:00
Added _LIBCPP_HAS_NO_THREADS for single_threaded binaries linked with libcxx.
Fixed single-threaded mode for Windows.
This commit is contained in:
parent
67c4b16d6e
commit
3997828a61
@ -1,6 +1,7 @@
|
||||
const std = @import("../std.zig");
|
||||
const builtin = @import("builtin");
|
||||
const build = std.build;
|
||||
const CrossTarget = std.zig.CrossTarget;
|
||||
const Step = build.Step;
|
||||
const Builder = build.Builder;
|
||||
const LibExeObjStep = build.LibExeObjStep;
|
||||
@ -142,6 +143,23 @@ pub fn expectStdErrEqual(self: *RunStep, bytes: []const u8) void {
|
||||
self.stderr_action = .{ .expect_exact = self.builder.dupe(bytes) };
|
||||
}
|
||||
|
||||
/// Returns true if the step could be run, otherwise false
|
||||
pub fn isRunnable(
|
||||
self: *RunStep,
|
||||
) bool {
|
||||
for (self.argv.items) |arg| {
|
||||
switch (arg) {
|
||||
.artifact => |artifact| {
|
||||
_ = self.getExternalExecutor(artifact) catch {
|
||||
return false;
|
||||
};
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn expectStdOutEqual(self: *RunStep, bytes: []const u8) void {
|
||||
self.stdout_action = .{ .expect_exact = self.builder.dupe(bytes) };
|
||||
}
|
||||
@ -154,6 +172,57 @@ fn stdIoActionToBehavior(action: StdIoAction) std.ChildProcess.StdIo {
|
||||
};
|
||||
}
|
||||
|
||||
fn getExternalExecutor(self: *RunStep, artifact: *LibExeObjStep) !?[]const u8 {
|
||||
const need_cross_glibc = artifact.target.isGnuLibC() and artifact.is_linking_libc;
|
||||
const executor = self.builder.host.getExternalExecutor(artifact.target_info, .{
|
||||
.qemu_fixes_dl = need_cross_glibc and self.builder.glibc_runtimes_dir != null,
|
||||
.link_libc = artifact.is_linking_libc,
|
||||
});
|
||||
switch (executor) {
|
||||
.bad_dl, .bad_os_or_cpu => {
|
||||
return error.NoExecutable;
|
||||
},
|
||||
.native => {
|
||||
return null;
|
||||
},
|
||||
.rosetta => {
|
||||
if (self.builder.enable_rosetta) {
|
||||
return null;
|
||||
} else {
|
||||
return error.RosettaNotEnabled;
|
||||
}
|
||||
},
|
||||
.qemu => |bin_name| {
|
||||
if (self.builder.enable_qemu) {
|
||||
return bin_name;
|
||||
} else {
|
||||
return error.QemuNotEnabled;
|
||||
}
|
||||
},
|
||||
.wine => |bin_name| {
|
||||
if (self.builder.enable_wine) {
|
||||
return bin_name;
|
||||
} else {
|
||||
return error.WineNotEnabled;
|
||||
}
|
||||
},
|
||||
.wasmtime => |bin_name| {
|
||||
if (self.builder.enable_wasmtime) {
|
||||
return bin_name;
|
||||
} else {
|
||||
return error.WasmtimeNotEnabled;
|
||||
}
|
||||
},
|
||||
.darling => |bin_name| {
|
||||
if (self.builder.enable_darling) {
|
||||
return bin_name;
|
||||
} else {
|
||||
return error.DarlingNotEnabled;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn make(step: *Step) !void {
|
||||
const self = @fieldParentPtr(RunStep, "step", step);
|
||||
|
||||
@ -169,6 +238,9 @@ fn make(step: *Step) !void {
|
||||
// On Windows we don't have rpaths so we have to add .dll search paths to PATH
|
||||
self.addPathForDynLibs(artifact);
|
||||
}
|
||||
if (try self.getExternalExecutor(artifact)) |executor| {
|
||||
try argv_list.append(executor);
|
||||
}
|
||||
const executable_path = artifact.installed_path orelse artifact.getOutputSource().getPath(self.builder);
|
||||
try argv_list.append(executable_path);
|
||||
},
|
||||
|
@ -1180,6 +1180,15 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
|
||||
if (must_single_thread and !single_threaded) {
|
||||
return error.TargetRequiresSingleThreaded;
|
||||
}
|
||||
if (!single_threaded and options.link_libcpp) {
|
||||
if (options.target.cpu.arch.isARM()) {
|
||||
log.warn(
|
||||
\\libc++ does not work on multi-threaded ARM yet.
|
||||
\\For more details: https://github.com/ziglang/zig/issues/6573
|
||||
, .{});
|
||||
return error.TargetRequiresSingleThreaded;
|
||||
}
|
||||
}
|
||||
|
||||
const llvm_cpu_features: ?[*:0]const u8 = if (build_options.have_llvm and use_llvm) blk: {
|
||||
var buf = std.ArrayList(u8).init(arena);
|
||||
@ -3803,6 +3812,10 @@ pub fn addCCArgs(
|
||||
try argv.append("-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS");
|
||||
try argv.append("-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS");
|
||||
try argv.append("-D_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS");
|
||||
|
||||
if (comp.bin_file.options.single_threaded) {
|
||||
try argv.append("-D_LIBCPP_HAS_NO_THREADS");
|
||||
} else {}
|
||||
}
|
||||
|
||||
if (comp.bin_file.options.link_libunwind) {
|
||||
|
@ -128,6 +128,12 @@ pub fn buildLibCXX(comp: *Compilation) !void {
|
||||
continue;
|
||||
if (std.mem.startsWith(u8, cxx_src, "src/support/ibm/") and target.os.tag != .zos)
|
||||
continue;
|
||||
if (comp.bin_file.options.single_threaded) {
|
||||
if (std.mem.startsWith(u8, cxx_src, "src/support/win32/thread_win32.cpp")) {
|
||||
continue;
|
||||
}
|
||||
try cflags.append("-D_LIBCPP_HAS_NO_THREADS");
|
||||
}
|
||||
|
||||
try cflags.append("-DNDEBUG");
|
||||
try cflags.append("-D_LIBCPP_BUILDING_LIBRARY");
|
||||
@ -145,8 +151,7 @@ pub fn buildLibCXX(comp: *Compilation) !void {
|
||||
}
|
||||
|
||||
if (target.os.tag == .wasi) {
|
||||
// WASI doesn't support thread and exception yet.
|
||||
try cflags.append("-D_LIBCPP_HAS_NO_THREADS");
|
||||
// WASI doesn't support exceptions yet.
|
||||
try cflags.append("-fno-exceptions");
|
||||
}
|
||||
|
||||
@ -264,13 +269,20 @@ pub fn buildLibCXXABI(comp: *Compilation) !void {
|
||||
var cflags = std.ArrayList([]const u8).init(arena);
|
||||
|
||||
if (target.os.tag == .wasi) {
|
||||
// WASI doesn't support thread and exception yet.
|
||||
if (std.mem.startsWith(u8, cxxabi_src, "src/cxa_thread_atexit.cpp") or
|
||||
std.mem.startsWith(u8, cxxabi_src, "src/cxa_exception.cpp") or
|
||||
// WASI doesn't support exceptions yet.
|
||||
if (std.mem.startsWith(u8, cxxabi_src, "src/cxa_exception.cpp") or
|
||||
std.mem.startsWith(u8, cxxabi_src, "src/cxa_personality.cpp"))
|
||||
continue;
|
||||
try cflags.append("-D_LIBCXXABI_HAS_NO_THREADS");
|
||||
try cflags.append("-fno-exceptions");
|
||||
}
|
||||
|
||||
// WASM targets are single threaded.
|
||||
if (comp.bin_file.options.single_threaded) {
|
||||
if (std.mem.startsWith(u8, cxxabi_src, "src/cxa_thread_atexit.cpp")) {
|
||||
continue;
|
||||
}
|
||||
try cflags.append("-D_LIBCXXABI_HAS_NO_THREADS");
|
||||
try cflags.append("-D_LIBCPP_HAS_NO_THREADS");
|
||||
} else {
|
||||
try cflags.append("-DHAVE___CXA_THREAD_ATEXIT_IMPL");
|
||||
}
|
||||
|
@ -1,20 +1,21 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const Builder = std.build.Builder;
|
||||
const CrossTarget = std.zig.CrossTarget;
|
||||
|
||||
// TODO integrate this with the std.build executor API
|
||||
fn isRunnableTarget(t: CrossTarget) bool {
|
||||
if (t.isNative()) return true;
|
||||
|
||||
return (t.getOsTag() == builtin.os.tag and
|
||||
t.getCpuArch() == builtin.cpu.arch);
|
||||
}
|
||||
|
||||
pub fn build(b: *Builder) void {
|
||||
const mode = b.standardReleaseOptions();
|
||||
const target = b.standardTargetOptions(.{});
|
||||
|
||||
const is_wine_enabled = b.option(bool, "enable-wine", "Use Wine to run cross compiled Windows tests") orelse false;
|
||||
const is_qemu_enabled = b.option(bool, "enable-qemu", "Use QEMU to run cross compiled foreign architecture tests") orelse false;
|
||||
const is_wasmtime_enabled = b.option(bool, "enable-wasmtime", "Use Wasmtime to enable and run WASI libstd tests") orelse false;
|
||||
const is_darling_enabled = b.option(bool, "enable-darling", "[Experimental] Use Darling to run cross compiled macOS tests") orelse false;
|
||||
const single_threaded = b.option(bool, "single-threaded", "Test single threaded mode") orelse false;
|
||||
b.enable_wine = is_wine_enabled;
|
||||
b.enable_qemu = is_qemu_enabled;
|
||||
b.enable_wasmtime = is_wasmtime_enabled;
|
||||
b.enable_darling = is_darling_enabled;
|
||||
|
||||
const test_step = b.step("test", "Test the program");
|
||||
|
||||
const exe_c = b.addExecutable("test_c", null);
|
||||
@ -29,9 +30,16 @@ pub fn build(b: *Builder) void {
|
||||
exe_cpp.addCSourceFile("test.cpp", &[0][]const u8{});
|
||||
exe_cpp.setBuildMode(mode);
|
||||
exe_cpp.setTarget(target);
|
||||
exe_cpp.linkSystemLibrary("c++");
|
||||
exe_cpp.linkLibCpp();
|
||||
exe_cpp.single_threaded = single_threaded;
|
||||
const os_tag = target.getOsTag();
|
||||
// macos C++ exceptions could be compiled, but not being catched,
|
||||
// additional support is required, possibly unwind + DWARF CFI
|
||||
if (target.getCpuArch().isWasm() or os_tag == .macos) {
|
||||
exe_cpp.defineCMacro("_LIBCPP_NO_EXCEPTIONS", null);
|
||||
}
|
||||
|
||||
switch (target.getOsTag()) {
|
||||
switch (os_tag) {
|
||||
.windows => {
|
||||
// https://github.com/ziglang/zig/issues/8531
|
||||
exe_cpp.want_lto = false;
|
||||
@ -44,13 +52,17 @@ pub fn build(b: *Builder) void {
|
||||
else => {},
|
||||
}
|
||||
|
||||
if (isRunnableTarget(target)) {
|
||||
const run_c_cmd = exe_c.run();
|
||||
const run_c_cmd = exe_c.run();
|
||||
if (run_c_cmd.isRunnable()) {
|
||||
test_step.dependOn(&run_c_cmd.step);
|
||||
const run_cpp_cmd = exe_cpp.run();
|
||||
test_step.dependOn(&run_cpp_cmd.step);
|
||||
} else {
|
||||
test_step.dependOn(&exe_c.step);
|
||||
}
|
||||
|
||||
const run_cpp_cmd = exe_cpp.run();
|
||||
if (run_cpp_cmd.isRunnable()) {
|
||||
test_step.dependOn(&run_cpp_cmd.step);
|
||||
} else {
|
||||
test_step.dependOn(&exe_cpp.step);
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,28 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
int val;
|
||||
typedef struct {
|
||||
int val;
|
||||
} STest;
|
||||
|
||||
int getVal(STest* data) { return data->val; }
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
STest* data = (STest*)malloc(sizeof(STest));
|
||||
data->val = 123;
|
||||
STest* data = (STest*)malloc(sizeof(STest));
|
||||
data->val = 123;
|
||||
|
||||
assert(getVal(data) != 456);
|
||||
int ok = (getVal(data) == 123);
|
||||
assert(getVal(data) != 456);
|
||||
int ok = (getVal(data) == 123);
|
||||
|
||||
if (argc>1) fprintf(stdout, "val=%d\n", data->val);
|
||||
if (argc > 1) {
|
||||
fprintf(stdout, "val=%d\n", data->val);
|
||||
}
|
||||
|
||||
free(data);
|
||||
free(data);
|
||||
|
||||
if (!ok) abort();
|
||||
if (!ok) abort();
|
||||
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -1,15 +1,33 @@
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_THREADS
|
||||
#include <future>
|
||||
#endif
|
||||
|
||||
thread_local unsigned int tls_counter = 1;
|
||||
|
||||
// a non-optimized way of checking for prime numbers:
|
||||
bool is_prime(int x) {
|
||||
for (int i = 2; i <x ; ++i) {
|
||||
if (x % i == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
class CTest {
|
||||
public:
|
||||
CTest(int val) : m_val(val) {};
|
||||
virtual ~CTest() {}
|
||||
CTest(int val) : m_val(val) {
|
||||
tls_counter++;
|
||||
};
|
||||
virtual ~CTest() {}
|
||||
|
||||
virtual int getVal() const { return m_val; }
|
||||
virtual void printVal() { std::cout << "val=" << m_val << std::endl; }
|
||||
virtual int getVal() const { return m_val; }
|
||||
virtual void printVal() { std::cout << "val=" << m_val << std::endl; }
|
||||
private:
|
||||
int m_val;
|
||||
int m_val;
|
||||
};
|
||||
|
||||
|
||||
@ -18,16 +36,30 @@ CTest global(runtime_val); // test if global initializers are called.
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
assert(global.getVal() == 456);
|
||||
assert(global.getVal() == 456);
|
||||
auto t = std::make_unique<CTest>(123);
|
||||
assert(t->getVal() != 456);
|
||||
assert(tls_counter == 2);
|
||||
if (argc > 1) {
|
||||
t->printVal();
|
||||
}
|
||||
bool ok = t->getVal() == 123;
|
||||
|
||||
auto* t = new CTest(123);
|
||||
assert(t->getVal()!=456);
|
||||
if (!ok) abort();
|
||||
|
||||
if (argc>1) t->printVal();
|
||||
bool ok = t->getVal() == 123;
|
||||
delete t;
|
||||
#ifndef _LIBCPP_HAS_NO_THREADS
|
||||
std::future<bool> fut = std::async(is_prime, 313);
|
||||
bool ret = fut.get();
|
||||
assert(ret);
|
||||
#endif
|
||||
|
||||
if (!ok) abort();
|
||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||
try {
|
||||
throw 20;
|
||||
} catch (int e) {
|
||||
assert(e == 20);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user