execute_process: libuv-based implementation breaks PyInstaller executables on Windows
We have a project which uses CMake in Msys2 with Conan and conan_provider.cmake - a script which integrates Conan into CMake.
Since 5420639a, when the script calls execute_process
it no longer launches Conan correctly. Conan is a Python program packaged as an executable using PyInstaller. The stderr handle provided by CMake is no longer accepted by Python.
In detail:
- In an MSYS2 MinGW x64 shell, CMake
execute_process
executesC:\msys64\mingw64\bin\conan.exe
- In the MSYS2 MinGW PyInstaller build of Conan,
conan.exe
is actually simple_launcher (see source code). - In CPython...
- ...the standard IO streams are set up in
init_sys_streams
... - ...which calls
create_stdio
... - ...which calls
is_valid_fd
... - ...which effectively checks
GetFileType(_get_osfhandle(fileno(stderr))) != FILE_TYPE_UNKNOWN
.
- ...the standard IO streams are set up in
Since 5420639a, this test fails causing Python to set sys.stderr
to None
causing widespread errors in Conan.
As an aid to debugging, a simplified test is provided: 20240517-test-cmake-exec-pyinstaller.zip
This test, replaces Conan, Python, PyInstaller and simple_launcher with simple test programs with equivalent behavior. To run the test, create a build directory, and run cmake ..
.
In versions after 5420639a, this message will be shown:
*** GetFileType(_get_osfhandle(fileno(stderr))) is 0.
Python will REJECT this handle!
In prior versions (e.g. b938e7de), this message will be show:
*** GetFileType(_get_osfhandle(fileno(stderr))) is 3.
Python will ACCEPT this handle!
The Makefile
can be used to rebuild the EXE files in an MSYS2 MinGW x64 terminal.
Strangely, if SetHandleInformation(hErr, HANDLE_FLAG_INHERIT, 0);
is removed from the pyinstaller-simple-launcher-replica.c
, the issue is suppressed.