build as C++ the normal way

Instead of building with $cc and linking a C++ standard library
where needed, build with $cxx, which takes care of that for us.

This lets us use threadsafe statics to check for Haswell support
once, rather than the platform-specific versions we use today.
(Threadsafe statics tend to need helpers from the library.)

Change-Id: If71eb4b6223b36ac6b9c6e587e1614020de5f291
Reviewed-on: https://skia-review.googlesource.com/139541
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
diff --git a/build/android b/build/android
index fb780cb..273f692 100644
--- a/build/android
+++ b/build/android
@@ -3,7 +3,9 @@
 arch    = arch-arm64
 ndk_api = 24
 
-cc      = $ndk/toolchains/llvm/prebuilt/*/bin/clang -target $target
+cc      = $ndk/toolchains/llvm/prebuilt/*/bin/clang   -target $target
+cxx     = $ndk/toolchains/llvm/prebuilt/*/bin/clang++ -target $target
+
 cflags  = -fcolor-diagnostics -Weverything $
           --sysroot $ndk/sysroot $
           -I $ndk/sysroot/usr/include/$target
diff --git a/build/android-arm b/build/android-arm
index e04beb5..d43d14c 100644
--- a/build/android-arm
+++ b/build/android-arm
@@ -3,7 +3,9 @@
 arch    = arch-arm
 ndk_api = 24
 
-cc      = $ndk/toolchains/llvm/prebuilt/*/bin/clang -target $target
+cc      = $ndk/toolchains/llvm/prebuilt/*/bin/clang   -target $target
+cxx     = $ndk/toolchains/llvm/prebuilt/*/bin/clang++ -target $target
+
 cflags  = -fcolor-diagnostics -Weverything $
           -march=armv7-a -mthumb $
           --sysroot $ndk/sysroot $
diff --git a/build/android-arm-gcc b/build/android-arm-gcc
index 1b1c452..fbf3fd2 100644
--- a/build/android-arm-gcc
+++ b/build/android-arm-gcc
@@ -4,6 +4,8 @@
 ndk_api = 24
 
 cc      = $ndk/toolchains/${target}-4.9/prebuilt/*/bin/${target}-gcc
+cxx     = $ndk/toolchains/${target}-4.9/prebuilt/*/bin/${target}-g++
+
 cflags  = -fdiagnostics-color -Wall -Wextra $
           -march=armv7-a -mfpu=neon -mthumb -mfloat-abi=softfp $
           --sysroot $ndk/sysroot $
diff --git a/build/android.fp16 b/build/android.fp16
index aec757f..9ec3191 100644
--- a/build/android.fp16
+++ b/build/android.fp16
@@ -4,4 +4,5 @@
 
 # The Clang in NDK ≤r17 is not new enough to support -march=armv8.2a+fp16 in any interesting way,
 # so we use your generic `clang` instead, which is hopefully newer.
-cc = clang -target $target
+cc  = clang   -target $target
+cxx = clang++ -target $target
diff --git a/build/clang b/build/clang
index c588705..27bad60 100644
--- a/build/clang
+++ b/build/clang
@@ -1,4 +1,5 @@
 cc     = clang
+cxx    = clang++
 cflags = -fcolor-diagnostics -Weverything
 out    = out/clang$mode
 
diff --git a/build/clang.xsan b/build/clang.xsan
index e28fb3a..014fec4 100644
--- a/build/clang.xsan
+++ b/build/clang.xsan
@@ -1,4 +1,4 @@
 mode          = .xsan
 extra_cflags  = -fsanitize=address,integer,undefined -fno-sanitize-recover=all
-extra_ldflags = -fsanitize=address,integer,undefined -lc++
+extra_ldflags = -fsanitize=address,integer,undefined
 include build/clang
diff --git a/build/common b/build/common
index 87a6c9f..a961577 100644
--- a/build/common
+++ b/build/common
@@ -25,14 +25,14 @@
     description = compile $out
 
 rule compile_cc
-    command = $disabled && touch $out || $cc -std=c++11 -g -Os $warnings_cc $cflags $extra_cflags $
+    command = $disabled && touch $out || $cxx -std=c++11 -g -Os $warnings_cc $cflags $extra_cflags $
              -MD -MF $out.d -c $in -o $out
     depfile = $out.d
     deps    = gcc
     description = compile $out
 
 rule link
-    command = $disabled && touch $out || $cc $ldflags $extra_ldflags $in -ldl -pthread -o $out
+    command = $disabled && touch $out || $cxx $ldflags $extra_ldflags $in -ldl -o $out
     description = link $out
 
 include build/targets
diff --git a/build/gcc b/build/gcc
index 2b6e1f9..ee9f8e4 100644
--- a/build/gcc
+++ b/build/gcc
@@ -1,4 +1,5 @@
 cc     = gcc
+cxx    = g++
 cflags = -fdiagnostics-color -Wall -Wextra -ffp-contract=off -fstack-usage
 out    = out/gcc$mode
 
diff --git a/build/gcc.xsan b/build/gcc.xsan
index a53f6ec..150ce07 100644
--- a/build/gcc.xsan
+++ b/build/gcc.xsan
@@ -1,4 +1,4 @@
 mode          = .xsan
 extra_cflags  = -fsanitize=address,undefined -fno-sanitize-recover=all
-extra_ldflags = -fsanitize=address,undefined -lstdc++
+extra_ldflags = -fsanitize=address,undefined
 include build/gcc
diff --git a/build/ios b/build/ios
index 638ea31..3667b11 100644
--- a/build/ios
+++ b/build/ios
@@ -1,4 +1,5 @@
-cc     = clang -arch arm64 -isysroot `xcrun --sdk iphoneos --show-sdk-path`
+cc     = clang   -arch arm64 -isysroot `xcrun --sdk iphoneos --show-sdk-path`
+cxx    = clang++ -arch arm64 -isysroot `xcrun --sdk iphoneos --show-sdk-path`
 cflags = -fcolor-diagnostics -Weverything
 out    = out/ios$mode
 
diff --git a/infra/bots/bot.py b/infra/bots/bot.py
index 19688cf..a6c937d 100644
--- a/infra/bots/bot.py
+++ b/infra/bots/bot.py
@@ -28,10 +28,13 @@
 elif 'linux' in sys.platform:
   # Point to clang in our clang_linux package.
   clang_linux = os.path.realpath(sys.argv[3])
-  append('skcms/build/clang', 'cc = {}/bin/clang'.format(clang_linux))
+  append('skcms/build/clang', 'cc  = {}/bin/clang  '.format(clang_linux))
+  append('skcms/build/clang', 'cxx = {}/bin/clang++'.format(clang_linux))
   # TODO(mtklein): once the NDK is new enough (r18?) we can use its Clang again
   append('skcms/build/android.fp16',
-         'cc = {}/bin/clang -target $target'.format(clang_linux))
+         'cc  = {}/bin/clang   -target $target'.format(clang_linux))
+  append('skcms/build/android.fp16',
+         'cxx = {}/bin/clang++ -target $target'.format(clang_linux))
 
   call('{ninja}/ninja -C skcms -k 0'.format(ninja=ninja))
 
diff --git a/skcms.cc b/skcms.cc
index 41a67ff..e81f949 100644
--- a/skcms.cc
+++ b/skcms.cc
@@ -1977,70 +1977,46 @@
 
     #define TEST_FOR_HSW
 
-    static bool hsw_ok_ = false;
-    static void check_hsw_ok() {
-        // See http://www.sandpile.org/x86/cpuid.htm
+    static bool hsw_ok() {
+        static const bool ok = []{
+            // See http://www.sandpile.org/x86/cpuid.htm
 
-        // First, a basic cpuid(1).
-        uint32_t eax, ebx, ecx, edx;
-        __asm__ __volatile__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
-                                     : "0"(1), "2"(0));
+            // First, a basic cpuid(1).
+            uint32_t eax, ebx, ecx, edx;
+            __asm__ __volatile__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
+                                         : "0"(1), "2"(0));
 
-        // Sanity check for prerequisites.
-        if ((edx & (1<<25)) != (1<<25)) { return; }   // SSE
-        if ((edx & (1<<26)) != (1<<26)) { return; }   // SSE2
-        if ((ecx & (1<< 0)) != (1<< 0)) { return; }   // SSE3
-        if ((ecx & (1<< 9)) != (1<< 9)) { return; }   // SSSE3
-        if ((ecx & (1<<19)) != (1<<19)) { return; }   // SSE4.1
-        if ((ecx & (1<<20)) != (1<<20)) { return; }   // SSE4.2
+            // Sanity check for prerequisites.
+            if ((edx & (1<<25)) != (1<<25)) { return false; }   // SSE
+            if ((edx & (1<<26)) != (1<<26)) { return false; }   // SSE2
+            if ((ecx & (1<< 0)) != (1<< 0)) { return false; }   // SSE3
+            if ((ecx & (1<< 9)) != (1<< 9)) { return false; }   // SSSE3
+            if ((ecx & (1<<19)) != (1<<19)) { return false; }   // SSE4.1
+            if ((ecx & (1<<20)) != (1<<20)) { return false; }   // SSE4.2
 
-        if ((ecx & (3<<26)) != (3<<26)) { return; }   // XSAVE + OSXSAVE
+            if ((ecx & (3<<26)) != (3<<26)) { return false; }   // XSAVE + OSXSAVE
 
-        {
-            uint32_t eax_xgetbv, edx_xgetbv;
-            __asm__ __volatile__("xgetbv" : "=a"(eax_xgetbv), "=d"(edx_xgetbv) : "c"(0));
-            if ((eax_xgetbv & (3<<1)) != (3<<1)) { return; }  // XMM+YMM state saved?
-        }
+            {
+                uint32_t eax_xgetbv, edx_xgetbv;
+                __asm__ __volatile__("xgetbv" : "=a"(eax_xgetbv), "=d"(edx_xgetbv) : "c"(0));
+                if ((eax_xgetbv & (3<<1)) != (3<<1)) { return false; }  // XMM+YMM state saved?
+            }
 
-        if ((ecx & (1<<28)) != (1<<28)) { return; }   // AVX
-        if ((ecx & (1<<29)) != (1<<29)) { return; }   // F16C
-        if ((ecx & (1<<12)) != (1<<12)) { return; }   // FMA  (TODO: not currently used)
+            if ((ecx & (1<<28)) != (1<<28)) { return false; }   // AVX
+            if ((ecx & (1<<29)) != (1<<29)) { return false; }   // F16C
+            if ((ecx & (1<<12)) != (1<<12)) { return false; }   // FMA  (TODO: not currently used)
 
-        // Call cpuid(7) to check for our final AVX2 feature bit!
-        __asm__ __volatile__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
-                                     : "0"(7), "2"(0));
-        if ((ebx & (1<< 5)) != (1<< 5)) { return; }   // AVX2
+            // Call cpuid(7) to check for our final AVX2 feature bit!
+            __asm__ __volatile__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
+                                         : "0"(7), "2"(0));
+            if ((ebx & (1<< 5)) != (1<< 5)) { return false; }   // AVX2
 
-        hsw_ok_ = true;
+            return true;
+        }();
+
+        return ok;
     }
 
-    #if defined(_MSC_VER)
-        #include <Windows.h>
-        INIT_ONCE check_hsw_ok_once = INIT_ONCE_STATIC_INIT;
-
-        static BOOL check_hsw_ok_InitOnce_wrapper(INIT_ONCE* once, void* param, void** ctx) {
-            (void)once;
-            (void)param;
-            (void)ctx;
-            check_hsw_ok();
-            return TRUE;
-        }
-
-        static bool hsw_ok() {
-            InitOnceExecuteOnce(&check_hsw_ok_once, check_hsw_ok_InitOnce_wrapper,
-                                nullptr, nullptr);
-            return hsw_ok_;
-        }
-    #else
-        #include <pthread.h>
-        static pthread_once_t check_hsw_ok_once = PTHREAD_ONCE_INIT;
-
-        static bool hsw_ok() {
-            pthread_once(&check_hsw_ok_once, check_hsw_ok);
-            return hsw_ok_;
-        }
-    #endif
-
 #endif
 
 static bool is_identity_tf(const skcms_TransferFunction* tf) {