A Better C++ Setup for ICPC/Competitive Programming on MacOS
Motivation For Not Using the homebrew gcc
compiler
In my last blog, I talked about how to make the #include <bits/stdc++.h>
line of code work for c++
. At the time of posting, I didn’t realize that Xcode 15
had already been released about two weeks prior to that on September 18, 2023
. Upon installing this update, homebrew’s g++-13
stopped being able to compile anything on MacOS!
The workaround provided by user Eskimo on Apple Developer was adding -Wl,ld_classic
to the flag, which does fix the error. However, the new linker also came with a couple of other issues, like the annoying
ld: warning: duplicate -rpath '/opt/homebrew/lib' ignored
warning that as of the time of writing this post, seems to have no widely accepted workarounds.
Motivation for Using Apple clang version 15.0.0
Apple’s new linker in Xcode 15 (known as ld_prime
) is significantly (by an order of magnitude) faster than the old linker. So much so that now it is around 60% as fast as the mold linker, the fastest linker on the planet as of right now.
This leads to significant gains in build times, especially if you’re compiling often trying to debug code.
Furthermore, this increase in linker speed, or rather just the compatability of clang with the rest of the system, leads to much more responsive diagnostics in VSCode, which makes the coding experience all around better.
How To
The general idea behind this is to
- use the same
stdc++.h
file as provided in the officialgcc
repository, slightly touching it up to make sure that it is compatible with Apple’sclang
compiler, then - slapping it in into a path that Apple’s
clang
compiler scans when it looks for files#include
d with<>
angle brackets.
Step 1
Let’s assume you want your programming scratch source file to be main.cpp
.
We again go the official gcc repository and search for the stdc++.h
file. We copy the file into a local .h
file in the same directory as our map.cpp
file. We update the include statement in our main.cpp
file to #include "stdc++.h"
instead of #include <bits/stdc++.h>
.
Now we try to compile the main.cpp
file, and resolve all compiler warnings by removing parts unsupported by the Apple clang
compiler out of the stdc++.h
file.
As of Apple’s Clang 15, this consists of removing all the #IF
guards, as well as some 3-4 libraries that are unsupported (don’t worry, these libraries are extremely new in the c++ standard and seldom used for CP).
See my version here if you don’t feel like making your own stdc++.h
.
Now, the next step is to move the file into the include path of the apple clang
compiler. You could theoretically just keep it in the same directory as your main.cpp
file, but then you’d have to use #include ""
with quotes instead of angle brackets, making submitting the code significantly harder. So we’ll put it in the include paths instead, where clang
searches by default.
How do we find these include path directories that Clang searches for? We simply run the following command:
echo | clang -E -v -x c++ -
look for any line that starts after the
#include <...> search starts here:
line.
The path that I use is /usr/local/include
, since it’s the shortest and most readable.
Now we simply move our file over (making sure to create the bits
directory, if it doesn’t exist:)
sudo mkdir /usr/local/include/bits
# assuming your .h file is in the current directory
sudo mv ./stdc++.h /usr/local/include/bits/stdc++.h
Now you should be able to compile your main.cpp
with Apple clang
!
VSCode
I use the following VSCode settings:
"C_Cpp.default.compilerPath": "clang++",
"C_Cpp.default.intelliSenseMode": "macos-clang-arm64",
"C_Cpp.default.cppStandard": "c++20",
The top two lines aren’t required, but setting the c++ standard is pretty important. As of October 2023, ICPC supports up to c++20, so it’s beneficial to use the latest standard.
Thanks all! Thanks for reading. If you have any questions, feel free to reach out to my email at andy.shengdong.li@gmail.com.