Clang and gcc on macOS Catalina - Finding the include paths
macOS 10.15 alias Catalina is out since the end of 2019, but I usually wait a while before I upgrade. Last week I took this step and did it, assuming most issues are either solved or there are solutions out there on the internet.
Getting a macOS version that is no longer in the AppStore
The first barrier was getting macOS Catalina. I did download it at the time but must have deleted it. The issue here is that Apple no longer offers Catalina in the macOS AppStore. Various searches did not come up with a satisfying result. I wanted an official version, not something distributed on the internet. The solution here was macadmin-scripts. It is able to download the files from Apple and creates an installer. First hurdle solved.
/usr/include
is no more
The upgrade itself went smooth. Everything looked all right initially. After installing XCode again and the Command Line Tools, I was happy to compile some code. One thing important to mention here, I use gcc as well as the latest Clang version. The latter one to develop C++ Insights. Apple's Clang version only comes to use when I develop apps for the macOS AppStore. My local compilers were the issue. Thanks to a new security measure /usr/include
is no more on macOS since /usr
is now a read-only partition. Luckily, /usr/local
still works, so no trouble for brew
. Before Catalina, installing the Command Line Tools also installed /usr/include
pointing to a directory inside XCode. The current location of the system header files can be found with:
1 |
|
Just append /usr/include
to the output, and you have the location of the system headers. But /usr/include
itself is still gone.
Without this you will end up seeing compiler errors like this:
1 2 3 4 5 6 7 8 9 |
|
Teaching the compiler its default include path
My first attempts to solve this were all unsatisfying. I can provide all the search paths via -isystem
. That may be all right for projects with CMake
, but not for a quick compile directly on the command line. The next tip I found was setting the environment variable CPLUS_INCLUDE_PATH
. Both compilers use it, and you can override the default include paths with it. The trouble is that all system include paths, need to be listed as this environment variable replaces them all. It seemed like a doable approach first. But remember that I use Clang and gcc? The compilers C++ includes are different for each of them. But there is only one CPLUS_INCLUDE_PATH
.
For Clang it would be:
1 |
|
For gcc it would be:
1 |
|
Aside from the fact that the two compilers have a slightly different path scheme, it also depends on the version of the compiler. We can see clang-11
and gcc-10
, and even 10.2.0
in the path. This approach does not work even with multiple versions of the same compiler.
My next attempt was to supply only -isysroot
with the global CXXFLAGS
. Once again, at first, it looked like the right thing, but I learned that only gcc looks at that global environment variable. Clang doesn't.
SDKROOT
to rescue
Still unhappy with the status quo, I continued my search and found that Clang supports SDKROOT
to supply the base path to an SDK. On my system this is /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk
without /usr/include
. The last part is stable, and the compiler adds it itself.
After another round of investigation, I found this mailing list entry Pick up SDKROOT as the sysroot fallback from Iain Sandoe. Very good news. Gcc also supports SDKROOT
, so all I have to do for all my compilers is to define a single environment variable somewhere in .bashrc
:
1 |
|
That's it! No compiler version in it! One environment variable for both compilers.
CMake
What initially distracted me was CMake. Because C++ Insights did compile fine, it looks like CMake automatically sets SDKROOT
.
Despite that this is not my usual C++ content and very macOS specific, I hope you learned something and that you are able to continue developing C++ code under macOS with custom compilers.
Andreas