Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -629,6 +629,17 @@ config_define(${abi_defines} _LIBCPP_ABI_DEFINES) endif() +# The Windows headers are split between Visual Studio and the Windows SDK's +# universal CRT. Allow clients to specify both. +if (LIBCXX_INCLUDE_NEXT_VC) + # Example for MSVC 2017: -D LIBCXX_INCLUDE_NEXT_VC=../../../MSVC/14.10.25017/include + config_define(${LIBCXX_INCLUDE_NEXT_VC} _LIBCPP_INCLUDE_NEXT_VC) +endif() +if (LIBCXX_INCLUDE_NEXT_UCRT) + # Example for Windows 10 SDK: -D LIBCXX_INCLUDE_NEXT_UCRT=../ucrt + config_define(${LIBCXX_INCLUDE_NEXT_UCRT} _LIBCPP_INCLUDE_NEXT_UCRT) +endif() + # By default libc++ on Windows expects to use a shared library, which requires # the headers to use DLL import/export semantics. However when building a # static library only we modify the headers to disable DLL import/export. Index: docs/DesignDocs/IncludeNextEmulation.rst =================================================================== --- /dev/null +++ docs/DesignDocs/IncludeNextEmulation.rst @@ -0,0 +1,89 @@ +======================= +Emulating #include_next +======================= +Why #include_next at all? +------------------------- +Libc++ does not come with a C library. It is intended to work with many different C libraries. The C++ standard also requires the wrappers around the C library headers [headers] and compatibility wrappers for the headers [depr.c.headers]. + +The straightforward way to implement these wrappers is to have the C++ headers use the preprocessor extension #include_next in order to get access to the C version of the headers. For example, the C++ and will need something like #include_next in order to get the C version of math.h, rather than recursively include the C++ math.h. + +Why emulate #include_next? +-------------------------- +#include_next isn't part of the C++ standard. It is a compiler extension that both GCC and Clang implement. Notably, Microsoft Visual Studio 2017 and earlier don't implement it (Visual Studio 2017 is the most current version as of the writing of this document). Libc++ still needs access to the underlying C libraries though. + +How does one emulate #include_next? +----------------------------------- +Emulating #include_next requires extra knowledge about the file system layout of your headers. Suppose you're file system was laid out this way... + +:: + + / + libcxx/ + include/ + math.h + cmath + vc/ + include/ + math.h + +We could then reach the vc/include/math.h include using a relative path include. + +:: + + #include <../../vc/include/math.h> + +The "vc/include" portion of the #include makes it impossible to pull in the math.h from libcxx/include. + +This has the obvious disadvantage of hard-coding C-library paths into multiple source code locations. This can be solved by relying on implementation defined behavior of the preprocessor (C11, 6.10.2.4 ["Source file inclusion"]). We will use what is referred to as a "computed include". + +:: + + #define _MY_INCLUDE_NEXT(header) <../../vc/include/header> + #include _MY_INCLUDE_NEXT(math.h) + +Libc++ goes an extra step with the computed includes. __config_site.in allows those building libc++ to specify the relative path on the command line. + +:: + + #cmakedefine _MY_INCLUDE_NEXT(header) <@_MY_INCLUDE_NEXT@/header> + +This works reasonably well for most headers. is trouble though. If the order of #includes is just right, then the token 'errno' will already be defined as a macro before we get to the #include _MY_INCLUDE_NEXT(errno.h) line. In a normal #include or #include "errno.h", the 'errno' macro isn't expanded. But in #include _MY_INCLUDE_NEXT(errno.h), the 'errno' macro will be expanded. For this situation, we undef errno inside a #pragma push_macro / pop_macro block, and hope that we didn't overwrite a 'better' errno definition. + +What is the right relative path for my version of Microsoft Visual Studio? +-------------------------------------------------------------------------- +That depends on the header, and on the version of Microsoft Visual Studio. +My Visual Studio 2017 installation places most of the C headers in the "universal CRT": + +:: + + C:\Program Files (x86)\Windows Kits\10\Include\10.0.14393.0\ucrt + +A few of the C headers (stdbool.h, limits.h, stdint.h, and setjmp.h) are found here though: + +:: + + C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.10.25017\include + +In Visual Studio 2015, most of the C headers could still be found in the universal crt, but the remainders are here: + +:: + + C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include + +The universal crt was introduced in Microsoft Visual Studio 2015. Prior to that, most of C headers could be found in the corresponding installation's VC\include directory. + +Over the past three major versions of Microsoft Visual Studio, the locations for headers have changed three times. Given that the path in Microsoft Visual Studio 2017 has a very specific version in the path (14.10.25017), it is reasonable to assume that the required relative path will change along with patches and updates. + +Since the C headers in Microsoft Visual Studio 2017 aren't all located in one place, the Libc++ implementation uses multiple macros and multiple relative paths to find the right headers. I have had some success with these paths: + +:: + + LIBCXX_INCLUDE_NEXT_VC=../../../MSVC/14.10.25017/include \ + LIBCXX_INCLUDE_NEXT_UCRT=../ucrt \ + + +How does Libc++ emulate #include_next? +-------------------------------------- +Each use of #include_next is guarded with a check of _LIBCPP_HAS_NO_INCLUDE_NEXT. When include_next isn't present, we use the emulation macros instead, and either #include _LIBCPP_INCLUDE_NEXT_UCRT(name.h) or #include _LIBCPP_INCLUDE_NEXT_VC(name.h). + +If the Microsoft Visual Studio headers change location again, in a way that doesn't put them all in the same location (e.g. all under ucrt), then more emulation macros will need to be added, possibly one macro per header. Index: include/__config =================================================================== --- include/__config +++ include/__config @@ -1157,6 +1157,10 @@ # define _LIBCPP_HAS_NO_COROUTINES #endif +#if defined(_LIBCPP_COMPILER_MSVC) +# define _LIBCPP_HAS_NO_INCLUDE_NEXT +#endif + // Decide whether to use availability macros. #if !defined(_LIBCPP_BUILDING_LIBRARY) && \ !defined(_LIBCPP_DISABLE_AVAILABILITY) && \ Index: include/__config_site.in =================================================================== --- include/__config_site.in +++ include/__config_site.in @@ -25,6 +25,8 @@ #cmakedefine _LIBCPP_HAS_THREAD_API_EXTERNAL #cmakedefine _LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL #cmakedefine _LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS +#cmakedefine _LIBCPP_INCLUDE_NEXT_VC(header) <@_LIBCPP_INCLUDE_NEXT_VC@/header> +#cmakedefine _LIBCPP_INCLUDE_NEXT_UCRT(header) <@_LIBCPP_INCLUDE_NEXT_UCRT@/header> #cmakedefine _LIBCPP_NO_VCRUNTIME @_LIBCPP_ABI_DEFINES@ Index: include/complex.h =================================================================== --- include/complex.h +++ include/complex.h @@ -30,7 +30,11 @@ #else // __cplusplus +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) +#include _LIBCPP_INCLUDE_NEXT_UCRT(complex.h) +#else #include_next +#endif #endif // __cplusplus Index: include/cstddef =================================================================== --- include/cstddef +++ include/cstddef @@ -41,7 +41,11 @@ #endif // Don't include our own ; we don't want to declare ::nullptr_t. +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) +#include _LIBCPP_INCLUDE_NEXT_UCRT(stddef.h) +#else #include_next +#endif #include <__nullptr> _LIBCPP_BEGIN_NAMESPACE_STD Index: include/ctype.h =================================================================== --- include/ctype.h +++ include/ctype.h @@ -36,7 +36,11 @@ #pragma GCC system_header #endif +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) +#include _LIBCPP_INCLUDE_NEXT_UCRT(ctype.h) +#else #include_next +#endif #ifdef __cplusplus Index: include/errno.h =================================================================== --- include/errno.h +++ include/errno.h @@ -29,7 +29,18 @@ #pragma GCC system_header #endif +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) + #ifdef errno + #pragma push_macro("errno") + #undef errno + #include _LIBCPP_INCLUDE_NEXT_UCRT(errno.h) + #pragma pop_macro("errno") + #else + #include _LIBCPP_INCLUDE_NEXT_UCRT(errno.h) + #endif +#else #include_next +#endif #ifdef __cplusplus Index: include/float.h =================================================================== --- include/float.h +++ include/float.h @@ -66,7 +66,11 @@ #pragma GCC system_header #endif +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) +#include _LIBCPP_INCLUDE_NEXT_UCRT(float.h) +#else #include_next +#endif #ifdef __cplusplus Index: include/inttypes.h =================================================================== --- include/inttypes.h +++ include/inttypes.h @@ -244,7 +244,11 @@ # define __STDC_FORMAT_MACROS #endif +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) +#include _LIBCPP_INCLUDE_NEXT_UCRT(inttypes.h) +#else #include_next +#endif #ifdef __cplusplus Index: include/limits.h =================================================================== --- include/limits.h +++ include/limits.h @@ -45,7 +45,11 @@ #endif #ifndef __GNUC__ +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) +#include _LIBCPP_INCLUDE_NEXT_VC(limits.h) +#else #include_next +#endif #else // GCC header limits.h recursively includes itself through another header called // syslimits.h for some reason. This setup breaks down if we directly Index: include/locale.h =================================================================== --- include/locale.h +++ include/locale.h @@ -40,6 +40,10 @@ #pragma GCC system_header #endif +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) +#include _LIBCPP_INCLUDE_NEXT_UCRT(locale.h) +#else #include_next +#endif #endif // _LIBCPP_LOCALE_H Index: include/math.h =================================================================== --- include/math.h +++ include/math.h @@ -298,7 +298,11 @@ #pragma GCC system_header #endif +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) +#include _LIBCPP_INCLUDE_NEXT_UCRT(math.h) +#else #include_next +#endif #ifdef __cplusplus Index: include/setjmp.h =================================================================== --- include/setjmp.h +++ include/setjmp.h @@ -32,7 +32,11 @@ #pragma GCC system_header #endif +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) +#include _LIBCPP_INCLUDE_NEXT_VC(setjmp.h) +#else #include_next +#endif #ifdef __cplusplus Index: include/stdbool.h =================================================================== --- include/stdbool.h +++ include/stdbool.h @@ -26,7 +26,11 @@ #pragma GCC system_header #endif +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) +#include _LIBCPP_INCLUDE_NEXT_VC(stdbool.h) +#else #include_next +#endif #ifdef __cplusplus #undef bool Index: include/stddef.h =================================================================== --- include/stddef.h +++ include/stddef.h @@ -15,7 +15,11 @@ #pragma GCC system_header #endif +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) +#include _LIBCPP_INCLUDE_NEXT_UCRT(stddef.h) +#else #include_next +#endif #elif !defined(_LIBCPP_STDDEF_H) #define _LIBCPP_STDDEF_H @@ -43,7 +47,11 @@ #pragma GCC system_header #endif +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) +#include _LIBCPP_INCLUDE_NEXT_UCRT(stddef.h) +#else #include_next +#endif #ifdef __cplusplus Index: include/stdint.h =================================================================== --- include/stdint.h +++ include/stdint.h @@ -116,6 +116,10 @@ # define __STDC_CONSTANT_MACROS #endif +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) +#include _LIBCPP_INCLUDE_NEXT_VC(stdint.h) +#else #include_next +#endif #endif // _LIBCPP_STDINT_H Index: include/stdio.h =================================================================== --- include/stdio.h +++ include/stdio.h @@ -14,7 +14,11 @@ #pragma GCC system_header #endif +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) +#include _LIBCPP_INCLUDE_NEXT_UCRT(stdio.h) +#else #include_next +#endif #elif !defined(_LIBCPP_STDIO_H) #define _LIBCPP_STDIO_H @@ -105,7 +109,11 @@ #pragma GCC system_header #endif +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) +#include _LIBCPP_INCLUDE_NEXT_UCRT(stdio.h) +#else #include_next +#endif #ifdef __cplusplus Index: include/stdlib.h =================================================================== --- include/stdlib.h +++ include/stdlib.h @@ -14,7 +14,11 @@ #pragma GCC system_header #endif +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) +#include _LIBCPP_INCLUDE_NEXT_UCRT(stdlib.h) +#else #include_next +#endif #elif !defined(_LIBCPP_STDLIB_H) #define _LIBCPP_STDLIB_H @@ -91,7 +95,11 @@ #pragma GCC system_header #endif +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) +#include _LIBCPP_INCLUDE_NEXT_UCRT(stdlib.h) +#else #include_next +#endif #ifdef __cplusplus Index: include/string.h =================================================================== --- include/string.h +++ include/string.h @@ -58,7 +58,11 @@ #pragma GCC system_header #endif +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) +#include _LIBCPP_INCLUDE_NEXT_UCRT(string.h) +#else #include_next +#endif // MSVCRT, GNU libc and its derivates may already have the correct prototype in // . This macro can be defined by users if their C library provides Index: include/wchar.h =================================================================== --- include/wchar.h +++ include/wchar.h @@ -14,7 +14,11 @@ #pragma GCC system_header #endif +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) +#include _LIBCPP_INCLUDE_NEXT_UCRT(wchar.h) +#else #include_next +#endif #elif !defined(_LIBCPP_WCHAR_H) #define _LIBCPP_WCHAR_H @@ -116,7 +120,11 @@ #define __CORRECT_ISO_CPP_WCHAR_H_PROTO #endif +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) +#include _LIBCPP_INCLUDE_NEXT_UCRT(wchar.h) +#else #include_next +#endif // Determine whether we have const-correct overloads for wcschr and friends. #if defined(_WCHAR_H_CPLUSPLUS_98_CONFORMANCE_) Index: include/wctype.h =================================================================== --- include/wctype.h +++ include/wctype.h @@ -51,7 +51,11 @@ #pragma GCC system_header #endif +#if defined(_LIBCPP_HAS_NO_INCLUDE_NEXT) +#include _LIBCPP_INCLUDE_NEXT_UCRT(wctype.h) +#else #include_next +#endif #ifdef __cplusplus Index: utils/libcxx/test/config.py =================================================================== --- utils/libcxx/test/config.py +++ utils/libcxx/test/config.py @@ -670,6 +670,8 @@ self.cxx.compile_flags += [define] if m == '_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS': continue + if m.startswith('_LIBCPP_INCLUDE_NEXT'): + continue if m == '_LIBCPP_ABI_VERSION': self.config.available_features.add('libcpp-abi-version-v%s' % feature_macros[m])