Using clang on macOS to compile g++ / libstdc++ compatible binaries

clang++ by default compiles for system “native” C++ library. On macOS, that is LLVM’s libc++. But what happens if happen to have a lot of binaries (on in my case) libraries compiled with g++ using its own libdstdc++ library?

Why was I doing that in the first place? Work stuff is mostly Linux and therefore uses gcc, and the Apple-provided clang that ships with Xcode.app doesn’t support OpenMP, so I ended up building a lot of stuff with a homebrew-sourced gcc. But it turns out that gcc’s OpenMP support on macOS (in particular the implementation of the synchronization primitives in libgomp) is surprisingly slow (on Linux it’s much better). I ended up with a piece of OpenMP code whose performance was so bad, I need to cross check what the cause was, and so I installed a (non-Apple) clang with which I wanted to compile the code in question, but preferably without having to rebuild all my gcc-compiled (and therefore libstdc++-using) dependencies.

The following seems to work for a homebrew-installed gcc 9.3 and llvm (clang) 10:

CXX=/usr/local/opt/llvm/bin/clang++
CXXFLAGS="-stdlib=libstdc++ -stdlib++-isystem /usr/local/Cellar/gcc/9.3.0_1/include/c++/9.3.0/ -cxx-isystem /usr/local/Cellar/gcc/9.3.0_1/include/c++/9.3.0/x86_64-apple-darwin19"
LDFLAGS="-stdlib=libstdc++ -L /usr/local/Cellar/gcc/9.3.0_1/lib/gcc/9 -L /usr/local/opt/llvm/lib"

The last part of the link flags that add the library path back to the homebrew clang are only required so that that clang‘s OpenMP support can find its libomp support library.

This works unless you used something like libstdc++‘s implementation of std::call_once, because that needs internal symbols that are declared as __thread, which with how homebrew’s gcc is configurationed specifically or gcc on Darwin behaves generally used “emulated thread-local storage” (tls), which in turn requires mangling that __thread declared symbol differently 😔. clang even knows about that (see -femulated-tls), but when I tried to use that variant (which did indeed link without complaint) I got weird malloc errors in emutls functions, and it was easier for me to replace std::call_once with a hack than figuring out where those errors came from.

Mac Pro History

  • 2006-08
    • 2.66 GHz 2×2-Core Xeon
    • 4 GB 667 MHz DDR2 ECC
    • ATI Radeon X1900 XT 512 MB
    • 500 GB Serial ATA 3 Gb/s drive
    • 16x SuperDrive DL
    • Airport Extreme & BT 2.0+EDR
  • 2013-12
    • 3.5 GHz 6-Core Xeon
    • 32 GB 1866 MHz DDR3 ECC
    • 2x AMD FirePro D700 6 GB GDDR5
    • 512 GB PCIe-based SSD
  • 2019-12
    • 3.3 GHz 12-Core Xeon
    • 96 GB 2933 MHz DDR4 ECC
    • Radeon Pro 580X 8 GB GDDR5
    • 1 TB SSD

Cores went up, (base-)speed went down slightly (although the average turbo-boosted speed should be higher). Memory per thread went up from 1 GB to 4 GB (hello huge C++ templates). The graphics card will be replaced by the AMD Radeon Pro W5700X once available.

Some Game recommendations from 2018

  • Tacoma (“walking simulator” by Fullbright (who made “Gone Home”))
  • Zero Time Dilemma series (weird time travel visual novel + escape room puzzles)
  • Iconoclasts (metroidvania with strong puzzle focus
  • Life is Strange: Before the Storm (I thought I didn’t want to go back, but turns out, I did :))
  • Q.U.B.E and Q.U.B.E. 2 (first-person 3D puzzle games)
  • What Remains of Edith Finch (“walking simulator”)
  • Undertale (RPG by Toby Fox with an unusual battle system, good story and great music)
  • Yakuza 0 (prequel to the Yakuza series, good entry-point, and probably the best game in the series)
  • God of War (2018)
  • Monster Hunter World (still a bit obtuse, but the loop worked for me until the “now for the same monsters, but harder” part – which was 40-ish hours in)
  • Destiny 2: Forsaken (base D2 was a bit of a disappointment, but Forsaken managed another “Taken King” turn-around)
  • Celeste (excellent platformer, hard but fair (and teaches what you need to be able to do), great music, and interesting story)
  • ASTRO Bot Rescue Mission (charming VR platformer)
  • Marvel’s Spider Man (a bit repetitive, but ultimately OK)EXAPUNKS
  • 7 Billion Humans (sequel to Human Resource Machine, visual programming puzzle)

More (mechanical) keyboards and Mac key remapping

After browsing too much r/MechanicalKeyboards I bought some more keyboards… 😀

One is a white TKL CODE with 65g Zealios switches
White TKL CODE with 65g Zealios switches
(which is essentially the same as my current WASDv2 except for the case color, switches and lighting), which I bought because I was interested in the Zealios switches, and this is one of the few pre-made keyboards that offer them.

The other was a birthday present to myself and is a Leopold FC660C (Topre) in Grey & Blue:Leopold FC660C (Topre) in Grey & BlueThe Leopold does not have a Mac specific mode (although you can use its DIP switches to swap the Windows and Alt key, but that doesn’t get you ⌘ to the right of the space bar).

Therefore I fiddled a bit with remapping some keys for these keyboards for macOS use. One option for the Leopold FC660C is Hasu’s Alt Controller which replaces the controller board itself with a fully programmable one. Another option is to use Karabiner to remap the keys at the software level, but I found the CPU usage of Karabiner’s karabiner_grabber process a bit too high for what it should be doing. Since macOS 10.12 there’s another way to remap keys using hidutil.

My configuration (for both keyboards) looks as follows (stored inside ~/bin/remap.sh which is run on login, based on this script):

#!/usr/bin/env bash
# https://developer.apple.com/library/content/technotes/tn2450/_index.html
# https://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-1035.41.2/IOHIDFamily/IOHIDUsageTables.h.auto.html
# https://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-1035.41.2/IOHIDFamily/AppleHIDUsageTables.h.auto.html
FROM="\"HIDKeyboardModifierMappingSrc\""
TO="\"HIDKeyboardModifierMappingDst\""

ESCAPE="0x700000029"
CAPS_LOCK="0x700000039"

PRINT_SCREEN="0x700000046"
SCROLL_LOCK="0x700000047"
PAUSE="0x700000048"
INSERT="0x700000049"

F13="0x700000068"
F14="0x700000069"
F15="0x70000006A"

LEFT_ALT="0x7000000E2"
LEFT_GUI="0x7000000E3"
RIGHT_CTRL="0x7000000E4"
RIGHT_ALT="0x7000000E6"
RIGHT_GUI="0x7000000E7"
PC_MENU="0x700000065"

MEDIA_PLAY="0xC000000B0"
MEDIA_NEXT="0xC000000B5"
MEDIA_PREV="0xC000000B6"
MEDIA_EJECT="0xC000000B8"

# WASDv2 / CODE in Mac mode
hidutil property --matching '{"ProductID":0x269, "VendorID":0x4d9}' --set "{\"UserKeyMapping\":[
{$FROM: $CAPS_LOCK,    $TO: $ESCAPE},
{$FROM: $INSERT,       $TO: $MEDIA_PLAY},
{$FROM: $F13,          $TO: $MEDIA_EJECT},
{$FROM: $F14,          $TO: $MEDIA_PREV},
{$FROM: $F15,          $TO: $MEDIA_NEXT},
]}"
# Leopold FC660C
hidutil property --matching '{"ProductID":0x134, "VendorID":0x853}' --set "{\"UserKeyMapping\":[
{$FROM: $CAPS_LOCK,    $TO: $ESCAPE},
{$FROM: $LEFT_GUI,     $TO: $LEFT_ALT},
{$FROM: $LEFT_ALT,     $TO: $LEFT_GUI},
{$FROM: $RIGHT_ALT,    $TO: $RIGHT_GUI},
{$FROM: $RIGHT_CTRL,   $TO: $RIGHT_ALT},
{$FROM: $PC_MENU,      $TO: $RIGHT_CTRL},
{$FROM: $INSERT,       $TO: $MEDIA_PLAY},
{$FROM: $PRINT_SCREEN, $TO: $MEDIA_EJECT},
{$FROM: $SCROLL_LOCK,  $TO: $MEDIA_PREV},
{$FROM: $PAUSE,        $TO: $MEDIA_NEXT},
]}"

Mainly this maps the modifier keys to be more Mac-like, caps lock to escape (which means I can run the Leopold’s escape key permanently in ` / ~ mode (using Fn + Q), as well as some media keys. The links in the header-comment of the script contain lists of supported pages and usages; the page is the upper 32-bit word and the usage the lower 32-bit word.

If you want to run this on login, you can use launchd by storing a plist in ~/Library/LaunchAgents/de.maven.remap_keys.plist for example containing

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>de.maven.remap_keys</string>
    <key>ProgramArguments</key>
    <array><string>/Users/maven/bin/remap.sh</string></array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>

Happy hacking!

SoundPusher v1.0.0

And we have a release (which is fairly untested, but it works for me). This is first time I’ve released something post-Gatekeeper, so I hope I signed all the things correctly. Also the first time I’ve attempted an installer.

I’ve redone the synchronisation between the input and output thread about 5 times now, let’s hope this variant works out. It’s easy if you don’t care about latency, but trying to get that as low as possible without glitching and staying real-time is quite hard. By default, only AC3 encoding is enabled as DTS support in libavcodec is only experimental. EAC3 seems to distribute packets over multiple SPDIF frames, and thus seems to be a bad choice due to further increased latency.

Diablo 3 sounds quite different with 5.1 sound for example, as the different screen corners map to in front or behind your character (and thus the listener) due to the isometric perspective.

Report any issues or suggestions on the GitHub page. Happy multi-channel audio-ing! 🙂