Catalina C++: Using <cmath> headers yield error: no member named 'signbit' in the global namespace

I'm curious: What compiler are you using? What's the value of CMAKE_OSX_SYSROOT?

I'm fairly convinced this is the result of a wrong CMAKE_OSX_SYSROOT. I had the problem you're describing when using python bindings for clang (where CMake doesn't manage the compiler call), but I managed to recreate the error in CMake by doing:

set(CMAKE_OSX_SYSROOT "")  # Reset.

I solved my problem by following the answers to this question: Cannot compile R packages with c++ code after updating to macOS Catalina.

To summarise: On Catalina, /usr/include is purged and protected by SIP. Thus, any project that expects the C headers to be found there will fail to compile. If I remember correctly, Apple recommends to file bug reports to projects that expect C headers in /usr/include.

You must point the build system of the code you're trying to compile to the right headers:

(1) Make sure Xcode is up to date. There's no telling what an outdated Xcode on Catalina might do to your build environment.

(2) Use the -isysroot /sdk/path compiler flag, where /sdk/path is the result of xcrun --show-sdk-path. I'm not sure what CMake's best practice is, but try doing

set(CMAKE_OSX_SYSROOT /sdk/path)

or

set(CMAKE_CXX_FLAGS "[...] -isysroot /sdk/path")

If that solves the problem, you may want to look for a better way to do this in CMake.

Of course, if you're adventurous, you could also disable SIP, as suggested in the answer to my question: /usr/include missing on macOS Catalina (with Xcode 11)


I am having the same problem while trying to target iOS (both on my MacBook Air and on GitHub Actions runner) and here are a few more thoughts on the problem even though I'm not familiar enough with Apple's ecosystem to suggest a proper solution. The original command line was coming from CMake in cpprestsdk, but once I boiled it down to essentials, here is a short repro.

  1. Create file cmath-bug.cpp with the only line in it:
    #include <cmath>
  1. Run (newlines in front of some arguments are for reading convenience, remove them)
clang -v -x c++ -target arm64-apple-ios13.2 -fcolor-diagnostics -std=c++11 -stdlib=libc++ 
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.2.sdk 
-isystem  /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.2.sdk/usr/include
-c cmath-bug.cpp

When I run it, i get the familiar to many facing the same issue:

Apple clang version 11.0.0 (clang-1100.0.33.16)
Target: arm64-apple-ios13.2
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
 "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" -cc1 -triple arm64-apple-ios13.2.0 -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -Werror=implicit-function-declaration -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -discard-value-names -main-file-name cmath-bug.cpp -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -fno-strict-return -masm-verbose -munwind-tables -target-sdk-version=13.2 -target-cpu cyclone -target-feature +fp-armv8 -target-feature +neon -target-feature +crypto -target-feature +zcm -target-feature +zcz -target-feature +sha2 -target-feature +aes -target-abi darwinpcs -fallow-half-arguments-and-returns -dwarf-column-info -debugger-tuning=lldb -ggnu-pubnames -target-linker-version 530 -v -coverage-notes-file /Users/myuser/Projects/C++/cmath-bug.gcno -resource-dir /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/11.0.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.2.sdk -isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.2.sdk/usr/include -stdlib=libc++ -internal-isystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1 -Wno-framework-include-private-from-public -Wno-atimport-in-framework-header -Wno-extra-semi-stmt -Wno-quoted-include-in-framework-header -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /Users/myuser/Projects/C++ -ferror-limit 19 -fmessage-length 204 -stack-protector 1 -fstack-check -mdarwin-stkchk-strong-link -fblocks -fencode-extended-block-signature -fregister-global-dtors-with-atexit -fobjc-runtime=ios-13.2.0 -fcxx-exceptions -fexceptions -fmax-type-align=16 -fdiagnostics-show-option -fcolor-diagnostics -o cmath-bug.o -x c++ cmath-bug.cpp
clang -cc1 version 11.0.0 (clang-1100.0.33.16) default target x86_64-apple-darwin19.0.0
ignoring nonexistent directory "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.2.sdk/usr/include/c++/v1"
ignoring nonexistent directory "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.2.sdk/usr/local/include"
ignoring nonexistent directory "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.2.sdk/Library/Frameworks"
ignoring duplicate directory "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.2.sdk/usr/include"
#include "..." search starts here:
#include <...> search starts here:
 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.2.sdk/usr/include
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/11.0.0/include
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include
 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.2.sdk/System/Library/Frameworks (framework directory)
End of search list.
In file included from cmath-bug.cpp:1:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/cmath:318:9: error: no member named 'signbit' in the global namespace
using ::signbit;
      ~~^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/cmath:319:9: error: no member named 'fpclassify' in the global namespace
using ::fpclassify;
      ~~^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/cmath:320:9: error: no member named 'isfinite' in the global namespace; did you mean 'finite'?
using ::isfinite;
      ~~^

The only 2 include directories I pass on my original command line exist and are:

$ ls -alF /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.2.sdk
lrwxr-xr-x  1 root  wheel    12B Dec 17 11:54 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.2.sdk@ -> iPhoneOS.sdk
$ ls -alF /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.2.sdk/usr/include
total 2160
drwxr-xr-x  169 root  wheel   5.3K Dec 17 12:07 ./
drwxr-xr-x    5 root  wheel   160B Nov  4 19:22 ../
 ...
-rw-r--r--    9 root  wheel    32K Nov  4 19:52 math.h
 ...

But the interesting bits here are the non-existing include directories it reports as well as the include directories it ends up searching eventually and their order. My guess is that additional directories not mentioned on the command line are inserted by Apple Clang's driver based on some Apple-specific logic.

You can see from the reported error that the <cmath> header is found at: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/cmath and at line 304 of it you can see:

#include <__config>      // Line 304
#include <math.h>        // This one ends up causing troubles
#include <__cxx_version>

Judging from the fact that in that same folder /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/ there is a file math.h that provides the necessary definitions, e.g.:

#include <__config>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif

#include_next <math.h>

#ifdef __cplusplus

// We support including .h headers inside 'extern "C"' contexts, so switch
// back to C++ linkage before including these C++ headers.
extern "C++" {

#include <type_traits>
#include <limits>

// signbit

#ifdef signbit

template <class _A1>
_LIBCPP_INLINE_VISIBILITY
bool
__libcpp_signbit(_A1 __lcpp_x) _NOEXCEPT
{
    return signbit(__lcpp_x);
}

#undef signbit

template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if<std::is_floating_point<_A1>::value, bool>::type
signbit(_A1 __lcpp_x) _NOEXCEPT
{
    return __libcpp_signbit((typename std::__promote<_A1>::type)__lcpp_x);
}

...

#elif defined(_LIBCPP_MSVCRT)
...
#endif  // signbit

the authors of <cmath> were expecting the math.h from that same folder be included first and then the #include_next <math.h> directive find the system-specific math.h. That is not what's happening in reality however.

If you look at the first 2 entries in searched directories:

#include <...> search starts here:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.2.sdk/usr/include
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1

you see that system-specific include directory ends up being above the Clang-injected standard library directory, which is why the system-specific math.h is being found, not the one in the same folder as the rest of the standard library headers. This is likely the case because if I explicitly add the standard library include directory to my command line BEFORE the other two directories -isystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1 the problem goes away and I am able to compile the file. That's not what Clang's driver or whatever else is involved here does automatically: it adds that standard library directory via -internal-system (not sure what's the semantics of that internal flag) and it adds it AFTER the system directory.

Now if you look at the list of ignored directories, the very first entry in that list is:

ignoring nonexistent directory "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.2.sdk/usr/include/c++/v1"

of which the trailing c++/v1 part does not exist on my machine, making me wonder whether the iPhone SDK installation was supposed to create a symbolic link c++ inside the existing part of the path to point to /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++ directory to make the whole thing work.

Anyways, this what I think is happening and I wonder if anyone knows how to properly fix this?

Thank you!

P.S. For the context:

$ xcode-select -p
/Applications/Xcode.app/Contents/Developer
$ xcrun --show-sdk-path -sdk iphoneos13.2
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.2.sdk