Adding a new thread model to GCC
Hi all, The 'win32' thread model of gcc has been there since long long ago, being compatible with very old Windows versions, also having a number of drawbacks: 0) its implementation is very inefficient, and 1) its mutexes and condition variables require dynamic initialization and are unusable in C++11 as std::mutex requires a `constexpr` constructor, and 2) allocating a number of rarely used mutexes or condition variables would eventually make the system run out of kernel objects. As a solution for 1) and 2), Microsoft introduced keyed events, details of which can be found here: http://joeduffyblog.com/2006/11/28/windows-keyed-events-critical-sections-and-new-vista-synchronization-features/ In one word: the Windows SRWLOCK and CONDITION_VARIABLE have been introduced since Vista and are working well without any dynamic initialization, just like FUTEX. But there are still some major drawbacks: 0) the SRWLOCK can be used as an exclusive mutex but it does not have an equivalent function to pthread_mutex_timedwait, and 1) the CONDITION_VARIABLE can only be used with SRWLOCK and CRITICAL_SECTION and no user-defined mutexes can be supportd. As a solution, I come up with my own library: https://github.com/lhmouse/mcfgthread With 4 threads contending my mutex implementation turns to be 10 times faster than the gthr-win32 implementation on my Xeon E3-1230 v3 processor. I have also done some research on gthr.h and successfully created a wrapper for __gthread_* functhins, which can be found in mcfgthread/src/env/gthread.h. I am currently looking for ways to integrate this library into gcc as a new thread model, let's say 'nt6' for example, so GCC can be configured with --enable-threads=nt6. But there is so little documentation about that. If someone know how to add a new thread model in GCC, I would appreciate that. Also, this library has not been fully tested. If someone has interest in exploring how it works or testing it, I might be able to help. -- Best regards, lh_mouse 2016-04-13
Re: Re: Adding a new thread model to GCC
Thanks for your reply. :> However I am still having problems building GCC. (Yesterday stage 1 was ok, but during stage 2 autoconf just failed to find any standard headers. I am still struggling with it.) Once I build gcc successfully I will have a look at that configure.ac. Wish me luck. (btw this could be one or two days later. :<) -- Best regards, lh_mouse 2016-04-13 - 发件人:Jonathan Wakely 发送日期:2016-04-13 18:30 收件人:lh_mouse 抄送:gcc,mingw-w64-public 主题:Re: Adding a new thread model to GCC On 13 April 2016 at 10:17, lh_mouse wrote: > Hi all, > > The 'win32' thread model of gcc has been there since long long ago, being > compatible with very old Windows versions, also having a number of drawbacks: > 0) its implementation is very inefficient, and > 1) its mutexes and condition variables require dynamic initialization and > are unusable in C++11 as std::mutex requires a `constexpr` constructor, and > 2) allocating a number of rarely used mutexes or condition variables would > eventually make the system run out of kernel objects. > > As a solution for 1) and 2), Microsoft introduced keyed events, details of > which can be found here: > http://joeduffyblog.com/2006/11/28/windows-keyed-events-critical-sections-and-new-vista-synchronization-features/ > > In one word: the Windows SRWLOCK and CONDITION_VARIABLE have been introduced > since Vista and are working well without any dynamic initialization, just > like FUTEX. > But there are still some major drawbacks: > 0) the SRWLOCK can be used as an exclusive mutex but it does not have an > equivalent function to pthread_mutex_timedwait, and Some of our supported targets don't support pthread_mutex_timedwait either (at least Mac OS X and HP-UX) so we have code in libstdc++ to support mutexes but not timed mutexes. That might also work for your new model. > 1) the CONDITION_VARIABLE can only be used with SRWLOCK and > CRITICAL_SECTION and no user-defined mutexes can be supportd. That's OK, std::condition_variable only needs to work with std::mutex, and then std::condition_variable_any (which works with user-defined mutexes) only requires std::mutex and std::condition_variable. The code to use user-defined mutexes is portable C++11, so doesn't need any platform-specific code. > As a solution, I come up with my own library: > https://github.com/lhmouse/mcfgthread > With 4 threads contending my mutex implementation turns to be 10 times faster > than the gthr-win32 implementation on my Xeon E3-1230 v3 processor. > I have also done some research on gthr.h and successfully created a wrapper > for __gthread_* functhins, which can be found in mcfgthread/src/env/gthread.h. Great! I haven't looked at the code, but I've been hoping someone would do something like this to improve the std::mutex and std::condition_variable implementations for modern Windows systems. > I am currently looking for ways to integrate this library into gcc as a new > thread model, let's say 'nt6' for example, so GCC can be configured with > --enable-threads=nt6. > But there is so little documentation about that. If someone know how to add a > new thread model in GCC, I would appreciate that. See line 1589 in gcc/configure.ac, where the allowed thread models are defined. Your gthreads wrapper header should be added as libgcc/config/i386/gthr-nt6.h and you might also need some changes to libgcc/configure.ac (see how it handles the existing gthr-win32.h model). You will need to use autoconf to regenerate the configure files after editing the configure.ac files (or for now you can just edit the configure files by hand, but eventually changes must go into the configure.ac files). I can probably help with that, although I can't build or test anything on Windows. Once you've added the new thread model as a gthr-xxx.h file in libgcc there will also be some work needed in libstdc++ to detect and correctly use the new model (e.g. to detect that the timedwait functions are not supported, so that timed mutexes will be disabled). We might want to discuss that latter part on the libstdc++ list.
Re: Re: Adding a new thread model to GCC
Yes I learnt those *ByAddress* functions a few months ago and was shocked that Microsoft had plagiarized futex from Linux. As you have pointed out already, those APIs are only available on Windows 8 and later. If we need fuex semantics on Windows 7 and earlier, we must simulate it. However, since futexes and keyed events work differently, simulation of futexes using keyed events would: 0) require a lot of work, and 1) suffer from performance penalty just like if we simulate keyed events on Windows 2000. The major difference is that, the FUTEX_WAIT syscall is an atomic compare-and-sleep operation, while the NtWaitForKeyedEvent syscall provides no comparison. Instead, the NtReleasedKeyedEvent syscall blocks the current thread until one thread is woken up, while FUTEX_WAKE does nothing and returns immediately. So here is my condition: in no event shall portability harm either efficiency or maintainability. Linux and Windows work differently. I consider it 'harmful' to make one look like the other. -- Best regards, lh_mouse 2016-04-14 - 发件人:Torvald Riegel 发送日期:2016-04-14 01:40 收件人:lh_mouse 抄送:gcc,mingw-w64-public 主题:Re: Adding a new thread model to GCC On Wed, 2016-04-13 at 17:17 +0800, lh_mouse wrote: > Hi all, > > The 'win32' thread model of gcc has been there since long long ago, being > compatible with very old Windows versions, also having a number of drawbacks: > 0) its implementation is very inefficient, and > 1) its mutexes and condition variables require dynamic initialization and > are unusable in C++11 as std::mutex requires a `constexpr` constructor, and > 2) allocating a number of rarely used mutexes or condition variables would > eventually make the system run out of kernel objects. > > As a solution for 1) and 2), Microsoft introduced keyed events, details of > which can be found here: > http://joeduffyblog.com/2006/11/28/windows-keyed-events-critical-sections-and-new-vista-synchronization-features/ Have you looked at WaitOnAddress and WakeByAddressSingle / WakeByAddressAll too? AFAIK this is new in Windows 8, and seems similar to futexes. I think it might be better to get a std::synchronic (or similar) implementation into GCC, and then use these to implement at least the mutexes: https://github.com/ogiroux/synchronic/blob/master/include/synchronic One benefit would be that we then have one place where we have optimized spinning/blocking in libstdc++ on Windows, and less platform-specific code.
Re: Re: Re: Adding a new thread model to GCC
And don't forget that --enable-threads=win32 also enables emulated TLS, which is completely unnecessary if we have some kind of TLS support. Because pthread_key_create() requires a destructor, TLS must still be emulated on x86 because there is no native support. The fiber local storage (FLS) APIs require the god damned __stdcall calling convention and are impossible to be made any use of. On x64 __stdcall has no effect and FLS APIs can be used to implement TLS functions. I tend to make a copy of the POSIX thread model and make some modification of it. -- Best regards, lh_mouse 2016-04-14 - 发件人:Dongsheng Song 发送日期:2016-04-14 11:02 收件人:lh_mouse 抄送:Torvald Riegel,gcc,mingw-w64-public 主题:Re: Re: Adding a new thread model to GCC Currently, --enable-threads=win32 map to gthr-win32.{h|c}, could we map --enable-threads=win32-vista --enable-threads=win32-win7 // Windows 7 and Windows Server 2008 R2 --enable-threads=win32-win8 // Windows 8 and Windows Server 2012 --enable-threads=win32-win8.1 // Windows 8.1 and Windows Server 2012 R2 --enable-threads=win32-win10 // Windows 10 and Windows Server 2016 to gthr-windows.{h|c} with the corresponding _WIN32_WINNT macros ? Regards, Dongsheng On Thu, Apr 14, 2016 at 10:24 AM, lh_mouse wrote: > Yes I learnt those *ByAddress* functions a few months ago and was shocked > that Microsoft had plagiarized futex from Linux. > As you have pointed out already, those APIs are only available on Windows 8 > and later. > > If we need fuex semantics on Windows 7 and earlier, we must simulate it. > However, since futexes and keyed events work differently, simulation of > futexes using keyed events would: > 0) require a lot of work, and > 1) suffer from performance penalty just like if we simulate keyed events on > Windows 2000. > > The major difference is that, the FUTEX_WAIT syscall is an atomic > compare-and-sleep operation, while the NtWaitForKeyedEvent syscall provides > no comparison. > Instead, the NtReleasedKeyedEvent syscall blocks the current thread until one > thread is woken up, while FUTEX_WAKE does nothing and returns immediately. > > So here is my condition: in no event shall portability harm either efficiency > or maintainability. > Linux and Windows work differently. I consider it 'harmful' to make one look > like the other. > > > -- > Best regards, > lh_mouse > 2016-04-14 > > - > 发件人:Torvald Riegel > 发送日期:2016-04-14 01:40 > 收件人:lh_mouse > 抄送:gcc,mingw-w64-public > 主题:Re: Adding a new thread model to GCC > > On Wed, 2016-04-13 at 17:17 +0800, lh_mouse wrote: >> Hi all, >> >> The 'win32' thread model of gcc has been there since long long ago, being >> compatible with very old Windows versions, also having a number of drawbacks: >> 0) its implementation is very inefficient, and >> 1) its mutexes and condition variables require dynamic initialization and >> are unusable in C++11 as std::mutex requires a `constexpr` constructor, and >> 2) allocating a number of rarely used mutexes or condition variables would >> eventually make the system run out of kernel objects. >> >> As a solution for 1) and 2), Microsoft introduced keyed events, details of >> which can be found here: >> http://joeduffyblog.com/2006/11/28/windows-keyed-events-critical-sections-and-new-vista-synchronization-features/ > > Have you looked at WaitOnAddress and WakeByAddressSingle / > WakeByAddressAll too? AFAIK this is new in Windows 8, and seems similar > to futexes. > > I think it might be better to get a std::synchronic (or similar) > implementation into GCC, and then use these to implement at least the > mutexes: > https://github.com/ogiroux/synchronic/blob/master/include/synchronic > > One benefit would be that we then have one place where we have optimized > spinning/blocking in libstdc++ on Windows, and less platform-specific > code. > > >
Re: Re: Adding a new thread model to GCC
A glance over gthr.h reminds me __gthread_time_t. There seem few requirements documented in gthr.h. I discussed this with Adrien Nader on mingw-w64's mailing list a few days ago. Specifically, here are the two questions: 0) Should __gthread_time_t be a struct or a plain integral type? The 'struct timespec' used by pthread is a struct introduced in POSIX. However my implementation uses a plain uint64_t. 1) How to obtain a __gthread_time_t representing the current time? According to Linux man pages, the timeout parameter of pthread_cond_timedwait() is the same as gettimeofday() - that is, it uses the wall clock. My implementation uses GetTickCount64() - that is, my implementation uses a monotonic clock. Quoting from ISO/IEC WG21 Draft N4582 (C++1z): [quote] 30.4.1.3.1 Class timed_mutex [thread.timedmutex.class] ... template bool try_lock_for(const chrono::duration& rel_time); template bool try_lock_until(const chrono::time_point& abs_time); ... [/quote] the std::timed_mutex::try_lock_for() function template shall accept any clock type, hence we have to do timestamp translation. It is also important to know how libstdc++ handles this. -- Best regards, lh_mouse 2016-04-18
Re: Re: Adding a new thread model to GCC
I have added a thread model and added its corresponding header files. But it failed the linker. The file 'gcc/libgcc/config/i386/t-mingw-pthread' which contained two lines: SHLIB_PTHREAD_CFLAG = -pthread SHLIB_PTHREAD_LDFLAG = -Wl,-lpthread I copied the file to 'gcc/libgcc/config/i386/t-mingw-mcfgthread' and modified the two lines to: SHLIB_PTHREAD_CFLAG = -lmcfgthread SHLIB_PTHREAD_LDFLAG = -Wl,-lmcfgthread It didn't work and I got a number of undefined references. The command line that invoked the linker didn't include either option. How to solve this problem? -- Best regards, lh_mouse 2016-04-18 9000-Added-mcf-thread-model-support-from-mcfgthread.patch Description: Binary data
Re: Re: Re: Adding a new thread model to GCC
Oh I missed the build-in specs in gcc/config/i386/mingw32.h and it was lack of -lmcfgthread in it that caused the failure. Stage 1 seemed ok. Already hacked that. Rebuilding. Apologize for that. -- Best regards, lh_mouse 2016-04-18 - 发件人:Jonathan Wakely 发送日期:2016-04-18 16:59 收件人:lh_mouse 抄送:gcc,mingw-w64-public 主题:Re: Re: Adding a new thread model to GCC On 18 April 2016 at 08:39, lh_mouse wrote: > I have added a thread model and added its corresponding header files. But it > failed the linker. > > The file 'gcc/libgcc/config/i386/t-mingw-pthread' which contained two lines: > SHLIB_PTHREAD_CFLAG = -pthread > SHLIB_PTHREAD_LDFLAG = -Wl,-lpthread > > I copied the file to 'gcc/libgcc/config/i386/t-mingw-mcfgthread' and modified > the two lines to: > SHLIB_PTHREAD_CFLAG = -lmcfgthread > SHLIB_PTHREAD_LDFLAG = -Wl,-lmcfgthread > > It didn't work and I got a number of undefined references. The command line > that invoked the linker didn't include either option. > > How to solve this problem? What are the linker errors? When do they happen?
Re: Re: Re: Adding a new thread model to GCC
> I don't see why it has to be a struct, it just has to be suitable as > an argument to the relevant __gthread functions. The type __gthread_time_t is referenced in gcc/libstdc++-v3/include/std/mutex:157 __gthread_time_t __ts = { static_cast(__s.time_since_epoch().count()), static_cast(__ns.count()) }; This definition uses a braced-init-list that has two elements and is unsuitable for scalar types. > If the current code assumes a struct and the Windows API calls need an > integer then either the existing code needs to be made more flexible, > or you need to define it as a struct and then convert to an integer > inside your new gthread wrapper functions. The Windows APIs involved use LARGE_INTEGER - a union of a 64-bit integer and an array of two 32-bit integers - because some languages might have no native 64-bit integer types. Actually in C99 and C++11 we just assume there is long long and int64_t despite the fact that ISO C marks int64_t as optional, so it can be regarded as a union whose only element is an int64_t. > std::condition_variable::__clock_t must be a typedef for the clock > used by the underlying implementation, so it sounds like you should > use std::chrono::steady_clock for your thread model. > All conversions are done using the std::chrono facilities, before any > conversion to __gthread_time_t. That means the conversions are > portable. Thought so. I have to take a deep look. Thanks for your help! -- Best regards, lh_mouse 2016-04-18
Re: Re: Re: Adding a new thread model to GCC
>>> If the current code assumes a struct and the Windows API calls need an >>> integer then either the existing code needs to be made more flexible, >>> or you need to define it as a struct and then convert to an integer >>> inside your new gthread wrapper functions. >> >> The Windows APIs involved use LARGE_INTEGER - a union of a 64-bit integer >> and an array of two 32-bit integers - because some languages might have no >> native 64-bit integer types. >> Actually in C99 and C++11 we just assume there is long long and int64_t >> despite the fact that ISO C marks int64_t as optional, so it can be regarded >> as a union whose only element is an int64_t. >> > What are the units of the argument? Milliseconds? >From Windows SDK: File Times A file time is a 64-bit value that represents the number of 100-nanosecond intervals that have elapsed since 12:00 A.M. January 1, 1601 Coordinated Universal Time (UTC). This decision makes it much easier to count leap years, no? > You have two choices, either modify all the places in libstdc++ that > use __gthread_time_t, changing the code to use some new function > template that populates a __gthread_time_t from a > std::chrono::time_point or std::chrono::duration, or define > a similar struct in your gthreads header and convert it to int64_t > inside your functions. For functions taking a relative time the > conversion from a { seconds, nanoseconds } struct to milliseconds is > trivial, for functions taking an absolute time you need to know the > epoch of the clock that was used when populating the struct. Will do that next week. Still need to make gcc work with my library. -- Best regards, lh_mouse 2016-04-18
Re: Re: Re: Adding a new thread model to GCC
Thanks to ktietz, Elieux, mingwandroid (via IRC) and jwakely (via mail), the integration of mcfgthread and gcc has been accomplished. This 9000- patch applies to the gcc-5-branch after all other patches from https://github.com/Alexpux/MINGW-packages/tree/master/mingw-w64-gcc-git are applied. After applying the patches please run 'configure' with --enable-threads=mcf. The newly compiled i686 gcc has passed 3-stages bootstrap and seems working. I am going to start the x64 build very soon. Source code and pre-built binaries of the 'mcfgthread' library can be found here: https://github.com/lhmouse/mcfgthread/tree/master/release Problem reports and suggestions are welcome. :> Thanks for your help and interest! -- Best regards, lh_mouse 2016-04-19 9000-Added-mcf-thread-model-support-from-mcfgthread.patch Description: Binary data mcfgthread-release-i686-x86_64.7z Description: Binary data
Re: Re: Re: Adding a new thread model to GCC
One more question about block-scoped static objects: >From compiled assembly I have learned that GCC uses a 64-bit integer guard to >ensure once-initialization of static objects with block scopes. Code in gcc/libstdc++-v3/libsupc++/guard.cc uses a global mutex to protect multiple threads from racing, which, as described in that file, could potentially cause a deadlock that can be avoided if a condition variable is used. This, however, is unnecessary with mcfgthread. The mcfgthread library uses the once_flag itself as both the mutex and condition variable, eliminating the need of a global mutex and condition variable. Code using mcfgthread might look like this: [code] class foo { ... }; static ::_MCFCRT_OnceFlag flag; static alignas(foo) char obj[sizeof(foo)]; foo *get_obj(){ const auto construct_obj = []{ ::new(static_cast(obj)) foo(); }; const auto destruct_obj = []{ reinterpret_cast(obj)->~foo(); }; // Lock the once flag as if it were a mutex. const auto result = ::_MCFCRT_WaitForOnceFlagForever(&flag); // This never times out, so result can be either _MCFCRT_kOnceResultInitial or _MCFCRT_kOnceResultFinished. if(result == ::_MCFCRT_kOnceResultInitial){ try { // Construct the object in-place. construct_obj(); if(std::atexit(&destruct_obj) != 0){ // Assume we have run out of memory. destruct_obj(); throw std::bad_alloc(); } } catch(...){ // Unlock the once flag, allowing other threads to retry the initialization. // This works like pthread_cond_signal(). ::_MCFCRT_SignalOnceFlagAsAborted(&flag); throw; } // We are done here. Unlock the once flag and other threads will not be blocked any more. // This works like pthread_cond_broadcast(). _MCFCRT_SignalOnceFlagAsFinished(&flag); } return reinterpret_cast(obj); } [/code] Now here is my question: That '__cxxabiv1::__guard' thing seems built-in of GCC. Does it have anything to do with code generation? And where is it involved? -- Best regards, lh_mouse 2016-04-20
Re: Why does gcc generate const local array on stack?
I tend to say clang is wrong here. Quoting the standard: ISO/IEC WG14 Draft N1570 (Programming languages — C): [quote] 6.2.2 Linkages of identifiers 6 The following identifiers have no linkage: an identifier declared to be anything other than an object or a function; an identifier declared to be a function parameter; a block scope identifier for an object declared without the storage-class specifier extern. 6.2.4 Storage durations of objects 6 An object whose identifier is declared with no linkage and without the storage-class specifier static has automatic storage duration, as do some compound literals. ... 7 For such an object that does have a variable length array type, its lifetime extends from the declaration of the object until execution of the program leaves the scope of the declaration.35) If the scope is entered recursively, a new instance of the object is created each time. The initial value of the object is indeterminate. [/quote] Your identifier 'a' has no linkage. Your object designated by 'a' does not have a storage-class specifier. So it has automatic storage duration and 6.2.4/7 applies: 'If the scope is entered recursively, a new instance of the object is created each time.' Interesting enough, ISO C doesn't say whether distinct objects should have distinct addresses. It is worth noting that this is explicitly forbidden in ISO C++ because distinct complete objects shall have distinct addresses: ISO/IEC WG21 N4582 (Working Draft, Standard for Programming Language C++) : [quote] 1.9 Program execution [intro.execution] 7 An instance of each object with automatic storage duration (3.7.3) is associated with each entry into its block. Such an object exists and retains its last-stored value during the execution of the block and while the block is suspended (by a call of a function or receipt of a signal). 1.8 The C++ object model [intro.object] 6 Unless an object is a bit-field or a base class subobject of zero size, the address of that object is the address of the first byte it occupies. Two objects that are not bit-fields may have the same address if one is a subobject of the other, or if at least one is a base class subobject of zero size and they are of different types; otherwise, they shall have distinct addresses.4 [/quote] -- Best regards, lh_mouse 2016-04-20 - 发件人:Bingfeng Mei 发送日期:2016-04-20 23:38 收件人:gcc 抄送: 主题:Why does gcc generate const local array on stack? Hi, I came across the following issue. int foo (int N) { const int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; return a[N]; } Compile with x86 O2 foo: .LFB0: .cfi_startproc movslq %edi, %rdi movl $0, -56(%rsp) movl $1, -52(%rsp) movl $2, -48(%rsp) movl $3, -44(%rsp) movl $4, -40(%rsp) movl $5, -36(%rsp) movl $6, -32(%rsp) movl $7, -28(%rsp) movl $8, -24(%rsp) movl $9, -20(%rsp) movl -56(%rsp,%rdi,4), %eax ret The array is placed on stack and GCC has to generate a sequence of instructions to initialize the array every time the function is called. On the contrary, LLVM moves the array to global data and doesn't need initialization within the function. If I add static to the array, GCC behaves the same as LLVM, just as expected. Is there some subtle C standard issue or some switch I didn't turned on? I understand if this function is recursive and pointer of the array is involved, GCC would have to maintain the array on stack and hence the initialization. But here the code is very simple. I don't understand the logic of generated code, or maybe missing optimization opportunity? Thanks, Bingfeng Mei
Re: Re: Why does gcc generate const local array on stack?
See this example: http://coliru.stacked-crooked.com/a/048b4aa5046da11b In this example the function is called recursively. During each call a pointer to that local areay is appended to a static array of pointers. Should a new instance of that local array of const int be created every time, abort() will never be called. Since calling a library function is observable behavior, clang's optimization has effectively changed that program's behavior. Hence I think it is wrong. [code] #include static const int *ptrs[2]; static unsigned recur; void foo(){ const int a[] = {0,1,2,3,4,5,6,7,8,9}; ptrs[recur] = a; if(recur == 0){ ++recur; foo(); } if(ptrs[0] == ptrs[1]){ abort(); } } int main(){ foo(); } [/code] -- Best regards, lh_mouse 2016-04-21 - 发件人:Jonathan Wakely 发送日期:2016-04-21 01:51 收件人:lh_mouse 抄送:Bingfeng Mei,gcc 主题:Re: Why does gcc generate const local array on stack? On 20 April 2016 at 18:31, lh_mouse wrote: > I tend to say clang is wrong here. If you can't detect the difference then it is a valid transformation. > Your identifier 'a' has no linkage. Your object designated by 'a' does not > have a storage-class specifier. > So it has automatic storage duration and 6.2.4/7 applies: 'If the scope is > entered recursively, a new instance of the object is created each time.' How do you tell the difference between a const array that is recreated each time and one that isn't? > Interesting enough, ISO C doesn't say whether distinct objects should have > distinct addresses. > It is worth noting that this is explicitly forbidden in ISO C++ because > distinct complete objects shall have distinct addresses: If the object's address doesn't escape from the function then I can't think of a way to tell the difference.
GCC 6.1 Hard-coded C++ header paths and relocation problem on Windows
This is a cross-post from gcc-help as there haven't been any replies on gcc-help since two days ago. Hope someone could help. ``` I have built GCC from gcc-6-branch in MSYS2 with mingw-w64 CRT on Windows today. Now I have a relocation problem: Assuming mingw-w64 headers are located in the follow directory,which is, the native_system_header_dir: > C:/MinGW/MSYS2/mingw32/lib/gcc/i686-w64-mingw32/6.1.1/include I have built GCC and it has that hard-coded path. When I compile something using g++ -v, the headers are searched in the following paths: ``` ignoring nonexistent directory "/mingw32/include" ignoring duplicate directory "C:/MinGW/MSYS2/mingw32/i686-w64-mingw32/include" #include "..." search starts here: #include <...> search starts here: C:/MinGW/MSYS2/mingw32/include/c++/6.1.1 C:/MinGW/MSYS2/mingw32/include/c++/6.1.1/i686-w64-mingw32 C:/MinGW/MSYS2/mingw32/include/c++/6.1.1/backward C:/MinGW/MSYS2/mingw32/lib/gcc/i686-w64-mingw32/6.1.1/include C:/MinGW/MSYS2/mingw32/lib/gcc/i686-w64-mingw32/6.1.1/../../../../include C:/MinGW/MSYS2/mingw32/lib/gcc/i686-w64-mingw32/6.1.1/include-fixed C:/MinGW/MSYS2/mingw32/lib/gcc/i686-w64-mingw32/6.1.1/../../../../i686-w64-mingw32/include End of search list. ``` The C++ headers are searched before any mingw-w64 headers, which is just fine. However, if I move gcc to another directory, let's say, C:/this_is_a_new_directory/mingw32/, then re-compile the same program with g++ -v, the headers are searched in the following paths: ``` ignoring duplicate directory "C:/this_is_a_new_directory/mingw32/lib/gcc/../../lib/gcc/i686-w64-mingw32/6.1.1/include" ignoring nonexistent directory "C:/MinGW/MSYS2/mingw32/include" ignoring nonexistent directory "/mingw32/include" ignoring duplicate directory "C:/this_is_a_new_directory/mingw32/lib/gcc/../../lib/gcc/i686-w64-mingw32/6.1.1/include-fixed" ignoring duplicate directory "C:/this_is_a_new_directory/mingw32/lib/gcc/../../lib/gcc/i686-w64-mingw32/6.1.1/../../../../i686-w64-mingw32/include" ignoring nonexistent directory "C:/MinGW/MSYS2/mingw32/i686-w64-mingw32/include" #include "..." search starts here: #include <...> search starts here: C:/this_is_a_new_directory/mingw32/bin/../lib/gcc/i686-w64-mingw32/6.1.1/include C:/this_is_a_new_directory/mingw32/bin/../lib/gcc/i686-w64-mingw32/6.1.1/../../../../include C:/this_is_a_new_directory/mingw32/bin/../lib/gcc/i686-w64-mingw32/6.1.1/include-fixed C:/this_is_a_new_directory/mingw32/bin/../lib/gcc/i686-w64-mingw32/6.1.1/../../../../i686-w64-mingw32/include C:/this_is_a_new_directory/mingw32/lib/gcc/../../include/c++/6.1.1 C:/this_is_a_new_directory/mingw32/lib/gcc/../../include/c++/6.1.1/i686-w64-mingw32 C:/this_is_a_new_directory/mingw32/lib/gcc/../../include/c++/6.1.1/backward End of search list. ``` This time the C++ headers are searched after mingw-w64 headers, which causes the following error: ``` In file included from C:/MinGW/mingw32/include/c++/6.1.1/ext/string_conversions.h:41:0, from C:/MinGW/mingw32/include/c++/6.1.1/bits/basic_string.h:5402, from C:/MinGW/mingw32/include/c++/6.1.1/string:52, from C:/MinGW/mingw32/include/c++/6.1.1/bits/locale_classes.h:40, from C:/MinGW/mingw32/include/c++/6.1.1/bits/ios_base.h:41, from C:/MinGW/mingw32/include/c++/6.1.1/ios:42, from C:/MinGW/mingw32/include/c++/6.1.1/ostream:38, from C:/MinGW/mingw32/include/c++/6.1.1/iostream:39, from test.cpp:1: C:/MinGW/mingw32/include/c++/6.1.1/cstdlib:75:25: fatal error: stdlib.h: No such file or directory #include_next ^ compilation terminated. ``` Do you know how to solve this problem (modifications to gcc source code are expected)? Thanks in advance. -- Best regards, lh_mouse 2016-05-02
Re: GCC 6.1 Hard-coded C++ header paths and relocation problem on Windows
I made some investigation yesterday and here is the result: ``` Diff'ing gcc/libstdc++-v3/include/c_global/cstdlib from gcc-5-branch and gcc-6-branch gives the following result: (git diff gcc-5-branch gcc-6-branch -- libstdc++-v3/include/c_global/cstdlib) ``` @@ -69,7 +69,11 @@ namespace std #else -#include +// Need to ensure this finds the C library's not a libstdc++ +// wrapper that might already be installed later in the include search path. +#define _GLIBCXX_INCLUDE_NEXT_C_HEADERS +#include_next +#undef _GLIBCXX_INCLUDE_NEXT_C_HEADERS // Get rid of those macros defined in in lieu of real functions. #undef abort ``` Replacing #include_next with #include fixes the problem. However, I am not exactly clear about whether it is these headers (cstdlib and cmath currently, there might be more) that are the problem. In my point of view, it is the inversion of C and C++ header paths that is the problem. -- Best regards, lh_mouse 2016-05-02
Re: Re: GCC 6.1 Hard-coded C++ header paths and relocation problem on Windows
Should I file a bug report then? We need some Linux testers, though not many people on Linux relocate compilers. -- Best regards, lh_mouse 2016-05-03 - 发件人:Jonathan Wakely 发送日期:2016-05-03 17:00 收件人:lh_mouse 抄送:gcc 主题:Re: GCC 6.1 Hard-coded C++ header paths and relocation problem on Windows On 2 May 2016 at 11:41, lh_mouse wrote: > However, I am not exactly clear about whether it is these headers (cstdlib > and cmath currently, there might be more) that are the problem. No, it's only those two. > In my point of view, it is the inversion of C and C++ header paths that is > the problem. Agree. I don't know why that happens though.