c++g++clang++zshrcapple-m2

Why does Clang fail to compile, but GCC succeeds, with identical ~/.zshrc configuration?


On my Apple M2 (ARM64-apple-darwin) I have the following C++ code stored in the file hello_world.cpp in some directory called code. I want to be able to compile it using both Clang and GCC, but compilation with Clang fails.

#include <iostream>
//#include <stdfloat>

int main() {
    const double a = 4.0;
    std::cout << "Hello world! a has value " << a << std::endl;
}

To compile, I have

  1. Clang version 17.0.6 downloaded from the official github page with the C and C++ compilers under the paths /opt/clang+llvm/clang+llvm-17.0.6/bin/clang and /opt/clang+llvm/clang+llvm-17.0.6/bin/clang++, respectively
  2. GCC installed via Homebrew, version 14.3.0, with the C and C++ compilers under the path /opt/homebrew/Cellar/gcc@14/14.3.0/bin/gcc-14 and /opt/homebrew/Cellar/gcc@14/14.3.0/bin/g++-14, respectively.

Then, following this tutorial, I set up my ~/.zshrc file like this:

# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/Users/davidtschan/anaconda3/bin/conda' 'shell.zsh' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
    eval "$__conda_setup"
else
    if [ -f "/Users/davidtschan/anaconda3/etc/profile.d/conda.sh" ]; then
        . "/Users/davidtschan/anaconda3/etc/profile.d/conda.sh"
    else
        export PATH="/Users/davidtschan/anaconda3/bin:$PATH"
    fi
fi
unset __conda_setup
# <<< conda initialize <<<

set_clang_17() {
    export CC="/opt/clang+llvm/clang+llvm-17.0.6/bin/clang"
    export CXX="/opt/clang+llvm/clang+llvm-17.0.6/bin/clang++"
}

set_gcc_14() {
    export CC="$(brew --prefix gcc@14)/bin/gcc-14"
    export CXX="$(brew --prefix gcc@14)/bin/g++-14"
}

export CFLAGS="-isysroot $(xcrun -show-sdk-path) ${CFLAGS}"
export CXXFLAGS="-isysroot $(xcrun -show-sdk-path) ${CXXFLAGS}"

export LDFLAGS="-L$(xcrun -show-sdk-path)/usr/lib ${LDFLAGS}"

where the entire coda block was already in the ~/.zshrc file. Finally, using this, I open a terminal, run cd code to be in the directory of my .cpp source code, then I run set_gcc_14 and run $CXX -o hello_world hello_world.cpp which compiles without an error. Then I run set_clang_17, and re-run $CXX -o hello_world hello_world.cpp and I get the following error traceback:

In file included from hello_world.cpp:1:
In file included from /opt/clang+llvm/clang+llvm-17.0.6/bin/../include/c++/v1/iostream:43:
In file included from /opt/clang+llvm/clang+llvm-17.0.6/bin/../include/c++/v1/ios:221:
In file included from /opt/clang+llvm/clang+llvm-17.0.6/bin/../include/c++/v1/__ios/fpos.h:14:
In file included from /opt/clang+llvm/clang+llvm-17.0.6/bin/../include/c++/v1/iosfwd:106:
In file included from /opt/clang+llvm/clang+llvm-17.0.6/bin/../include/c++/v1/__std_mbstate_t.h:14:
/opt/clang+llvm/clang+llvm-17.0.6/bin/../include/c++/v1/__mbstate_t.h:51:5: error: "We don't know how to get the definition of mbstate_t without <wchar.h> on your platform."

The error goes on, I just put in a snippet. I guess it has something to do with the linker because when I run set_clang_17 and then run

$CXX -o hello_world hello_world.cpp -isysroot $(xcrun -show-sdk-path) -L$(xcrun -show-sdk-path)/usr/lib

the program can compile. I don't understand where the problem comes from, i.e. why it compiles when I make the root and linker paths explicit. Why do I have this behavior?

I expect set_clang_17 to give me the correct configuration so that I can compile hello_world.cpp using both clang++ and g++ using my setting from the ~/.zshrc file.


Solution

  • Because gcc on brew is built with --with-sysroot, pointing it to a default sysroot other than /.

    We can even see this by running strings $(which gcc-14) | fgrep .sdk:

    ../configure [...] --with-sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk
    

    Upstream clang is just not built that way, so it has its sysroot set to /.


    Separate note: you can also use --sysroot=... in place of -isysroot+-L.