hspec / silently

Prevent or capture output to stdout or other handles in Haskell
Other
21 stars 5 forks source link

Odd behavior when trying to capture C functions #3

Open mtolly opened 7 years ago

mtolly commented 7 years ago

cfunc.c:

#include <stdio.h>

void cFunc() {
  printf("from C\n");
}

Main.hs:

module Main where

import System.IO.Silently

foreign import ccall unsafe "cFunc"
  cFunc :: IO ()

main :: IO ()
main = do
  capture_ (putStrLn "from haskell") >>= print
  capture_ cFunc >>= print

On my system (macOS 10.12.5, GHC 8.0.2, silently 1.2.5) this produces the output:

"from haskell\n"
""
from C

So I figured that was that, silently only works for Haskell code. Not sure why the C printf comes after the Haskell print but chalked it up to buffering weirdness. But then I modified main to look like this:

main :: IO ()
main = do
  capture_ (putStrLn "from haskell") >>= print
  cFunc
  capture_ cFunc >>= print

And that produces this output:

"from haskell\n"
from C
"from C\n"

So if I have C code print at least once to stdout, then thereafter it can be captured by silently...? I don't understand why at all. Any insight?

andreasabel commented 2 years ago

I can reproduce this as of 2022-08-20 (GHC 9.4.1).
I don't know the FFI enough to be able to comprehend this behavior. But I experienced capture failures of stderr on Windows which I could fix using evaluate. However, in this case evaluate did not help (the cFunc returns (), nothing to evaluate here).

Is there literature how the FFI handles I/O? Didn't find anything...