boostorg / thread

Boost.org thread module
http://boost.org/libs/thread
200 stars 161 forks source link

mingw-w64: wants to use libpthreadGC2.a, why not libpthread.a? #156

Closed hanetzer closed 6 years ago

hanetzer commented 6 years ago

As above. The mingw-w64 runtime can produce a set of pthread dlls and import libraries (usr/bin/libwinpthread-1.dll, usr/lib/libpthread.a, usr/lib/libpthread.dll.a, usr/lib/libwinpthread.a, and usr/lib/libwinpthread.dll.a) which can be used just like the linux ones, whereas I have no idea where libpthreadGC2.a even comes from.

viboes commented 6 years ago

I suspect that this is not a Boost.Thread issue ;-) it is about pthread library.

hanetzer commented 6 years ago

@viboes I don't know, but the library 'libpthreadGC2.a' is hardcoded in at least one place in the boost distro tarball, being tools/build/src/engine/boehm_gc/threadlibs.c around line 48 or so.

hanetzer commented 6 years ago

@viboes seriously? This is a buildfile issue on your guys's end, you hardcode the check for libpthreadGC2.a in https://github.com/boostorg/thread/blob/develop/build/Jamfile.v2#L214 This is NOT invalid.

viboes commented 6 years ago

Sorry, you message was not clear enough.

Please, create a bug issue for Boost.Build. Boost.Thread has nothing to do how Boost?Build links with external libraries :(

hanetzer commented 6 years ago

@viboes well can you point me at the proper location to file said bug? boostorg/build? or on that svn/trac thing I've found boost bugs on?

viboes commented 6 years ago

I believe Boost.Build accepts issues on github

https://github.com/boostorg/build/issues/

viboes commented 6 years ago

I've take a look at the Jamfile and I see something that can be related

         if <toolset>gcc in $(properties)
         {
             libname = lib$(libname)GC2.a ;
         }

I'm not sure how cross-compiling should work on Boost.Thread. Any help welcome.

what command are you using?

viboes commented 6 years ago

Is this related https://sourceware.org/ml/pthreads-win32/2011/msg00027.html?

viboes commented 6 years ago

Would https://github.com/boostorg/thread/pull/160 help?

karzhenkov commented 6 years ago

@hanetzer did you try to compile Boost.Thread using threadapi=win32 on the command line?

hanetzer commented 6 years ago

@karzhenkov yes, it will compile with threadapi=win32, but ideally I should be able to take advantage of mingw-w64's pthread libraries.

viboes commented 6 years ago

Could you tell me which command do you use and what are the values of in your configuration?

With witch library would you like to link and how would you like to tell it to Boost.Thread?

karzhenkov commented 6 years ago

@viboes the problem is not about cross-compiling. With mingw-w64 on Windows (when it is both a host and a target) result is the same. The only difference is default threadapi, but this is the issue #160.

The line containing "...GC2.a" in Jamfile exists since 2007. I guess that the mingw has changed significantly in the meantime. The "mingw-w64" and original "mingw" are related but different projects. The original "mingw" has almost no activity since 2013.

hanetzer commented 6 years ago

@karzhenkov exactly. The libpthreadGC2 library is from an external project which according to some folks on irc.oftc.net/#mingw-w64 is only capable of 32-bit operation, and minw-w64's runtime provides its own pthread library, which is usually installed by default for most distro's mingw packages (which are more often than not is mingw-w64, and not the original, legacy mingw).

viboes commented 6 years ago

Could one of you provide a patch for mingw-w64?

viboes commented 6 years ago

Hi, I received the following at 03:06 but it seems it was removed.

@viboes

compile command line: b2 --user-config=/tmp/portage/dev-libs/boost-1.65.0-r1/work/boost_1_65_0-abi_x86_32.x86/user-config.jam gentoorelease -j16 -q -d+2 -sICU_PATH=/usr --without-mpi --without-context --without-coroutine --without-fiber pch=off --boost-build=/usr/share/boost-build --prefix=/tmp/portage/dev-libs/boost-1.65.0-r1/image/usr --layout=system threading=multi link=shared -sNO_BZIP2=1 target-os=windows --without-python

user-config.jam: using gcc : 6.4 : i686-w64-mingw32-g++ : "-O2 -pipe -fomit-frame-pointer" "-O2 -pipe -fomit-frame-pointer -std=c++14" "-Wl,-O1 -Wl,--as-needed" ;

build.log: https://bpaste.net/show/0f4ad2771c83

if you need any other info, please let me know.

viboes commented 6 years ago

Could you try --without-log and report the build.log?

hanetzer commented 6 years ago

@viboes actually that was a different command line, I was mistaken on it.

viboes commented 6 years ago

Ok. I propose to remove this comment and the preceding 3.

viboes commented 6 years ago

A PR fixing this issue is welcome.

hanetzer commented 6 years ago

@viboes I personally have nothing in the way of skills in this area. I would gladly fix it myself, but it is beyond me atm. I'm just a consumer of the library and not a direct developer using it. I just know that there is a more 'native' mingw-w64 pthreads library which is already there, and does not require an external, unmaintained package.

Kojoley commented 6 years ago

@hanetzer you can start by commenting out this line https://github.com/boostorg/thread/blob/e848363029b0267c8b1de98b64026f7ab044680d/build/Jamfile.v2#L270 and solving this compile errors

Click for an output log ``` $ ../../../b2 toolset=gcc threadapi=pthread test_thread -d2 Performing configuration checks - default address-model : 64-bit (cached) - default architecture : x86 (cached) - symlinks supported : yes (cached) ************************************************************ Trying to build Boost.Thread with pthread support. If you need pthread you should specify the paths. You can specify them in site-config.jam, user-config.jam or in the environment. For example: PTW32_INCLUDE=C:\Program Files\ptw32\Pre-built2\include PTW32_LIB=C:\Program Files\ptw32\Pre-built2\lib ************************************************************ - lockfree boost::atomic_flag : yes (cached) ...patience... ...patience... ...found 3467 targets... ...updating 23 targets... common.mkdir ..\..\..\bin.v2\libs\thread if not exist "..\..\..\bin.v2\libs\thread\\" mkdir "..\..\..\bin.v2\libs\thread" common.mkdir ..\..\..\bin.v2\libs\thread\test if not exist "..\..\..\bin.v2\libs\thread\test\\" mkdir "..\..\..\bin.v2\libs\thread\test" common.mkdir ..\..\..\bin.v2\libs\thread\test\test_thread.test if not exist "..\..\..\bin.v2\libs\thread\test\test_thread.test\\" mkdir "..\..\..\bin.v2\libs\thread\test\test_thread.test" common.mkdir ..\..\..\bin.v2\libs\thread\test\test_thread.test\gcc-mingw-gnu-7.3.0 if not exist "..\..\..\bin.v2\libs\thread\test\test_thread.test\gcc-mingw-gnu-7.3.0\\" mkdir "..\..\..\bin.v2\libs\thread\test\test_thread.test\gcc-mingw-gnu-7.3.0" common.mkdir ..\..\..\bin.v2\libs\thread\test\test_thread.test\gcc-mingw-gnu-7.3.0\debug if not exist "..\..\..\bin.v2\libs\thread\test\test_thread.test\gcc-mingw-gnu-7.3.0\debug\\" mkdir "..\..\..\bin.v2\libs\thread\test\test_thread.test\gcc-mingw-gnu-7.3.0\debug" common.mkdir ..\..\..\bin.v2\libs\thread\test\test_thread.test\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread if not exist "..\..\..\bin.v2\libs\thread\test\test_thread.test\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\\" mkdir "..\..\..\bin.v2\libs\thread\test\test_thread.test\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread" common.mkdir ..\..\..\bin.v2\libs\thread\test\test_thread.test\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\threading-multi if not exist "..\..\..\bin.v2\libs\thread\test\test_thread.test\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\threading-multi\\" mkdir "..\..\..\bin.v2\libs\thread\test\test_thread.test\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\threading-multi" gcc.compile.c++ ..\..\..\bin.v2\libs\thread\test\test_thread.test\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\threading-multi\test_thread.o "g++" -O0 -fno-inline -Wall -pedantic -g -pthread -m64 -Wextra -Wno-long-long -Wno-unused-parameter -Wunused-function -pedantic -DBOOST_ALL_NO_LIB=1 -DBOOST_CHRONO_DYN_LINK=1 -DBOOST_SYSTEM_DYN_LINK=1 -DBOOST_TEST_DYN_LINK=1 -DBOOST_TEST_NO_AUTO_LINK=1 -DBOOST_THREAD_BUILD_DLL=1 -DBOOST_THREAD_POSIX -DBOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED -DBOOST_THREAD_USE_DLL=1 -DBOOST_TIMER_DYN_LINK=1 -I"..\..\.." -c -o "..\..\..\bin.v2\libs\thread\test\test_thread.test\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\threading-multi\test_thread.o" "test_thread.cpp" In file included from ..\..\../boost/thread/mutex.hpp:16:0, from ..\..\../boost/thread/pthread/thread_data.hpp:13, from ..\..\../boost/thread/thread_only.hpp:17, from test_thread.cpp:13: ..\..\../boost/thread/pthread/mutex.hpp: In member function 'bool boost::timed_mutex::do_try_lock_until(const internal_platform_timepoint&)': ..\..\../boost/thread/pthread/mutex.hpp:309:77: error: 'const internal_platform_timepoint {aka const struct boost::detail::mono_platform_timepoint}' has no member named 'getTs'; did you mean 'getNs'? int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout.getTs()); ^~~~~ getNs In file included from ..\..\../boost/assert.hpp:58:0, from ..\..\../boost/thread/pthread/pthread_mutex_scoped_lock.hpp:10, from ..\..\../boost/thread/pthread/mutex.hpp:25, from ..\..\../boost/thread/mutex.hpp:16, from ..\..\../boost/thread/pthread/thread_data.hpp:13, from ..\..\../boost/thread/thread_only.hpp:17, from test_thread.cpp:13: ..\..\../boost/thread/pthread/mutex.hpp:314:31: error: in argument to unary ! BOOST_ASSERT(!cond_res); ^ ..\..\../boost/thread/pthread/mutex.hpp:314:17: note: in expansion of macro 'BOOST_ASSERT' BOOST_ASSERT(!cond_res); ^~~~~~~~~~~~ In file included from ..\..\../boost/thread/thread_only.hpp:17:0, from test_thread.cpp:13: ..\..\../boost/thread/pthread/thread_data.hpp: In member function 'void boost::thread_attributes::set_stack_size(std::size_t)': ..\..\../boost/thread/pthread/thread_data.hpp:57:37: error: '::sysconf' has not been declared std::size_t page_size = ::sysconf( _SC_PAGESIZE); ^~~~~~~ ..\..\../boost/thread/pthread/thread_data.hpp:57:37: note: suggested alternative: 'sscanf' std::size_t page_size = ::sysconf( _SC_PAGESIZE); ^~~~~~~ sscanf ..\..\../boost/thread/pthread/thread_data.hpp:57:46: error: '_SC_PAGESIZE' was not declared in this scope std::size_t page_size = ::sysconf( _SC_PAGESIZE); ^~~~~~~~~~~~ ..\..\../boost/thread/pthread/thread_data.hpp:57:46: note: suggested alternative: '_CVTBUFSIZE' std::size_t page_size = ::sysconf( _SC_PAGESIZE); ^~~~~~~~~~~~ _CVTBUFSIZE In file included from ..\..\../boost/thread/condition_variable.hpp:16:0, from ..\..\../boost/thread/thread_only.hpp:26, from test_thread.cpp:13: ..\..\../boost/thread/pthread/condition_variable.hpp: In member function 'bool boost::condition_variable::do_wait_until(boost::unique_lock&, const internal_platform_timepoint&)': ..\..\../boost/thread/pthread/condition_variable.hpp:128:70: error: 'const internal_platform_timepoint {aka const struct boost::detail::mono_platform_timepoint}' has no member named 'getTs'; did you mean 'getNs'? cond_res=pthread_cond_timedwait(&cond,the_mutex,&timeout.getTs()); ^~~~~ getNs ..\..\../boost/thread/pthread/condition_variable.hpp: In member function 'bool boost::condition_variable_any::do_wait_until(lock_type&, const internal_platform_timepoint&)': ..\..\../boost/thread/pthread/condition_variable.hpp:480:73: error: 'const internal_platform_timepoint {aka const struct boost::detail::mono_platform_timepoint}' has no member named 'getTs'; did you mean 'getNs'? res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout.getTs()); ^~~~~ getNs ...failed gcc.compile.c++ ..\..\..\bin.v2\libs\thread\test\test_thread.test\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\threading-multi\test_thread.o... gcc.compile.c++ ..\..\..\bin.v2\libs\thread\test\test_thread.test\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\threading-multi\winrt_init.o "g++" -O0 -fno-inline -Wall -pedantic -g -pthread -m64 -Wextra -Wno-long-long -Wno-unused-parameter -Wunused-function -pedantic -DBOOST_ALL_NO_LIB=1 -DBOOST_CHRONO_DYN_LINK=1 -DBOOST_SYSTEM_DYN_LINK=1 -DBOOST_TEST_DYN_LINK=1 -DBOOST_TEST_NO_AUTO_LINK=1 -DBOOST_THREAD_BUILD_DLL=1 -DBOOST_THREAD_POSIX -DBOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED -DBOOST_THREAD_USE_DLL=1 -DBOOST_TIMER_DYN_LINK=1 -I"..\..\.." -c -o "..\..\..\bin.v2\libs\thread\test\test_thread.test\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\threading-multi\winrt_init.o" "winrt_init.cpp" common.mkdir ..\..\..\bin.v2\libs\thread\build if not exist "..\..\..\bin.v2\libs\thread\build\\" mkdir "..\..\..\bin.v2\libs\thread\build" common.mkdir ..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0 if not exist "..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0\\" mkdir "..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0" common.mkdir ..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0\debug if not exist "..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0\debug\\" mkdir "..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0\debug" common.mkdir ..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread if not exist "..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\\" mkdir "..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread" common.mkdir ..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\threading-multi if not exist "..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\threading-multi\\" mkdir "..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\threading-multi" common.mkdir ..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\threading-multi\pthread if not exist "..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\threading-multi\pthread\\" mkdir "..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\threading-multi\pthread" gcc.compile.c++ ..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\threading-multi\pthread\thread.o "g++" -O0 -fno-inline -Wall -pedantic -g -pthread -m64 -Wextra -Wno-long-long -Wno-unused-parameter -Wunused-function -pedantic -DBOOST_ALL_NO_LIB=1 -DBOOST_SYSTEM_DYN_LINK=1 -DBOOST_THREAD_BUILD_DLL=1 -DBOOST_THREAD_DONT_USE_CHRONO -DBOOST_THREAD_POSIX -DBOOST_USE_WINDOWS_H -DWIN32_LEAN_AND_MEAN -I"..\..\.." -c -o "..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\threading-multi\pthread\thread.o" "..\..\..\libs\thread\src\pthread\thread.cpp" In file included from ..\..\../boost/thread/mutex.hpp:16:0, from ..\..\../boost/thread/pthread/thread_data.hpp:13, from ..\..\../boost/thread/thread_only.hpp:17, from ..\..\..\libs\thread\src\pthread\thread.cpp:11: ..\..\../boost/thread/pthread/mutex.hpp: In member function 'bool boost::timed_mutex::do_try_lock_until(const internal_platform_timepoint&)': ..\..\../boost/thread/pthread/mutex.hpp:309:77: error: 'const internal_platform_timepoint {aka const struct boost::detail::mono_platform_timepoint}' has no member named 'getTs'; did you mean 'getNs'? int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout.getTs()); ^~~~~ getNs In file included from ..\..\../boost/assert.hpp:58:0, from ..\..\../boost/thread/pthread/pthread_mutex_scoped_lock.hpp:10, from ..\..\../boost/thread/pthread/mutex.hpp:25, from ..\..\../boost/thread/mutex.hpp:16, from ..\..\../boost/thread/pthread/thread_data.hpp:13, from ..\..\../boost/thread/thread_only.hpp:17, from ..\..\..\libs\thread\src\pthread\thread.cpp:11: ..\..\../boost/thread/pthread/mutex.hpp:314:31: error: in argument to unary ! BOOST_ASSERT(!cond_res); ^ ..\..\../boost/thread/pthread/mutex.hpp:314:17: note: in expansion of macro 'BOOST_ASSERT' BOOST_ASSERT(!cond_res); ^ In file included from ..\..\../boost/thread/thread_only.hpp:17:0, from ..\..\..\libs\thread\src\pthread\thread.cpp:11: ..\..\../boost/thread/pthread/thread_data.hpp: In member function 'void boost::thread_attributes::set_stack_size(std::size_t)': ..\..\../boost/thread/pthread/thread_data.hpp:57:37: error: '::sysconf' has not been declared std::size_t page_size = ::sysconf( _SC_PAGESIZE); ^~~~~~~ ..\..\../boost/thread/pthread/thread_data.hpp:57:37: note: suggested alternative: 'sscanf' std::size_t page_size = ::sysconf( _SC_PAGESIZE); ^~~~~~~ sscanf ..\..\../boost/thread/pthread/thread_data.hpp:57:46: error: '_SC_PAGESIZE' was not declared in this scope std::size_t page_size = ::sysconf( _SC_PAGESIZE); ^~~~~~~~~~~~ ..\..\../boost/thread/pthread/thread_data.hpp:57:46: note: suggested alternative: 'DC_PAPERSIZE' std::size_t page_size = ::sysconf( _SC_PAGESIZE); ^~~~~~~~~~~~ DC_PAPERSIZE In file included from ..\..\../boost/thread/condition_variable.hpp:16:0, from ..\..\../boost/thread/thread_only.hpp:26, from ..\..\..\libs\thread\src\pthread\thread.cpp:11: ..\..\../boost/thread/pthread/condition_variable.hpp: In member function 'bool boost::condition_variable::do_wait_until(boost::unique_lock&, const internal_platform_timepoint&)': ..\..\../boost/thread/pthread/condition_variable.hpp:128:70: error: 'const internal_platform_timepoint {aka const struct boost::detail::mono_platform_timepoint}' has no member named 'getTs'; did you mean 'getNs'? cond_res=pthread_cond_timedwait(&cond,the_mutex,&timeout.getTs()); ^~~~~ getNs ..\..\../boost/thread/pthread/condition_variable.hpp: In member function 'bool boost::condition_variable_any::do_wait_until(lock_type&, const internal_platform_timepoint&)': ..\..\../boost/thread/pthread/condition_variable.hpp:480:73: error: 'const internal_platform_timepoint {aka const struct boost::detail::mono_platform_timepoint}' has no member named 'getTs'; did you mean 'getNs'? res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout.getTs()); ^~~~~ getNs ..\..\..\libs\thread\src\pthread\thread.cpp: In function 'void boost::this_thread::yield()': ..\..\..\libs\thread\src\pthread\thread.cpp:479:9: error: expected ';' before '}' token } ^ ...failed gcc.compile.c++ ..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\threading-multi\pthread\thread.o... gcc.compile.c++ ..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\threading-multi\pthread\once.o "g++" -O0 -fno-inline -Wall -pedantic -g -pthread -m64 -Wextra -Wno-long-long -Wno-unused-parameter -Wunused-function -pedantic -DBOOST_ALL_NO_LIB=1 -DBOOST_SYSTEM_DYN_LINK=1 -DBOOST_THREAD_BUILD_DLL=1 -DBOOST_THREAD_DONT_USE_CHRONO -DBOOST_THREAD_POSIX -DBOOST_USE_WINDOWS_H -DWIN32_LEAN_AND_MEAN -I"..\..\.." -c -o "..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\threading-multi\pthread\once.o" "..\..\..\libs\thread\src\pthread\once.cpp" gcc.compile.c++ ..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\threading-multi\future.o "g++" -O0 -fno-inline -Wall -pedantic -g -pthread -m64 -Wextra -Wno-long-long -Wno-unused-parameter -Wunused-function -pedantic -DBOOST_ALL_NO_LIB=1 -DBOOST_SYSTEM_DYN_LINK=1 -DBOOST_THREAD_BUILD_DLL=1 -DBOOST_THREAD_DONT_USE_CHRONO -DBOOST_THREAD_POSIX -DBOOST_USE_WINDOWS_H -DWIN32_LEAN_AND_MEAN -I"..\..\.." -c -o "..\..\..\bin.v2\libs\thread\build\gcc-mingw-gnu-7.3.0\debug\threadapi-pthread\threading-multi\future.o" "..\..\..\libs\thread\src\future.cpp" ...skipped libboost_thread_pthread-mgw73-mt-d-x64-1_67.dll.a for lack of pthread\thread.o... ...skipped test_thread.exe for lack of test_thread.o... ...skipped test_thread.run for lack of test_thread.exe... ...failed updating 2 targets... ...skipped 4 targets... ...updated 16 targets... ```

Do not pay attention to this message:

************************************************************
Trying to build Boost.Thread with pthread support.
If you need pthread you should specify the paths.
You can specify them in site-config.jam, user-config.jam
or in the environment.
For example:
PTW32_INCLUDE=C:\Program Files\ptw32\Pre-built2\include
PTW32_LIB=C:\Program Files\ptw32\Pre-built2\lib
************************************************************

you will link by using linkflags=-pthread or modifying Boost.Build src/tools/gcc.jam#L377

hanetzer commented 6 years ago

@Kojoley oof. that's an ugly amount of issues to fix up. I'll go ahead and give it the good ol' college try, may need to have some talks with the fine folks in the #mingw-w64 irc chan on that.

viboes commented 6 years ago

If someone has time to spend on this platform, please provide a PR.