Add windows support #231

pull ryanofsky wants to merge 8 commits into bitcoin-core:master from ryanofsky:pr/win changing 14 files +717 −78
  1. ryanofsky commented at 8:31 AM on October 22, 2025: collaborator

    Add support for running on windows. These changes make the libmultiprocess API more generic, using stream types instead of file descriptors. All features are supported, including spawning processes with socket connections to the parent process. These changes were originally made in https://github.com/bitcoin/bitcoin/pull/32387

  2. DrahtBot commented at 8:31 AM on October 22, 2025: none

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline and AI policy for information on the review process.

    Type Reviewers
    Approach ACK hebasto, ViniciusCestarii

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #324 (proxy: Name threads spawned by the event loop by ViniciusCestarii)
    • #312 (util: report back child errors to parent and throw by ViniciusCestarii)
    • #298 (Fix error handling when creating clients (mp::ConnectStream) by xyzconstant)
    • #212 (ci: add newdeps job testing newer versions of cmake and capnproto by ryanofsky)
    • #175 (Set cmake_minimum_required(VERSION 3.22) by maflcko)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

    LLM Linter (✨ experimental)

    Possible typos and grammar issues:

    • It it possible -> It is possible [typo in include/mp/util.h comment; the intended meaning is clear but the verb is malformed.]

    <sup>2026-08-05 04:48:54</sup>

  3. DrahtBot added the label Needs rebase on Jan 13, 2026
  4. pavlenex referenced this in commit 9800329587 on Mar 24, 2026
  5. ryanofsky force-pushed on Apr 3, 2026
  6. ryanofsky commented at 9:43 PM on April 3, 2026: collaborator

    <!-- begin push-2 -->

    Rebased 7d2f3c4371f8689260061b4b98f0f15dff9d95f7 -> 2975facdd1ddb3b52d052aaaac611566f3ff27ae (pr/win.1 -> pr/win.2, compare)<!-- end --> due to conflicts with #237

  7. DrahtBot removed the label Needs rebase on Apr 3, 2026
  8. pavlenex commented at 8:58 AM on April 8, 2026: none

    We have miners using Stratum V2 that are on Windows and would like to see Windows IPC support landing, is there any estimate when they can expect this to materialize? We have a dozen of users who can help with testing if that's a blocker.

  9. Sjors commented at 10:20 AM on April 8, 2026: member

    @pavlenex testing would definitely be useful. I guess for that to work we'd need a stack of pull requests: this one here in libmultiprocess, one in Bitcoin Core that enables IPC support in the Windows Guix build, and then an SRI pull request that uses it. Testers would then have download (or build themselves) the custom bitcoin core and SRI binaries.

    I've added Windows support to my v32 wish list: https://github.com/bitcoin/bitcoin/issues/33777

    No guarantees obviously.

  10. ryanofsky commented at 1:18 PM on April 8, 2026: collaborator

    I'll try to get this PR ready for review this week, split up into smaller commits and with ci passing. From there as Sjors mentioned there is a lot more work to do: more code changes in https://github.com/bitcoin/bitcoin/pull/32387 that need to be made in bitcoin core, enabling IPC into windows builds in bitcoin core, enabling it in windows CI jobs with pycapnp, adding client support, probably adding a windows CI job to this repository.

    v32 sounds like a good target though and it is very useful to know there is demand for this feature, because it hasn't been a priority so far

  11. ryanofsky closed this on Apr 15, 2026

  12. ryanofsky force-pushed on Apr 15, 2026
  13. ryanofsky reopened this on Apr 15, 2026

  14. ryanofsky commented at 4:42 PM on April 15, 2026: collaborator

    PR is split up into commits now and should be reviewable. CI is not passing but failures look like IWYU errors. I also opened https://github.com/bitcoin/bitcoin/pull/35084 with corresponding bitcoin core changes. Windows support for bitcoin core can be tested with https://github.com/bitcoin/bitcoin/pull/32387 which combines both PRs and enables IPC by default in windows builds.

    <!-- begin push-3 -->

    Rebased 2975facdd1ddb3b52d052aaaac611566f3ff27ae -> cb16d2e37ece4ce9326f03624f7f195ae0e55462 (pr/win.2 -> pr/win.3, compare)<!-- end --> splitting changes up into more reviewable commits

    <!-- begin push-4 -->

    Updated cb16d2e37ece4ce9326f03624f7f195ae0e55462 -> e563c968b4e13ac54aaec474e2a6bd98cd0c1c36 (pr/win.3 -> pr/win.4, compare)<!-- end --> to fix various ci failures #231 (comment): macos/freebsd shutdownwrite fail, bitcoin core ci jobs api incompatibility, iwyu and olddeps fixes

    <!-- begin push-5 -->

    Updated e563c968b4e13ac54aaec474e2a6bd98cd0c1c36 -> d9fcac6e30d0b9ea2cf24814bb014be70e6a2ade (pr/win.4 -> pr/win.5, compare)<!-- end --> to fix IWYU errors https://github.com/bitcoin-core/libmultiprocess/actions/runs/24539430990/job/71741856575?pr=231

    <!-- begin push-6 -->

    Added 1 commits d9fcac6e30d0b9ea2cf24814bb014be70e6a2ade -> a1748e2fae3abf7ba41ffa78db82eae4761f6723 (pr/win.5 -> pr/win.6, compare)<!-- end --> to fix bitcoin core macos exception type error https://github.com/bitcoin-core/libmultiprocess/actions/runs/24541950788/job/71749481354?pr=231

    <!-- begin push-7 -->

    Updated a1748e2fae3abf7ba41ffa78db82eae4761f6723 -> 18fc18846e38dfec4b92a36b7a20d4f9be74a874 (pr/win.6 -> pr/win.7, compare)<!-- end --> with updates from https://github.com/bitcoin/bitcoin/pull/32387 pr/ipc-win.23

    <!-- begin push-8 -->

    Updated 18fc18846e38dfec4b92a36b7a20d4f9be74a874 -> 7fd5ec40bc8c2a1fa0e2645d2b587ce2c1c3d17d (pr/win.7 -> pr/win.8, compare)<!-- end --> adding workaround for ubuntu packaging bug exposed by cmake change https://github.com/bitcoin-core/libmultiprocess/actions/runs/24746487506/job/72399345861, also fixing olddeps include and iwyu errors https://github.com/bitcoin-core/libmultiprocess/actions/runs/24746487510, also fixing more MSVC errors, and rearranging commits

  15. ryanofsky force-pushed on Apr 16, 2026
  16. ryanofsky force-pushed on Apr 17, 2026
  17. Sjors commented at 1:57 PM on April 20, 2026: member

    How realistic is it to add a Windows CI job here? (can be cross-compiled)

  18. Sjors referenced this in commit d42af54c56 on Apr 20, 2026
  19. Sjors referenced this in commit 7de24f776c on Apr 20, 2026
  20. Sjors referenced this in commit 2f549eb17d on Apr 20, 2026
  21. ryanofsky commented at 5:21 PM on April 21, 2026: collaborator

    How realistic is it to add a Windows CI job here? (can be cross-compiled)

    I think this does need a windows CI job to exist in order to be merged, otherwise windows support is very likely to break with future changes, so thanks for opening #272.

    I think it may also make sense to split this PR up to separate the commits which are needed to support windows but don't actually add any windows code, from the one commit which actually does add windows code.

  22. Sjors commented at 7:00 PM on April 21, 2026: member

    it may also make sense to split this PR up to separate the commits which are needed to support windows but don't actually add any windows code

    Yes it would be good to land those changes to keep this PR focussed.

  23. ryanofsky force-pushed on Apr 21, 2026
  24. ryanofsky force-pushed on Apr 22, 2026
  25. Sjors referenced this in commit 8db8bf06ee on Apr 23, 2026
  26. Sjors referenced this in commit baf5d5e571 on Apr 23, 2026
  27. Sjors referenced this in commit 36b415c486 on Apr 23, 2026
  28. Sjors referenced this in commit a20bfd86d2 on Apr 23, 2026
  29. in include/mp/util.h:265 in 4f58c8c981
     260 | @@ -257,12 +261,20 @@ std::string LogEscape(const kj::StringTree& string, size_t max_size);
     261 |  
     262 |  using Stream = kj::Own<kj::AsyncIoStream>;
     263 |  
     264 | +#ifdef WIN32
     265 | +using ProcessId = uintptr_t;
    


    ViniciusCestarii commented at 5:50 PM on May 11, 2026:

    Out of curiosity, any reason ProcessId is uintptr_t rather than HANDLE on Windows? Would remove the reinterpret_casts


    ryanofsky commented at 1:26 PM on June 2, 2026:

    re: #231 (review)

    Out of curiosity, any reason ProcessId is uintptr_t rather than HANDLE on Windows? Would remove the reinterpret_casts

    Good question, I think you are right it could be good to use HANDLE instead. Probably original motivation for using uintptr_t was to avoid needing to pull in win32 headers for all code using mp/util.h, but maybe that bridge has already been crossed with inclusion of winsock2.h as per your other comment #231 (comment), so this should be revisited. Could also go the other direction and drop winsock2.h since it looks like it is only needed for INVALID_SOCKET definition.

    Another potentially confusing about this is that process handles and process ids (as returned by functions like GetCurrentProcessId) are actually different things on windows. Handles are more useful for controlling and waiting for processes, but process ids are more globally unique and useful in other contexts.

    Will look into alternatives here and try to add a clarifying comment at least.


    ryanofsky commented at 8:37 PM on July 29, 2026:

    re: #231 (review)

    This is switched to use HANDLE now

  30. ViniciusCestarii commented at 8:18 PM on May 11, 2026: contributor

    Tested mingw cross-build and native MSVC build

    Environment: Arch Linux (kernel 6.19), CMake 4.3.2, mingw-w64 GCC 15.2.0, Cap'n Proto 1.2.0, target Windows 11 (x64). MSVC side: MSBuild 18.5.4

    mingw cross (x86_64-w64-mingw32) worked for me with one small tweak. <winsock2.h> in util.h pulls winsock2.h -> ole2.h -> objbase.h -> rpc.h, which #defines interface as struct and breaks the build:

    #ifdef WIN32
    +#ifndef WIN32_LEAN_AND_MEAN
    +#define WIN32_LEAN_AND_MEAN
    +#endif
    #include <winsock2.h>
    #endif
    

    With that, build succeeds, examples run, and tests pass on Windows 11 10.0.26100

    MSVC native: same interface-as-struct macro pollution and more errors shows up but to make it work it seems it's not one line fix:

    <details> <summary>MSVC build log</summary> C:\Users\vinic\libmultiprocess>cmake --build build -j 1 MSBuild version 18.5.4+cb4e32d21 for .NET Framework

    util.cpp C:\Users\vinic\libmultiprocess\include\mp\util.h(187,38): warning C4003: not enough arguments for function-like macro i nvocation 'MP_ASSERT_CAPABILITY' [C:\Users\vinic\libmultiprocess\build\mputil.vcxproj] (compiling source file '../src/mp/util.cpp')

    C:\Users\vinic\libmultiprocess\src\mp\util.cpp(262,5): warning C4996: 'WSADuplicateSocketA': Use WSADuplicateSocketW() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings [C:\Users\vinic\libmultiprocess\bu ild\mputil.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\util.cpp(291,5): warning C4244: 'argument': conversion from 'SOCKET' to 'int', po ssible loss of data [C:\Users\vinic\libmultiprocess\build\mputil.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\util.cpp(290,19): warning C4996: 'WSASocketA': Use WSASocketW() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings [C:\Users\vinic\libmultiprocess\build\mputil.vcxpro j] mputil.vcxproj -> C:\Users\vinic\libmultiprocess\build\mputil.dir\Debug\mputil.lib gen.cpp C:\Users\vinic\libmultiprocess\include\mp\util.h(187,38): warning C4003: not enough arguments for function-like macro i nvocation 'MP_ASSERT_CAPABILITY' [C:\Users\vinic\libmultiprocess\build\mpgen.vcxproj] (compiling source file '../src/mp/gen.cpp')

    C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(80,66): error C2332: 'struct': missing tag name [C:\Users\vinic\libmultip rocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(80,66): error C2144: syntax error: '<unnamed-tag>' should be preceded by ')' [C:\Users\vinic\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(80,66): error C2144: syntax error: '<unnamed-tag>' should be preceded by ';' [C:\Users\vinic\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(80,66): error C2059: syntax error: ',' [C:\Users\vinic\libmultiprocess\bu ild\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(80,132): error C2332: 'struct': missing tag name [C:\Users\vinic\libmulti process\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(80,132): error C2144: syntax error: '<unnamed-tag>' should be preceded by ')' [C:\Users\vinic\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(80,132): error C2062: type '' unexpected [C:\Users\vinic\libmultiprocess
    build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(80,171): error C2947: expecting '>' to terminate template-argument-list, found '>' [C:\Users\vinic\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(80,182): error C2059: syntax error: ')' [C:\Users\vinic\libmultiprocess\b uild\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(81,1): error C2143: syntax error: missing ';' before '{' [C:\Users\vinic
    libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(81,1): error C2447: '{': missing function header (old-style formal list?) [C:\Users\vinic\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(392,35): error C2332: 'struct': missing tag name [C:\Users\vinic\libmulti process\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(392,35): error C2226: syntax error: unexpected type '<unnamed-tag>' [C:\U sers\vinic\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(414,36): error C2332: 'struct': missing tag name [C:\Users\vinic\libmulti process\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(414,36): error C2144: syntax error: '<unnamed-tag>' should be preceded by ')' [C:\Users\vinic\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(414,13): error C2660: 'ForEachMethod': function does not take 0 arguments [C:\Users\vinic\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(80,13): see declaration of 'ForEachMethod' C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(414,13): while trying to match the argument list '()'

    C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(414,36): error C2144: syntax error: '<unnamed-tag>' should be preceded by ';' [C:\Users\vinic\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(414,36): error C2059: syntax error: ',' [C:\Users\vinic\libmultiprocess\b uild\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(414,137): error C2143: syntax error: missing ';' before '{' [C:\Users\vin ic\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(415,51): error C2065: 'method': undeclared identifier [C:\Users\vinic\lib multiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(417,35): error C2065: 'method': undeclared identifier [C:\Users\vinic\lib multiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(417,17): error C2672: 'GetAnnotationText': no matching overloaded functio n found [C:\Users\vinic\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(57,13): could be 'bool GetAnnotationText(const Reader &,uint64_t,kj::StringPtr *)'

    C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(419,92): error C2065: 'method_interface': undeclared identifier [C:\Users \vinic\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(485,48): error C2065: 'method': undeclared identifier [C:\Users\vinic\lib multiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(485,33): error C2734: 'schema_field': 'const' object must be initialized if not 'extern' [C:\Users\vinic\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(485,33): error C3531: 'schema_field': a symbol whose type contains 'auto' must have an initializer [C:\Users\vinic\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(485,46): error C2143: syntax error: missing ';' before ':' [C:\Users\vini c\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(485,81): error C2143: syntax error: missing ';' before ')' [C:\Users\vini c\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(488,48): error C2065: 'method': undeclared identifier [C:\Users\vinic\lib multiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(488,33): error C2734: 'schema_field': 'const' object must be initialized if not 'extern' [C:\Users\vinic\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(488,33): error C3531: 'schema_field': a symbol whose type contains 'auto' must have an initializer [C:\Users\vinic\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(488,46): error C2143: syntax error: missing ';' before ':' [C:\Users\vini c\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(488,82): error C2143: syntax error: missing ';' before ')' [C:\Users\vini c\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(504,55): error C2065: 'method_interface': undeclared identifier [C:\Users \vinic\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(504,85): error C2332: 'struct': missing tag name [C:\Users\vinic\libmulti process\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(504,85): error C2226: syntax error: unexpected type '<unnamed-tag>' [C:\U sers\vinic\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(504,88): error C2143: syntax error: missing ';' before '{' [C:\Users\vini c\libmultiprocess\build\mpgen.vcxproj] C:\Users\vinic\libmultiprocess\src\mp\gen.cpp(620,14): error C2059: syntax error: ')' [C:\Users\vinic\libmultiprocess\b uild\mpgen.vcxproj] proxy.cpp C:\Users\vinic\libmultiprocess\include\mp\util.h(187,38): warning C4003: not enough arguments for function-like macro i nvocation 'MP_ASSERT_CAPABILITY' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\capnproto\install\include\capnp\capability.h(88,40): error C2838: 'IPrintDialogServices': illegal qualified name in member declaration [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\capnproto\install\include\capnp\capability.h(88,40): error C2275: 'IPrintDialogServices': expected an expression ins tead of a type [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\capnproto\install\include\capnp\capability.h(88,40): error C2440: 'initializing': cannot convert from 'IPrintDialogS ervices' to 'const capnp::Kind' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\capability.h(88,40): No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

    C:\capnproto\install\include\capnp\capability.h(913,32): error C2838: 'IPrintDialogServices': illegal qualified name in member declaration [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\capnproto\install\include\capnp\capability.h(913,32): error C2275: 'IPrintDialogServices': expected an expression in stead of a type [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\capability.h(913,32): prefix the qualified-id with 'typename' to indicate a type

    C:\capnproto\install\include\capnp\capability.h(913,32): error C2975: 'k': invalid template argument for 'capnp::_::Poi nterHelpers', expected compile-time constant expression [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(319,28): see declaration of 'k'

    C:\capnproto\install\include\capnp\capability.h(940,22): error C2838: 'IPrintDialogServices': illegal qualified name in member declaration [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\capnproto\install\include\capnp\capability.h(940,22): error C2275: 'IPrintDialogServices': expected an expression in stead of a type [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\capability.h(940,22): prefix the qualified-id with 'typename' to indicate a type

    C:\capnproto\install\include\capnp\capability.h(940,22): error C2975: 'k': invalid template argument for 'capnp::List', expected compile-time constant expression [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(204,28): see declaration of 'k'

    C:\capnproto\install\include\capnp\capability.h(940,8): error C2953: 'capnp::List<T,capnp::Kind::PRIMITIVE>': class tem plate has already been defined [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\list.h(101,8): see declaration of 'capnp::List<T,capnp::Kind::PRIMITIVE>'

    C:\capnproto\install\include\capnp\capability.h(1285,43): error C2838: 'IPrintDialogServices': illegal qualified name i n member declaration [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\capnproto\install\include\capnp\capability.h(1285,43): error C2275: 'IPrintDialogServices': expected an expression i nstead of a type [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\capability.h(1285,43): prefix the qualified-id with 'typename' to indicate a type

    C:\capnproto\install\include\capnp\capability.h(1285,43): error C2975: 'unnamed-parameter': invalid template argument f or 'capnp::Orphanage::GetInnerReader', expected compile-time constant expression [C:\Users\vinic\libmultiprocess\build
    multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\orphan.h(184,25): see declaration of 'unnamed-parameter'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(57,5): error C2838: 'IPrintDialogServices': illegal quali fied name in member declaration [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(57,5): error C2275: 'IPrintDialogServices': expected an e xpression instead of a type [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(57,5): error C2440: 'initializing': cannot convert from ' IPrintDialogServices' to 'const capnp::Kind' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(57,5): No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(106,5): error C2838: 'IPrintDialogServices': illegal qual ified name in member declaration [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(106,5): error C2275: 'IPrintDialogServices': expected an expression instead of a type [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(106,5): error C2440: 'initializing': cannot convert from 'IPrintDialogServices' to 'const capnp::Kind' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(106,5): No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(755,53): error C2039: 'get': is not a member of 'capnp::_ ::PointerHelpersmp::Thread,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::_::PointerHelpersmp::Thread,capnp::Kind::INTERFACE'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(755,53): error C3861: 'get': identifier not found [C:\Use rs\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(759,53): error C2039: 'get': is not a member of 'capnp::_ ::PointerHelpersmp::Thread,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::_::PointerHelpersmp::Thread,capnp::Kind::INTERFACE'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(759,53): error C2672: 'get': no matching overloaded funct ion found [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\kj\tuple.h(360,13): could be 'unknown-type kj::get(Tuple &&)' C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(759,53): 'unknown-type kj::get(Tuple &&)': could not deduce template argument for 'index'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(766,46): error C2039: 'set': is not a member of 'capnp::_ ::PointerHelpersmp::Thread,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::_::PointerHelpersmp::Thread,capnp::Kind::INTERFACE'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(766,46): error C3861: 'set': identifier not found [C:\Use rs\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(770,46): error C2039: 'set': is not a member of 'capnp::_ ::PointerHelpersmp::Thread,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::_::PointerHelpersmp::Thread,capnp::Kind::INTERFACE'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(770,46): error C3861: 'set': identifier not found [C:\Use rs\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(775,46): error C2039: 'adopt': is not a member of 'capnp: :::PointerHelpersmp::Thread,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::::PointerHelpersmp::Thread,capnp::Kind::INTERFACE'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(775,46): error C3861: 'adopt': identifier not found [C:\U sers\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(779,53): error C2039: 'disown': is not a member of 'capnp ::::PointerHelpersmp::Thread,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::::PointerHelpersmp::Thread,capnp::Kind::INTERFACE'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(779,53): error C3861: 'disown': identifier not found [C:
    Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(852,53): error C2039: 'get': is not a member of 'capnp::_ ::PointerHelpersmp::Thread,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::_::PointerHelpersmp::Thread,capnp::Kind::INTERFACE'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(852,53): error C3861: 'get': identifier not found [C:\Use rs\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(856,53): error C2039: 'get': is not a member of 'capnp::_ ::PointerHelpersmp::Thread,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::_::PointerHelpersmp::Thread,capnp::Kind::INTERFACE'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(856,53): error C2672: 'get': no matching overloaded funct ion found [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\kj\tuple.h(360,13): could be 'unknown-type kj::get(Tuple &&)' C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(856,53): 'unknown-type kj::get(Tuple &&)': could not deduce template argument for 'index'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(863,46): error C2039: 'set': is not a member of 'capnp::_ ::PointerHelpersmp::Thread,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::_::PointerHelpersmp::Thread,capnp::Kind::INTERFACE'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(863,46): error C3861: 'set': identifier not found [C:\Use rs\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(867,46): error C2039: 'set': is not a member of 'capnp::_ ::PointerHelpersmp::Thread,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::_::PointerHelpersmp::Thread,capnp::Kind::INTERFACE'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(867,46): error C3861: 'set': identifier not found [C:\Use rs\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(872,46): error C2039: 'adopt': is not a member of 'capnp: :::PointerHelpersmp::Thread,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::::PointerHelpersmp::Thread,capnp::Kind::INTERFACE'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(872,46): error C3861: 'adopt': identifier not found [C:\U sers\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(876,53): error C2039: 'disown': is not a member of 'capnp ::::PointerHelpersmp::Thread,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::::PointerHelpersmp::Thread,capnp::Kind::INTERFACE'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(876,53): error C3861: 'disown': identifier not found [C:
    Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(891,53): error C2039: 'get': is not a member of 'capnp::_ ::PointerHelpersmp::Thread,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::_::PointerHelpersmp::Thread,capnp::Kind::INTERFACE'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(891,53): error C3861: 'get': identifier not found [C:\Use rs\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(895,53): error C2039: 'get': is not a member of 'capnp::_ ::PointerHelpersmp::Thread,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::_::PointerHelpersmp::Thread,capnp::Kind::INTERFACE'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(895,53): error C2672: 'get': no matching overloaded funct ion found [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\kj\tuple.h(360,13): could be 'unknown-type kj::get(Tuple &&)' C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(895,53): 'unknown-type kj::get(Tuple &&)': could not deduce template argument for 'index'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(902,46): error C2039: 'set': is not a member of 'capnp::_ ::PointerHelpersmp::Thread,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::_::PointerHelpersmp::Thread,capnp::Kind::INTERFACE'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(902,46): error C3861: 'set': identifier not found [C:\Use rs\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(906,46): error C2039: 'set': is not a member of 'capnp::_ ::PointerHelpersmp::Thread,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::_::PointerHelpersmp::Thread,capnp::Kind::INTERFACE'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(906,46): error C3861: 'set': identifier not found [C:\Use rs\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(911,46): error C2039: 'adopt': is not a member of 'capnp: :::PointerHelpersmp::Thread,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::::PointerHelpersmp::Thread,capnp::Kind::INTERFACE'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(911,46): error C3861: 'adopt': identifier not found [C:\U sers\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(915,53): error C2039: 'disown': is not a member of 'capnp ::::PointerHelpersmp::Thread,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::::PointerHelpersmp::Thread,capnp::Kind::INTERFACE'

    C:\Users\vinic\libmultiprocess\build\include\mp\proxy.capnp.h(915,53): error C3861: 'disown': identifier not found [C:
    Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\capnproto\install\include\capnp\rpc-twoparty.capnp.h(724,60): error C2039: 'get': is not a member of 'capnp::::Poin terHelperscapnp::Capability,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::::PointerHelperscapnp::Capability,capnp::Kind::INTERFACE'

    C:\capnproto\install\include\capnp\rpc-twoparty.capnp.h(724,60): error C3861: 'get': identifier not found [C:\Users\vin ic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\capnproto\install\include\capnp\rpc-twoparty.capnp.h(728,60): error C2039: 'get': is not a member of 'capnp::::Poin terHelperscapnp::Capability,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::::PointerHelperscapnp::Capability,capnp::Kind::INTERFACE'

    C:\capnproto\install\include\capnp\rpc-twoparty.capnp.h(728,60): error C2672: 'get': no matching overloaded function fo und [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\kj\tuple.h(360,13): could be 'unknown-type kj::get(Tuple &&)' C:\capnproto\install\include\capnp\rpc-twoparty.capnp.h(728,60): 'unknown-type kj::get(Tuple &&)': could not deduce template argument for 'index'

    C:\capnproto\install\include\capnp\rpc-twoparty.capnp.h(735,53): error C2039: 'set': is not a member of 'capnp::::Poin terHelperscapnp::Capability,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::::PointerHelperscapnp::Capability,capnp::Kind::INTERFACE'

    C:\capnproto\install\include\capnp\rpc-twoparty.capnp.h(735,53): error C3861: 'set': identifier not found [C:\Users\vin ic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\capnproto\install\include\capnp\rpc-twoparty.capnp.h(739,53): error C2039: 'set': is not a member of 'capnp::::Poin terHelperscapnp::Capability,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::::PointerHelperscapnp::Capability,capnp::Kind::INTERFACE'

    C:\capnproto\install\include\capnp\rpc-twoparty.capnp.h(739,53): error C3861: 'set': identifier not found [C:\Users\vin ic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\capnproto\install\include\capnp\rpc-twoparty.capnp.h(744,53): error C2039: 'adopt': is not a member of 'capnp::::Po interHelperscapnp::Capability,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::::PointerHelperscapnp::Capability,capnp::Kind::INTERFACE'

    C:\capnproto\install\include\capnp\rpc-twoparty.capnp.h(744,53): error C3861: 'adopt': identifier not found [C:\Users\v inic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    C:\capnproto\install\include\capnp\rpc-twoparty.capnp.h(748,60): error C2039: 'disown': is not a member of 'capnp::::P ointerHelperscapnp::Capability,capnp::Kind::INTERFACE' [C:\Users\vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp') C:\capnproto\install\include\capnp\common.h(320,8): see declaration of 'capnp::::PointerHelperscapnp::Capability,capnp::Kind::INTERFACE'

    C:\capnproto\install\include\capnp\rpc-twoparty.capnp.h(748,60): error C3861: 'disown': identifier not found [C:\Users
    vinic\libmultiprocess\build\multiprocess.vcxproj] (compiling source file '../src/mp/proxy.cpp')

    </details>

  31. ryanofsky commented at 1:27 PM on June 2, 2026: collaborator

    Thanks for the review! Will follow up and look into ProcessId and winsock2.h issues

  32. DrahtBot added the label Needs rebase on Jun 2, 2026
  33. ryanofsky referenced this in commit 3f221b5bfd on Jul 17, 2026
  34. ryanofsky force-pushed on Jul 17, 2026
  35. ryanofsky commented at 2:06 PM on July 17, 2026: collaborator

    This PR is rebased after the #274 merge, so should be ready for review now. It does look like fixes will be needed for CI, though, and I'm working on that.

    Note my goal with this PR is just to add a basic level of windows support so libmultiprocess cross-compiles with mingw and spawn and listen tests run in wine. More followups will probably be needed after this to fix any problems that arise with MSVC support or enabling IPC in windows builds for Bitcoin core. The full PR targeting all of that is https://github.com/bitcoin/bitcoin/pull/32387 and has some unresolved issues still.

    The downstream PR https://github.com/bitcoin/bitcoin/pull/35084 updating Bitcoin core to use the newer libmultiprocess API is also ready for review and can be reviewed in parallel to this.


    <!-- begin push-9 -->

    Rebased 7fd5ec40bc8c2a1fa0e2645d2b587ce2c1c3d17d -> 259f0101b61dbce11cf8c3b1ee678cc1719ead16 (pr/win.8 -> pr/win.9, compare)<!-- end --> after #274

    <!-- begin push-10 -->

    Updated 259f0101b61dbce11cf8c3b1ee678cc1719ead16 -> c0bc409b645844afc8da0feb609aa3ded41864e8 (pr/win.9 -> pr/win.10, compare)<!-- end --> making listen_tests fixes and enabling wine CI job

    <!-- begin push-11 -->

    Updated c0bc409b645844afc8da0feb609aa3ded41864e8 -> 5a707dccf145cf88587d10a42d524eff8af2041a (pr/win.10 -> pr/win.11, compare)<!-- end --> to fix windows CI nix errors https://github.com/bitcoin-core/libmultiprocess/actions/runs/29765222110/job/88429702800?pr=231

  36. DrahtBot removed the label Needs rebase on Jul 17, 2026
  37. ryanofsky force-pushed on Jul 20, 2026
  38. ryanofsky force-pushed on Jul 20, 2026
  39. in include/mp/util.h:282 in 37a2190728 outdated
     276 | @@ -277,22 +277,19 @@ using ProcessId = int;
     277 |  using SocketId = int;
     278 |  constexpr SocketId SocketError{-1};
     279 |  
     280 | -//! Information about parent process passed to child process as a command-line
     281 | -//! argument. On unix this is the child socket fd number formatted as a string.
     282 | -using SpawnConnectInfo = std::string;
    


    Sjors commented at 11:05 AM on July 21, 2026:

    In 37a2190728ecfb7e19b9c7641f645e8152f6ab1c Improve SpawnProcess API and documentation nit: could document your rationale for this (https://github.com/bitcoin-core/libmultiprocess/pull/274#discussion_r3602499719) in the commit message:

    The type SpawnConnectInfo and SpawnConnectInfoToArgsFn aliases introduced in beaa50a046190277a91cdf9ca87c169fd2516c55 hurt readability more than they help.


    ryanofsky commented at 4:51 PM on July 22, 2026:

    re: #231 (review)

    Thanks! Added more context

  40. in include/mp/util.h:292 in 37a2190728 outdated
     302 | +std::tuple<ProcessId, SocketId> SpawnProcess(const std::function<std::vector<std::string>(std::string)>& spawn_argv);
     303 | +
     304 | +//! Initialize spawned child process using the connection string passed by
     305 | +//! SpawnProcess through its command line arguments. Returns socket id for
     306 | +//! communicating with the parent process.
     307 | +SocketId StartSpawned(const std::string& connect_info);
    


    Sjors commented at 11:15 AM on July 21, 2026:

    In 37a2190728ecfb7e19b9c7641f645e8152f6ab1c Improve SpawnProcess API and documentation: would be good to specifically document the connect_info argument.

    //! Initialize spawned child process. The connect_info argument is the
    //! connection string SpawnProcess generated in the parent process and passed
    //! to the child on its command line. Returns socket id for communicating with
    //! the parent process.
    

    ryanofsky commented at 4:52 PM on July 22, 2026:

    re: #231 (review)

    Nice, applied this change

  41. in include/mp/util.h:286 in 37a2190728
     296 | +//! pair. Calls spawn_argv callback with a connection string that needs to be
     297 | +//! passed to the child process, and executes the argv command line it returns.
     298 | +//! Returns child process id and socket id.
     299 | +//!
     300 | +//! The connection string is just a file descriptor number on unix, and the
     301 | +//! child process can call SpawnProcess to parse it.
    


    Sjors commented at 2:22 PM on July 21, 2026:

    In 37a2190728ecfb7e19b9c7641f645e8152f6ab1c Improve SpawnProcess API and documentation: did you mean StartSpawned instead of SpawnProcess?

    //! The connection string is just a file descriptor number on unix, and the 
    //! child process can call StartSpawned to get a socket handle from the connection string.
    

    For other reviewers, here's a diagram of how StartSpawned, SpawnProcess and the spawn_argv dance, based on the calculator example:

    <img width="619" height="904" alt="Image" src="https://github.com/user-attachments/assets/49457df1-8813-48fc-aff0-949f315f9fac" />


    ryanofsky commented at 5:01 PM on July 22, 2026:

    re: #231 (review)

    Good catch, fixed StartSpawned references. SpawnProcess and StartSpawned complement each other with SpawnProcess being called by parent and returing socket id, and StartSpawned being called by child and returning socket id.

    ConnectStream and ServeStream are also complements of each other with ServeStream wrapping a C++ interface pointer and serving it over a stream, and ConnectStream wrapping a stream and returning a C++ interface pointer.

    Usually ConnectStream is paired with SpawnProcess in the parent, and ServeStream is paired with StartSpawned in the child because the parent wants to call C++ methods on some interface provided by the child. But it's also possible to do the reverse and have the parent serve an interface to the child, or to not use Connect and Serve at all and just communicate directly over the socketpair.

  42. Sjors commented at 3:20 PM on July 21, 2026: member

    Some feedback on the first commit.

  43. ryanofsky force-pushed on Jul 22, 2026
  44. ryanofsky commented at 5:05 PM on July 22, 2026: collaborator

    Thanks for the review! Am planning to update downstream PR https://github.com/bitcoin/bitcoin/pull/32387 shortly with these changes and other fixes


    <!-- begin push-12 -->

    Updated 5a707dccf145cf88587d10a42d524eff8af2041a -> 8a682fea6ad99730f718398347c556649a5bbaf1 (pr/win.11 -> pr/win.12, compare)<!-- end --> with suggested changes and another listen_tests fix

  45. in src/mp/util.cpp:140 in 86aa0296b7 outdated
     132 | @@ -117,10 +133,56 @@ std::string LogEscape(const kj::StringTree& string, size_t max_size)
     133 |      return result;
     134 |  }
     135 |  
     136 | +//! Generate command line that the executable being invoked will split up using
     137 | +//! the CommandLineToArgvW function, which expects arguments with spaces to be
     138 | +//! quoted, quote characters to be backslash-escaped, and backslashes to also be
     139 | +//! backslash-escaped, but only if they precede a quote character.
     140 | +std::string CommandLineFromArgv(const std::vector<std::string>& argv)
    


    Sjors commented at 2:52 PM on July 23, 2026:

    In 86aa0296b7ff93e9810e8863dd863a050d17e1b3 util: Add Windows support: maybe introduce this helper in a separate commit along with some tests. Claude also thinks it found a bug:

    diff --git a/include/mp/util.h b/include/mp/util.h
    index 1182479796..1a3b92eea2 100644
    --- a/include/mp/util.h
    +++ b/include/mp/util.h
    @@ -283,4 +283,11 @@ std::string ThreadName(const char* exe_name);
     std::string LogEscape(const kj::StringTree& string, size_t max_size);
    
    +//! Convert an argument vector into a single command line string suitable for
    +//! CreateProcess, following the quoting rules of CommandLineToArgvW, which
    +//! executables use to split the command line back into arguments. Declared
    +//! unconditionally (not just on windows) so it can be unit tested on any
    +//! platform.
    +std::string CommandLineFromArgv(const std::vector<std::string>& argv);
    +
     using Stream = kj::Own<kj::AsyncIoStream>;
    
    diff --git a/src/mp/util.cpp b/src/mp/util.cpp
    index 024840db0e..0b080765a7 100644
    --- a/src/mp/util.cpp
    +++ b/src/mp/util.cpp
    @@ -162,4 +162,9 @@ std::string CommandLineFromArgv(const std::vector<std::string>& argv)
                             out.append(backslash_count * 2 + 1, '\\');
                             out.push_back('"');
    +                    } else if (i == arg.size()) {
    +                        // Backslashes at the end of the argument precede the
    +                        // closing quote added below, so also need to be doubled
    +                        out.append(backslash_count * 2, '\\');
    +                        --i; // Compensate for the outer loop's increment
                         } else {
                             // Otherwise, backslashes remain as-is
    diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
    index 1324629392..c3c181af82 100644
    --- a/test/CMakeLists.txt
    +++ b/test/CMakeLists.txt
    @@ -30,4 +30,5 @@ if(BUILD_TESTING AND TARGET CapnProto::kj-test)
         mp/test/spawn_tests.cpp
         mp/test/test.cpp
    +    mp/test/util_tests.cpp
       )
       include(${PROJECT_SOURCE_DIR}/cmake/TargetCapnpSources.cmake)
    diff --git a/test/mp/test/util_tests.cpp b/test/mp/test/util_tests.cpp
    new file mode 100644
    index 0000000000..9f78042f16
    --- /dev/null
    +++ b/test/mp/test/util_tests.cpp
    @@ -0,0 +1,106 @@
    +// Copyright (c) The Bitcoin Core developers
    +// Distributed under the MIT software license, see the accompanying
    +// file COPYING or http://www.opensource.org/licenses/mit-license.php.
    +
    +#include <mp/util.h>
    +
    +#include <kj/test.h>
    +
    +#ifdef WIN32
    +#include <shellapi.h>
    +#include <string>
    +#include <vector>
    +#endif
    +
    +namespace mp {
    +namespace test {
    +
    +KJ_TEST("CommandLineFromArgv quoting")
    +{
    +    // Arguments without spaces, tabs, or quotes pass through unquoted, even if
    +    // they contain backslashes.
    +    KJ_EXPECT(CommandLineFromArgv({}) == "");
    +    KJ_EXPECT(CommandLineFromArgv({"simple"}) == "simple");
    +    KJ_EXPECT(CommandLineFromArgv({"a", "b", "c"}) == "a b c");
    +    KJ_EXPECT(CommandLineFromArgv({R"(C:\a\b)"}) == R"(C:\a\b)");
    +    KJ_EXPECT(CommandLineFromArgv({R"(\\.\pipe\mp-1234-1)"}) == R"(\\.\pipe\mp-1234-1)");
    +    KJ_EXPECT(CommandLineFromArgv({R"(\)"}) == R"(\)");
    +
    +    // Empty arguments must be quoted so they are not dropped.
    +    KJ_EXPECT(CommandLineFromArgv({""}) == R"("")");
    +    KJ_EXPECT(CommandLineFromArgv({"a", "", "b"}) == R"(a "" b)");
    +
    +    // Arguments with spaces or tabs are quoted.
    +    KJ_EXPECT(CommandLineFromArgv({"has space"}) == R"("has space")");
    +    KJ_EXPECT(CommandLineFromArgv({"has\ttab"}) == "\"has\ttab\"");
    +    KJ_EXPECT(CommandLineFromArgv({R"(C:\Program Files\bitcoin\bitcoin-node.exe)", "-ipcfd", "4"}) ==
    +              R"("C:\Program Files\bitcoin\bitcoin-node.exe" -ipcfd 4)");
    +
    +    // Embedded quotes are backslash-escaped.
    +    KJ_EXPECT(CommandLineFromArgv({R"(say "hi")"}) == R"("say \"hi\"")");
    +    KJ_EXPECT(CommandLineFromArgv({R"(")"}) == R"("\"")");
    +
    +    // Backslashes preceding a quote are doubled; other backslashes are not.
    +    KJ_EXPECT(CommandLineFromArgv({R"(back\\"slash quote)"}) == R"("back\\\\\"slash quote")");
    +
    +    // Backslashes at the end of a quoted argument precede the closing quote,
    +    // so they must be doubled too, or the closing quote would be read as an
    +    // escaped literal quote and the argument would swallow the rest of the
    +    // command line.
    +    KJ_EXPECT(CommandLineFromArgv({R"(trailing backslash\)"}) == R"("trailing backslash\\")");
    +    KJ_EXPECT(CommandLineFromArgv({R"(trailing backslashes\\)"}) == R"("trailing backslashes\\\\")");
    +    KJ_EXPECT(CommandLineFromArgv({R"(mix \" of \\" things\)"}) == R"("mix \\\" of \\\\\" things\\")");
    +}
    +
    +#ifdef WIN32
    +KJ_TEST("CommandLineFromArgv round-trips through CommandLineToArgvW")
    +{
    +    //! Argument vectors covering the CommandLineToArgvW quoting rules: plain
    +    //! arguments, spaces and tabs, embedded quotes, backslashes in various
    +    //! positions, and realistic Windows paths.
    +    const std::vector<std::vector<std::string>> quoting_cases{
    +        {"simple"},
    +        {"a", "b", "c"},
    +        {""},
    +        {"a", "", "b"},
    +        {"has space"},
    +        {"has\ttab"},
    +        {R"(say "hi")"},
    +        {R"(")"},
    +        {R"(\)"},
    +        {R"(C:\a\b)"},
    +        {R"(C:\Program Files\bitcoin\bitcoin-node.exe)", "-ipcfd", "4"},
    +        {R"(\\.\pipe\mp-1234-1)"},
    +        {R"(trailing backslash\)"},
    +        {R"(trailing backslashes\\)"},
    +        {R"(back\\"slash quote)"},
    +        {R"(mix \" of \\" things\)"},
    +    };
    +
    +    for (const auto& argv : quoting_cases) {
    +        // Prepend a plain program name: CommandLineToArgvW parses the first
    +        // token with simpler rules (no backslash escaping), so only the
    +        // remaining arguments exercise the quoting logic under test.
    +        std::vector<std::string> args{"prog"};
    +        args.insert(args.end(), argv.begin(), argv.end());
    +
    +        const std::string cmd{CommandLineFromArgv(args)};
    +        // Test arguments are ASCII, so widening by casting is fine.
    +        const std::wstring wcmd{cmd.begin(), cmd.end()};
    +
    +        int argc{0};
    +        LPWSTR* wargv{CommandLineToArgvW(wcmd.c_str(), &argc)};
    +        KJ_ASSERT(wargv != nullptr, cmd);
    +        KJ_EXPECT(argc == static_cast<int>(args.size()), cmd, argc);
    +        for (int i = 0; i < argc && i < static_cast<int>(args.size()); ++i) {
    +            const std::wstring warg{wargv[i]};
    +            const std::string arg{warg.begin(), warg.end()};
    +            KJ_EXPECT(arg == args[i], cmd, i, arg);
    +        }
    +        LocalFree(wargv);
    +    }
    +}
    +#endif
    +
    +} // namespace test
    +} // namespace mp
    

    ryanofsky commented at 8:40 PM on July 29, 2026:

    re: #231 (review)

    Thanks! Added these tests and confirmed bugfix makes sense and is valid (both new tests fail without it)

  46. Sjors commented at 2:55 PM on July 23, 2026: member

    Roughly reviewed 86aa0296b7ff93e9810e8863dd863a050d17e1b3 util: Add Windows support. Windows code gives me a headache, but it's nicely constrained to a few places.

  47. sedited referenced this in commit a9d181f2d3 on Jul 29, 2026
  48. ryanofsky force-pushed on Jul 29, 2026
  49. ryanofsky commented at 11:26 PM on July 29, 2026: collaborator

    Thanks for the reviews!

    <!-- begin push-13 -->

    Updated 8a682fea6ad99730f718398347c556649a5bbaf1 -> 0d536801bd20aa87aba96b84f0d5bc8d9fab36fb (pr/win.12 -> pr/win.13, compare)<!-- end --> fixing CommandLineFromArgv final quoting bug and adding tests. Also cleaning up some casts and and ifdef.

  50. ryanofsky closed this on Jul 30, 2026

  51. ryanofsky reopened this on Jul 30, 2026

  52. hebasto commented at 8:27 PM on July 30, 2026: member

    Concept and approach ACK.

  53. ryanofsky force-pushed on Jul 30, 2026
  54. ryanofsky commented at 9:06 PM on July 30, 2026: collaborator

    <!-- begin push-14 -->

    Rebased 0d536801bd20aa87aba96b84f0d5bc8d9fab36fb -> b7e367622070a05d3cb14b8e6f06b2f2259ab0b1 (pr/win.13 -> pr/win.14, compare)<!-- end --> due to silent conflict with #311 https://github.com/bitcoin-core/libmultiprocess/actions/runs/30571231743/job/90968191947?pr=231

  55. Kino1994 referenced this in commit 33bd9b5d17 on Aug 2, 2026
  56. Improve SpawnProcess API and documentation
    Remove recently introduced SpawnConnectInfo and SpawnConnectInfoToArgsFn type
    aliases since they are the same on all platforms and might obscure the fact
    that connect info should be treated as an opaque string.
    
    Co-authored-by: Sjors Provoost <sjors@sprovoost.nl>
    8270bcec7d
  57. util: Add Windows CommandLineFromArgv escaping function
    Co-authored-by: Sjors Provoost <sjors@sprovoost.nl>
    dc27ce435b
  58. util: Add Windows support
    Add Windows-specific code to support building and running on Windows:
    
    - util.h: Guard ProcessId/SocketId/SocketError type aliases with WIN32
      ifdefs so they use SOCKET/uintptr_t on Windows and int on Unix.
      Add winsock2.h include on Windows.
    - util.cpp: Guard Unix-specific system headers with WIN32 ifdefs. Add
      Windows-specific includes (windows.h, winsock2.h). Guard MaxFd() with
      #ifndef WIN32. Add GetCurrentThreadId() branch in ThreadName(). Add
      win32Socketpair() forward-declare. Add Windows branch in SocketPair()
      using win32Socketpair(). Add CommandLineFromArgv() helper needed to
      construct CreateProcess command lines. Add Windows branch in
      SpawnProcess() using named pipes and WSADuplicateSocket to pass socket
      to child. Add Windows branch in StartSpawned() reading socket from
      named pipe. Add Windows branch in WaitProcess() using
      WaitForSingleObject/GetExitCodeProcess.
    - proxy.cpp: Add SocketOutputStream class on Windows (analogous to
      FdOutputStream but using SOCKET/send()). Add Windows branch in
      EventLoop constructor to create m_post_writer using SocketOutputStream.
    61ad1ed903
  59. in test/mp/test/spawn_tests.cpp:14 in 25443b923e
      10 | @@ -11,6 +11,7 @@
      11 |  #include <condition_variable>
      12 |  #include <csignal>
      13 |  #include <cstdlib>
      14 | +#include <functional>
    


    ViniciusCestarii commented at 1:29 PM on August 3, 2026:

    In "Improve SpawnProcess API and documentation" 25443b923eaaa518ed06855845a68dd9f1ca2b23

    nit: this #include <functional> seems unrelated and isn't needed here.


    ryanofsky commented at 3:34 AM on August 5, 2026:

    re: #231 (review)

    nit: this #include <functional> seems unrelated and isn't needed here.

    Thanks, dropped this include

    EDIT: added it back, since it's needed to call SpawnProcess and there are IWYU errors without it


    ViniciusCestarii commented at 11:58 AM on August 5, 2026:

    Sorry, I tried locally with a wrong command at first. But now I was able to reproduce this IWYU error and confirm that the include is necessary.

  60. in src/mp/util.cpp:268 in 7dcb54db4b
     263 | +    // Start child process
     264 | +    std::string cmd{CommandLineFromArgv(spawn_argv(pipe_path))};
     265 | +    STARTUPINFOA si{};
     266 | +    si.cb = sizeof(si);
     267 | +    PROCESS_INFORMATION pi{};
     268 | +    KJ_WIN32(CreateProcessA(/*lpApplicationName=*/nullptr, const_cast<char*>(cmd.c_str()), /*lpProcessAttributes=*/nullptr, /*lpThreadAttributes=*/nullptr, /*bInheritHandles=*/TRUE, /*dwCreationFlags=*/0, /*lpEnvironment=*/nullptr, /*lpCurrentDirectory=*/nullptr, &si, &pi), "CreateProcess failed");
    


    ViniciusCestarii commented at 2:08 PM on August 3, 2026:

    In "util: Add Windows support" 7dcb54db4bb707009081ab358c9a247a43d577fb

    The Unix branch tries to close all fds that child doesn't need before exec, but the Windows branch leaks everything inheritable with bInheritHandles=TRUE to the child process instead of only the necessary, including the both ends of the socketpair.


    ryanofsky commented at 3:33 AM on August 5, 2026:

    re: #231 (review)

    The Unix branch tries to close all fds that child doesn't need before exec, but the Windows branch leaks everything inheritable with bInheritHandles=TRUE to the child process instead of only the necessary, including the both ends of the socketpair.

    Makes sense. There should be no need for inherited handles so now setting this to false.

  61. in src/mp/util.cpp:260 in 7dcb54db4b
     252 | @@ -236,44 +253,111 @@ std::tuple<ProcessId, SocketId> SpawnProcess(const std::function<std::vector<std
     253 |          _exit(127);
     254 |      }
     255 |      return {pid, fds[1]};
     256 | +#else
     257 | +    // Create windows pipe to send socket over to child process.
     258 | +    static std::atomic<int> counter{1};
     259 | +    std::string pipe_path{"\\\\.\\pipe\\mp-" + std::to_string(GetCurrentProcessId()) + "-" + std::to_string(counter.fetch_add(1))};
     260 | +    HANDLE pipe{CreateNamedPipeA(pipe_path.c_str(), PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE | PIPE_WAIT, /*nMaxInstances=*/1, /*nOutBufferSize=*/0, /*nInBufferSize=*/0, /*nDefaultTimeOut=*/0, /*lpSecurityAttributes=*/nullptr)};
    


    ViniciusCestarii commented at 4:51 PM on August 3, 2026:

    In "util: Add Windows support" 7dcb54db4bb707009081ab358c9a247a43d577fb

    CreateNamedPipeA sets the flag PIPE_WAIT and then calls ConnectNamedPipe so if the child never connects to the pipe (exits or crashes before), the parent blocks in ConnectNamedPipe forever.

    KJ_TEST("SpawnProcess does not hang if child never connects to the pipe")
    {
        // The named pipe SpawnProcess uses to hand the socket to the child is
        // created with PIPE_WAIT and ConnectNamedPipe
        // is called without an OVERLAPPED structure. If the child exits, crashes,
        // or is a program that never opens the pipe, that call blocks forever and
        // the parent hangs with no way to recover.
        //
        // Run SpawnProcess on a detached thread so the test can time out instead of
        // hanging the whole suite. The thread is detached rather than joined because
        // a hung SpawnProcess is never joinable; the state it touches is therefore
        // shared by value, and the leaked thread is reclaimed at process exit.
        // Either returning or throwing counts as a pass: the requirement is only
        // that it does not block indefinitely.
        auto done{std::make_shared<std::atomic<bool>>(false)};
    
        std::thread spawn([done] {
            try {
                const auto [process, socket]{SpawnProcess([](std::string connect_info) -> std::vector<std::string> {
                    // A child that runs to completion without ever opening the pipe
                    // named by connect_info.
                    return {"cmd.exe", "/c", "exit 0"};
                })};
                closesocket(socket);
                CloseHandle(process);
            } catch (...) {
                // SpawnProcess reporting an error is an acceptable outcome; only
                // blocking forever is not.
            }
            done->store(true);
        });
        spawn.detach();
    
        const auto deadline{std::chrono::steady_clock::now() + FAILURE_TIMEOUT};
        while (!done->load() && std::chrono::steady_clock::now() < deadline) {
            std::this_thread::sleep_for(std::chrono::milliseconds{10});
        }
    
        KJ_EXPECT(done->load(), "SpawnProcess blocked waiting for a child that never connected");
    }
    

    ryanofsky commented at 3:33 AM on August 5, 2026:

    re: #231 (review)

    Thanks! Added this test and a change to detect this in error in a new commit. I think this case would most likely arise in practice as a result of a bug, but good to show an error instead of hanging if this happens.

  62. in src/mp/util.cpp:259 in 7dcb54db4b
     252 | @@ -236,44 +253,111 @@ std::tuple<ProcessId, SocketId> SpawnProcess(const std::function<std::vector<std
     253 |          _exit(127);
     254 |      }
     255 |      return {pid, fds[1]};
     256 | +#else
     257 | +    // Create windows pipe to send socket over to child process.
     258 | +    static std::atomic<int> counter{1};
     259 | +    std::string pipe_path{"\\\\.\\pipe\\mp-" + std::to_string(GetCurrentProcessId()) + "-" + std::to_string(counter.fetch_add(1))};
    


    ViniciusCestarii commented at 7:10 PM on August 3, 2026:

    In "util: Add Windows support" 7dcb54db4bb707009081ab358c9a247a43d577fb

    nit: R"()" here too, to match the util_tests.cpp

        std::string pipe_path{R"(\\.\pipe\mp-)" + std::to_string(GetCurrentProcessId()) + "-" + std::to_string(counter.fetch_add(1))};
    

    ryanofsky commented at 3:31 AM on August 5, 2026:

    re: #231 (review)

    Thanks, switched to raw string here

  63. in test/mp/test/listen_tests.cpp:52 in 749e76a530


    ViniciusCestarii commented at 12:57 PM on August 4, 2026:

    In "test: fix listen_tests to compile and run on Windows" 749e76a53047b5933ea9dd4aa2947d5a34f341b8

    nit: TCP here isn't just a Wine workaround, it's what kj win32Socketpair uses on Windows, so the test matches the real transport.


    ryanofsky commented at 3:29 AM on August 5, 2026:

    re: #231 (review)

    nit: TCP here isn't just a Wine workaround, it's what kj win32Socketpair uses on Windows, so the test matches the real transport.

    That's a good observation, and the the windows code does use TCP sockets for the socketpair and spawned proceses. But it uses UNIX sockets to make things like -ipcbind and the bitcoin IPC mining interface work. Since this file is supposed to test listening and connecting it would make the most sense for it to test UNIX sockets on all platforms so the choice to use TCP here really is just a workaround for wine. Updated the comment to be clear that UNIX sockets do work on windows, and this workaround mostly exists for wine


    ViniciusCestarii commented at 12:25 PM on August 5, 2026:

    Thanks for the explanation. I had forgotten the -ipcbind uses AF_UNIX even on Windows, so testing UNIX sockets does make more sense here.

  64. in test/mp/test/listen_tests.cpp:44 in 493a4b074c
      38 | @@ -39,6 +39,19 @@
      39 |  #include <sys/un.h>
      40 |  #endif
      41 |  
      42 | +#ifdef WIN32
      43 | +// Call WSAStartup before any test runs. Winsock requires WSAStartup before any
      44 | +// socket call; the mp library calls it inside ConnectSocketToProcess(), but
    


    ViniciusCestarii commented at 1:13 PM on August 4, 2026:

    In "test: Initialize Winsock in listen_tests.cpp on Windows" 493a4b074c34d4819b14ae2042e96ec44c2842c2

    nit: this comment and the commit message mentions ConnectSocketToProcess but it doens't exist in the codebase. The WSAStartup call is in StartSpawned()

    // socket call; the mp library calls it inside StartSpawned(), but
    

    ryanofsky commented at 3:30 AM on August 5, 2026:

    re: #231 (review)

    nit: this comment and the commit message mentions ConnectSocketToProcess but it doens't exist in the codebase. The WSAStartup call is in StartSpawned()

    Good catch I think that referred to an older version of the code

  65. ViniciusCestarii commented at 1:39 PM on August 4, 2026: contributor

    Approach ACK b7e367622070a05d3cb14b8e6f06b2f2259ab0b1.

    Looking good, build locally with mingw and ran tests and examples with wine.

    I found a couple of issues in SpawnProcess that I think are worth addressing and left some nits.

  66. SpawnProcess on Windows creates a named pipe with PIPE_WAIT and then calls
    ConnectNamedPipe synchronously. If the child exits or crashes before
    connecting, ConnectNamedPipe blocks forever with no recovery path.
    
    Fix by opening the pipe with FILE_FLAG_OVERLAPPED and using
    WaitForMultipleObjects on both the connect event and the child process
    handle. If the process handle signals first, the child died without
    connecting and SpawnProcess throws instead of hanging. Since the pipe is
    now in overlapped mode, WriteFile also requires an OVERLAPPED structure;
    use GetOverlappedResult with bWait=TRUE to handle both synchronous and
    asynchronous completion.
    
    Add a Windows-only test that spawns a child which exits immediately
    without opening the named pipe and asserts SpawnProcess does not block.
    
    (https://github.com/bitcoin-core/libmultiprocess/pull/231#discussion_r3706021950)
    
    Co-Authored-By: ViniciusCestarii <viniciuscestari01@gmail.com>
    Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
    dbdc118d8d
  67. util: make pthreads optional on Windows to enable MSVC builds
    Allow code to compile without pthreads available, as required for MSVC
    compatibility. Avoid unconditional POSIX calls (fork, posix_spawn,
    pthread_getname_np) by moving them into #ifndef WIN32 or HAVE_PTHREAD_*
    guards. When pthreads is available on Windows (detected via cmake
    HAVE_PTHREAD_* checks), still use it for thread name reporting since it
    provides useful information at low cost.
    
    Also add Threads::Threads as an explicit dependency of the multiprocess
    library. proxy.cpp directly uses thread_local, std::this_thread, and
    std::thread, and the dependency was previously satisfied only through
    transitive linkage from CapnProto::kj-async.
    
    Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
    0088657950
  68. test: fix listen_tests to compile and run on Windows
    Replace POSIX-only headers (sys/socket.h, sys/un.h, unistd.h) with
    Windows equivalents (afunix.h via util.h), guard them with #ifdef WIN32,
    use TCP sockets instead of Unix sockets for Wine compatibility, replace
    mkdtemp/unlink/rmdir with std::filesystem equivalents, and use
    SocketId/SocketError types instead of int/-1 for socket handles so the
    file compiles and works with MinGW.
    
    Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
    0b13104b7b
  69. test: Initialize Winsock in listen_tests.cpp on Windows
    listen_tests.cpp tests fail on Windows with:
      "expected m_fd != SocketError [18446744073709551615 != 18446744073709551615]"
    
    socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) returns INVALID_SOCKET because
    WSAStartup() has not been called. The mp library calls WSAStartup() only inside
    ConnectSocketToProcess(), which listen_tests.cpp never reaches — it creates
    sockets directly using the BSD API.
    
    Fix: add a static initializer that calls WSAStartup(MAKEWORD(2,2), ...) at
    program startup before any test runs.
    
    Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
    d361fc3875
  70. ci: add Windows cross-compilation config using MinGW and Wine
    - shell.nix: add `windows` parameter that selects pkgs.pkgsCross.mingwW64
      as the cross target; also change crossPkgs default from import<nixpkgs>{}
      to null (cleaner API). When windows=true, add native pkgs.capnproto to
      nativeBuildInputs so capnp/capnpc-c++ are in PATH for cmake code generation,
      and add wine64Packages.staging so ctest can run mptest.exe via wine.
      Change llvmBase to always use pkgs (native) instead of crossPkgs.
    
    - ci/configs/windows.bash: new config that cross-compiles with mingw,
      sets CMAKE_SYSTEM_NAME=Windows, CMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER
      (so cmake finds native capnp from PATH), CMAKE_CROSSCOMPILING_EMULATOR=wine
      (so ctest runs mptest.exe via wine), and sets MPGEN_PRE_BUILD=1.
    
    - ci/scripts/ci.sh: add MPGEN_PRE_BUILD support: when set, build native mpgen
      in $CI_DIR-native before the main cross build, then inject
      -DMPGEN_EXECUTABLE into CMAKE_ARGS. This is needed because cmake's
      add_custom_command does not use CMAKE_CROSSCOMPILING_EMULATOR, so the
      cross-compiled mpgen.exe cannot be used as a code generator directly.
    
    Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
    19f7d315a5
  71. ryanofsky referenced this in commit d541023c6d on Aug 5, 2026
  72. ryanofsky force-pushed on Aug 5, 2026
  73. ryanofsky commented at 3:41 AM on August 5, 2026: collaborator

    <!-- begin push-15 -->

    Updated b7e367622070a05d3cb14b8e6f06b2f2259ab0b1 -> be00288b992590ff29f96eeb1ee3247147600a41 (pr/win.14 -> pr/win.15, compare)<!-- end --> with suggested changes. Also fixed pthreads include to avoid pthread_self compile error in mingw builds where pthreads is present, as described in #318 (comment)

    <!-- begin push-16 -->

    Updated be00288b992590ff29f96eeb1ee3247147600a41 -> ad7562e9383065e161d88df9fed9aaae0ce06ab2 (pr/win.15 -> pr/win.16, compare)<!-- end --> to fix IWYU errors: add <unistd.h> to listen_tests.cpp, move <atomic> inside #ifdef WIN32 and add <functional> in spawn_tests.cpp https://github.com/bitcoin-core/libmultiprocess/actions/runs/30972705059/job/92200276090

    <!-- begin push-17 -->

    Rebased ad7562e9383065e161d88df9fed9aaae0ce06ab2 -> 19f7d315a5dc547dce2258541decfb6db984b657 (pr/win.16 -> pr/win.17, compare)<!-- end --> to fix silent conflict with #310 https://github.com/bitcoin-core/libmultiprocess/actions/runs/30974304265/job/92205053288?pr=231

  74. ryanofsky referenced this in commit b2653a6a99 on Aug 5, 2026
  75. ryanofsky force-pushed on Aug 5, 2026
  76. ryanofsky force-pushed on Aug 5, 2026

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin-core/libmultiprocess. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-08-05 21:30 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me