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

时间:2015-07-27 15:44:25

标签: c++ clang llvm c-preprocessor libc++

我认为这是No type named 'unique_ptr' in namespace 'std' when compiling under LLVM/Clang问题的一部分。 According to Marshall Clow,我可以通过-stdlib=libc++检测_LIBCPP_VERSION

  

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

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

不幸的是,在从LLVM项目下载后,我使用Apple的Clang(3.4-SVN)和Clang(3.6)来解决这个问题。我猜这个测试只在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或其他外部库或框架。

1 个答案:

答案 0 :(得分:19)

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

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

对于libc ++,建议使用#include <ciso646>,它在C ++中没有任何用处并且什么都不声明,但是对于libc ++,确实定义了_LIBCPP_VERSION宏。但是,对于libstdc ++历史<ciso646>定义了可用于检测libstdc ++的任何宏,例如__GLIBCXX__。这改变了GCC 6.1所以现在可以使用<ciso646>,但是对于旧版本,你需要包含一个不同的头来检测libstdc ++。