diff --git a/cabal-testsuite/src/Test/Cabal/Monad.hs b/cabal-testsuite/src/Test/Cabal/Monad.hs index 38534402d26..04771018cbf 100644 --- a/cabal-testsuite/src/Test/Cabal/Monad.hs +++ b/cabal-testsuite/src/Test/Cabal/Monad.hs @@ -402,8 +402,8 @@ runTestM mode m = testSkipSetupTests = argSkipSetupTests (testCommonArgs args), testHaveCabalShared = runnerWithSharedLib senv, testEnvironment = - -- Try to avoid Unicode output - [ ("LC_ALL", Just "C") + -- Use UTF-8 output on all platforms. + [ ("LC_ALL", Just "en_US.UTF-8") -- Hermetic builds (knot-tied) , ("HOME", Just (testHomeDir env)) -- Set CABAL_DIR in addition to HOME, since HOME has no diff --git a/cabal-testsuite/src/Test/Cabal/Run.hs b/cabal-testsuite/src/Test/Cabal/Run.hs index 37b27e9edf3..498c14ded23 100644 --- a/cabal-testsuite/src/Test/Cabal/Run.hs +++ b/cabal-testsuite/src/Test/Cabal/Run.hs @@ -54,6 +54,29 @@ runAction _verbosity mb_cwd env_overrides path0 args input action = do mb_env <- getEffectiveEnvironment env_overrides putStrLn $ "+ " ++ showCommandForUser path args (readh, writeh) <- createPipe + + -- `System.Process.createPipe` calls (through many intermediaries) + -- `GHC.IO.Handle.FD.fdToHandle`, whose documentation says: + -- + -- > Makes a binary Handle. This is for historical reasons; it should + -- > probably be a text Handle with the default encoding and newline + -- > translation instead. + -- + -- The documentation for `System.IO.hSetBinaryMode` says: + -- + -- > This has the same effect as calling `hSetEncoding` with `char8`, together + -- > with `hSetNewlineMode` with `noNewlineTranslation`. + -- + -- But this is a lie, and Unicode written to or read from binary handles is + -- always encoded or decoded as Latin-1, which is always the wrong choice. + -- + -- Therefore, we explicitly set the output to UTF-8 to keep it consistent + -- between platforms and correct on all modern computers. + -- + -- See: https://gitlab.haskell.org/ghc/ghc/-/issues/25307 + hSetEncoding readh utf8 + hSetEncoding writeh utf8 + hSetBuffering readh LineBuffering hSetBuffering writeh LineBuffering let drain = do