如何在预处理器中检测-stdlib=libc++

How to detect -stdlib=libc++ in the preprocessor?

本文关键字:检测 -stdlib libc++ 处理器 预处理      更新时间:2023-10-16

我认为这是在LLVM/Cang下编译时,命名空间"std"中名为"unique_ptr"的No类型出现问题的一部分。根据Marshall Clow的说法,我可以通过_LIBCPP_VERSION:检测-stdlib=libc++

如果您正在编写跨平台代码,有时您需要知道您正在使用的标准库。理论上,他们都应该提供等效功能,但这只是理论。有时你只是需要知道。检查libc++的最佳方法是查找预处理器符号_LIBCPP_VERSION。如果这是定义的,那么你使用libc++。

#ifdef  _LIBCPP_VERSION
//  libc++ specific code here
#else
//  generic code here
#endif

不幸的是,苹果的Clang(3.4-SVN(和我从LLVM项目下载后从源代码构建的Clang。我猜这个测试只在Xcode下有效。

如何在预处理器中可靠地检测-stdlib=libc++


以下是测试用例:

$ cat test-clapple.cxx
// Need to test {C++03,C++11} x {libc++, no libc++}
// c++ -c test-clapple.cxx
//     - OK
// c++ -stdlib=libc++ -c test-clapple.cxx
//     - OK
// c++ -std=c++11 -c test-clapple.cxx
//     - FAILS, no type named 'unique_ptr' in namespace 'std'
// c++ -std=c++11 -stdlib=libc++ -c test-clapple.cxx
//     - OK
#include <ciso646>
#if (__cplusplus >= 201103L) || (_MSC_VER >= 1600)
# pragma message "C++11"
#elif (__cplusplus >= 199711L)
# pragma message "C++03"
#endif
#if (_LIBCPP_VERSION)
# pragma message "libc++"
#else
# pragma message "no libc++"
#endif
#if defined(__apple_build_version__)
# pragma message "Apple build"
#else
# pragma message "non-Apple build"
#endif
#if (__cplusplus >= 201103L) || (_MSC_VER >= 1600) // C++11
# include <memory>
#else
# include <tr1/memory>
#endif
// Manage auto_ptr warnings and deprecation in C++11
#if (__cplusplus >= 201103L) || (_MSC_VER >= 1600)
  template<typename T>
    using auto_ptr = std::unique_ptr<T>;
#else
  using std::auto_ptr;
#endif // C++11
int main(int argc, char* argv[])
{
    return argc;
}

此项目不使用Autotools、Cmake、Boost或其他外部库或框架。

-stdlib=libc++对预处理器的唯一影响是更改用于查找标准库头的包含路径,因此您无法在命令行上检测到-stdlib=libc++本身的存在,只能检测到包含了哪些标准库头。显然,如果不包含一个或多个标准库头,就无法检测到这一点。

如果包含任何libc++标头,则将定义_LIBCPP_VERSION,因此检测-stdlib=libc++的方法是至少包含一个C++库标头并检查_LIBCPP_VERSION

在C++20及更高版本中,建议使用专门为此目的创建的#include <version>。在C++20之前,建议使用#include <ciso646>,它在C++中没有任何作用,也没有声明任何内容,但对于libc++,它确实定义了_LIBCPP_VERSION宏。然而,对于libstdc++,历史上<ciso646>没有定义任何可用于检测libstdcC++的宏,如__GLIBCXX__。GCC 6.1改变了这一点,因此现在可以使用<ciso646>,但对于较旧的版本,您需要包含一个不同的标头来检测libstdc++。