authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-10 23:38:44-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-05-10 23:38:44-04:00
logf5edf78eea403c14635a05e1729672cfb50aca89
tree1661a15b3ee4427ce6a4286f4c972be49e9f572c
parent458943e324e81762a9a2aa839d2fa3c851068e6f
parent45415093c655d30ec226172695248fbf28941667
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10143 from nuald/single-threaded-cpp1

Normalized C++ compilation options for single-threaded targets

5 files changed, 106 insertions(+), 32 deletions(-)

src/Compilation.zig+13
......@@ -1180,6 +1180,15 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
11801180 if (must_single_thread and !single_threaded) {
11811181 return error.TargetRequiresSingleThreaded;
11821182 }
1183 if (!single_threaded and options.link_libcpp) {
1184 if (options.target.cpu.arch.isARM()) {
1185 log.warn(
1186 \\libc++ does not work on multi-threaded ARM yet.
1187 \\For more details: https://github.com/ziglang/zig/issues/6573
1188 , .{});
1189 return error.TargetRequiresSingleThreaded;
1190 }
1191 }
11831192
11841193 const llvm_cpu_features: ?[*:0]const u8 = if (build_options.have_llvm and use_llvm) blk: {
11851194 var buf = std.ArrayList(u8).init(arena);
......@@ -3803,6 +3812,10 @@ pub fn addCCArgs(
38033812 try argv.append("-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS");
38043813 try argv.append("-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS");
38053814 try argv.append("-D_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS");
3815
3816 if (comp.bin_file.options.single_threaded) {
3817 try argv.append("-D_LIBCPP_HAS_NO_THREADS");
3818 }
38063819 }
38073820
38083821 if (comp.bin_file.options.link_libunwind) {
src/libcxx.zig+18-6
......@@ -128,6 +128,12 @@ pub fn buildLibCXX(comp: *Compilation) !void {
128128 continue;
129129 if (std.mem.startsWith(u8, cxx_src, "src/support/ibm/") and target.os.tag != .zos)
130130 continue;
131 if (comp.bin_file.options.single_threaded) {
132 if (std.mem.startsWith(u8, cxx_src, "src/support/win32/thread_win32.cpp")) {
133 continue;
134 }
135 try cflags.append("-D_LIBCPP_HAS_NO_THREADS");
136 }
131137
132138 try cflags.append("-DNDEBUG");
133139 try cflags.append("-D_LIBCPP_BUILDING_LIBRARY");
......@@ -145,8 +151,7 @@ pub fn buildLibCXX(comp: *Compilation) !void {
145151 }
146152
147153 if (target.os.tag == .wasi) {
148 // WASI doesn't support thread and exception yet.
149 try cflags.append("-D_LIBCPP_HAS_NO_THREADS");
154 // WASI doesn't support exceptions yet.
150155 try cflags.append("-fno-exceptions");
151156 }
152157
......@@ -264,13 +269,20 @@ pub fn buildLibCXXABI(comp: *Compilation) !void {
264269 var cflags = std.ArrayList([]const u8).init(arena);
265270
266271 if (target.os.tag == .wasi) {
267 // WASI doesn't support thread and exception yet.
268 if (std.mem.startsWith(u8, cxxabi_src, "src/cxa_thread_atexit.cpp") or
269 std.mem.startsWith(u8, cxxabi_src, "src/cxa_exception.cpp") or
272 // WASI doesn't support exceptions yet.
273 if (std.mem.startsWith(u8, cxxabi_src, "src/cxa_exception.cpp") or
270274 std.mem.startsWith(u8, cxxabi_src, "src/cxa_personality.cpp"))
271275 continue;
272 try cflags.append("-D_LIBCXXABI_HAS_NO_THREADS");
273276 try cflags.append("-fno-exceptions");
277 }
278
279 // WASM targets are single threaded.
280 if (comp.bin_file.options.single_threaded) {
281 if (std.mem.startsWith(u8, cxxabi_src, "src/cxa_thread_atexit.cpp")) {
282 continue;
283 }
284 try cflags.append("-D_LIBCXXABI_HAS_NO_THREADS");
285 try cflags.append("-D_LIBCPP_HAS_NO_THREADS");
274286 } else {
275287 try cflags.append("-DHAVE___CXA_THREAD_ATEXIT_IMPL");
276288 }
test/standalone/c_compiler/build.zig+1-1
......@@ -29,7 +29,7 @@ pub fn build(b: *Builder) void {
2929 exe_cpp.addCSourceFile("test.cpp", &[0][]const u8{});
3030 exe_cpp.setBuildMode(mode);
3131 exe_cpp.setTarget(target);
32 exe_cpp.linkSystemLibrary("c++");
32 exe_cpp.linkLibCpp();
3333
3434 switch (target.getOsTag()) {
3535 .windows => {
test/standalone/c_compiler/test.c+13-10
......@@ -1,25 +1,28 @@
11#include <assert.h>
22#include <stdio.h>
3#include <stdlib.h>
34
4typedef struct {
5 int val;
5typedef struct {
6 int val;
67} STest;
78
89int getVal(STest* data) { return data->val; }
910
1011int main (int argc, char *argv[])
1112{
12 STest* data = (STest*)malloc(sizeof(STest));
13 data->val = 123;
13 STest* data = (STest*)malloc(sizeof(STest));
14 data->val = 123;
1415
15 assert(getVal(data) != 456);
16 int ok = (getVal(data) == 123);
16 assert(getVal(data) != 456);
17 int ok = (getVal(data) == 123);
1718
18 if (argc>1) fprintf(stdout, "val=%d\n", data->val);
19 if (argc > 1) {
20 fprintf(stdout, "val=%d\n", data->val);
21 }
1922
20 free(data);
23 free(data);
2124
22 if (!ok) abort();
25 if (!ok) abort();
2326
24 return 0;
27 return EXIT_SUCCESS;
2528}
test/standalone/c_compiler/test.cpp+61-15
......@@ -1,33 +1,79 @@
1#include <iostream>
21#include <cassert>
2#include <iostream>
3
4#ifndef _LIBCPP_HAS_NO_THREADS
5#include <future>
6#endif
7
8thread_local unsigned int tls_counter = 1;
9
10// a non-optimized way of checking for prime numbers:
11bool is_prime(int x) {
12 for (int i = 2; i <x ; ++i) {
13 if (x % i == 0) {
14 return false;
15 }
16 }
17 return true;
18}
319
420class CTest {
521public:
6 CTest(int val) : m_val(val) {};
7 virtual ~CTest() {}
22 CTest(int val) : m_val(val) {
23 tls_counter++;
24 };
25 virtual ~CTest() {}
826
9 virtual int getVal() const { return m_val; }
10 virtual void printVal() { std::cout << "val=" << m_val << std::endl; }
27 virtual int getVal() const { return m_val; }
28 virtual void printVal() { std::cout << "val=" << m_val << std::endl; }
1129private:
12 int m_val;
30 int m_val;
31};
32
33class GlobalConstructorTest {
34public:
35 GlobalConstructorTest(int val) : m_val(val) {};
36 virtual ~GlobalConstructorTest() {}
37
38 virtual int getVal() const { return m_val; }
39 virtual void printVal() { std::cout << "val=" << m_val << std::endl; }
40private:
41 int m_val;
1342};
1443
1544
1645volatile int runtime_val = 456;
17CTest global(runtime_val); // test if global initializers are called.
46GlobalConstructorTest global(runtime_val); // test if global initializers are called.
1847
1948int main (int argc, char *argv[])
2049{
21 assert(global.getVal() == 456);
50 assert(global.getVal() == 456);
51
52 auto t = std::make_unique<CTest>(123);
53 assert(t->getVal() != 456);
54 assert(tls_counter == 2);
55 if (argc > 1) {
56 t->printVal();
57 }
58 bool ok = t->getVal() == 123;
2259
23 auto* t = new CTest(123);
24 assert(t->getVal()!=456);
60 if (!ok) abort();
2561
26 if (argc>1) t->printVal();
27 bool ok = t->getVal() == 123;
28 delete t;
62#ifndef _LIBCPP_HAS_NO_THREADS
63 std::future<bool> fut = std::async(is_prime, 313);
64 bool ret = fut.get();
65 assert(ret);
66#endif
2967
30 if (!ok) abort();
68#if !defined(__wasm__) && !defined(__APPLE__)
69 // WASM and macOS are not passing this yet.
70 // TODO file an issue for this and link it here.
71 try {
72 throw 20;
73 } catch (int e) {
74 assert(e == 20);
75 }
76#endif
3177
32 return 0;
78 return EXIT_SUCCESS;
3379}