Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Normalized C++ compilation options for single-threaded targets #10143

Merged
merged 2 commits into from
May 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/Compilation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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");
}
}

if (comp.bin_file.options.link_libunwind) {
Expand Down
24 changes: 18 additions & 6 deletions src/libcxx.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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");
}

Expand Down Expand Up @@ -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");
}
Expand Down
2 changes: 1 addition & 1 deletion test/standalone/c_compiler/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ 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();

switch (target.getOsTag()) {
.windows => {
Expand Down
23 changes: 13 additions & 10 deletions test/standalone/c_compiler/test.c
Original file line number Diff line number Diff line change
@@ -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;
}
76 changes: 61 additions & 15 deletions test/standalone/c_compiler/test.cpp
Original file line number Diff line number Diff line change
@@ -1,33 +1,79 @@
#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;
};

class GlobalConstructorTest {
public:
GlobalConstructorTest(int val) : m_val(val) {};
virtual ~GlobalConstructorTest() {}

virtual int getVal() const { return m_val; }
virtual void printVal() { std::cout << "val=" << m_val << std::endl; }
private:
int m_val;
};


volatile int runtime_val = 456;
CTest global(runtime_val); // test if global initializers are called.
GlobalConstructorTest 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();
#if !defined(__wasm__) && !defined(__APPLE__)
// WASM and macOS are not passing this yet.
// TODO file an issue for this and link it here.
try {
throw 20;
} catch (int e) {
assert(e == 20);
}
#endif

return 0;
return EXIT_SUCCESS;
}