Как определить -stdlib=libC++ в препроцессоре?
Я думаю, что это является частью проблемы в No type с именем "unique_ptr" в пространстве имен "std" при компиляции в LLVM / Clang. По словам Маршалла Клоу, я могу обнаружить -stdlib=libc++
с помощью _LIBCPP_VERSION
:
Если вы пишете кроссплатформенный код, иногда вам нужно знать, какую стандартную библиотеку вы используете. Теоретически, все они должны предлагать эквивалентную функциональность, но это только теория. Иногда вам просто нужно знать. Лучший способ проверить наличие libC++ - это найти символ препроцессора _LIBCPP_VERSION. Если это определено, то вы используете libC++.
#ifdef _LIBCPP_VERSION // libc++ specific code here #else // generic code here #endif
К сожалению, это ломается с Apple Clang (3.4-SVN) и Clang (3.6), которые я собрал из источников после загрузки из проекта LLVM. Я предполагаю, что тест действителен только под 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 ответ
Единственный эффект -stdlib=libc++
на препроцессоре нужно изменить пути включения, которые он использует для поиска заголовков стандартной библиотеки, чтобы вы не могли обнаружить присутствие -stdlib=libc++
в командной строке per se вы можете только определить, какие заголовки стандартной библиотеки включены. Очевидно, что вы не можете обнаружить это без фактического включения одного или нескольких стандартных библиотечных заголовков.
Если вы включите любой заголовок libC++, то _LIBCPP_VERSION
будет определен, поэтому способ обнаружения -stdlib=libc++
должен включать как минимум один заголовок библиотеки C++ и проверять наличие _LIBCPP_VERSION
,
Для libC++ рекомендуется #include <ciso646>
который не имеет смысла в C++ и ничего не объявляет, но для libC++ определяет _LIBCPP_VERSION
макро. Однако для libstdC++ исторически <ciso646>
не определил никаких макросов, таких как __GLIBCXX__
это может быть использовано для обнаружения libstdC++. Что изменилось с GCC 6.1, так <ciso646>
можно использовать сейчас, но для более старых выпусков вам нужно включить другой заголовок для обнаружения libstdC++.