Can't compile a simple c++ file with g++ on MacOS 13, XCode 14

1.4k Views Asked by At

I'm on a new M2 Mac Mini. I have this simple test c++ file:

% cat conftest.cpp 
#include <limits>
#include <cmath>
#include <algorithm>
int main(int argc, char **argv) { return 0;}

I need to compile it with c++ rather than clang++ (the actual problem is building a conan dependency that does this, so I can't easily switch it).

I have XCode 14.2 (latest, I think) and this c++

% g++ --version
Apple clang version 14.0.0 (clang-1400.0.29.202)
Target: arm64-apple-darwin22.3.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

From my reading, I know that since Catalina XCode's g++ doesn't automatically find the standard header and lib dirs the way clang does on Mac, so I think I need to set CPATH and LIBPATH.

% echo $LIBRARY_PATH 
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib
% echo $CPATH
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include

Unfortunately, compiling this gives an error, which appears to be a conflict between cmath and algorithm because removing either of those makes it compile and link OK:

% /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ conftest.cpp
In file included from conftest.cpp:4:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/algorithm:653:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:499:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional/bind_back.h:15:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional/perfect_forward.h:17:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:159:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_base:22:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/exception:83:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/cstdlib:130:9: error: target of using declaration conflicts with declaration already in scope
using ::abs _LIBCPP_USING_IF_EXISTS;
        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/stdlib.h:132:6: note: target of using declaration
int      abs(int) __pure2;
         ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/cmath:338:1: note: conflicting declaration
using ::abs _LIBCPP_USING_IF_EXISTS;
^

I must be missing something simple. That test program compiles and runs fine on godbolt and Windows. Any ideas, anyone?

1

There are 1 best solutions below

3
Anya Shenanigans On BEST ANSWER

The issue here is one of wrapping. When you invoke the toolchain compiler directly, it uses a specific set of headers for the toolchain itself, and omits the headers for the platform. When we use -### to see all the include paths specified for the toolchain compiler, we see the following from the direct toolchain compiler:

So compiling with /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++:

"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1"
"/usr/local/include"
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/14.0.0/include"
"/usr/include"
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include"

Compiling with the /usr/bin/c++ wrapper, we get the following headers:

"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk"
"-I/usr/local/include"
"-stdlib=libc++"
"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1"
"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/local/include"
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/14.0.0/include"
"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include"
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include"

It's adding in the headers for macOS, because it assumes it's building for MacOS, because it's the local wrapper.

We can successfully compile using the toolchain compiler, when we pass in an additional -isysroot option as extracted using:

-isysroot $(xcrun --sdk macosx --show-sdk-path)

so:

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ -isysroot $(xcrun --sdk macosx --show-sdk-path) -o conftest conftest.cpp

builds and runs cleanly. In the case of trying to get dependencies to build properly you're going to need to pick the appropriate compiler for the target.

If you want to work around building, the two variables that matter in this case are generally CPPFLAGS and CXXFLAGS - flags for the preprocessor and C++ compiler. You should be able to set CPPFLAGS to:

-isysroot $(xcrun --sdk macosx --show-sdk-path)

and it should build for you, if the standard makefile logic is in effect in the tools you're using.

$ export CPPFLAGS="-isysroot $(xcrun --sdk macosx --show-sdk-path)"
$ export CXX=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++
$ make conftest
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++  -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.1.sdk   conftest.cpp   -o conftest