1

When using parallel builds in shake, i get malformed output like this:

[»] Compiling src/Game/Game.cpp
[»] Compiling [»] Compiling [»] Compiling src/Graphics/Image/Png/PngLoader.cpp
src/Main.cpp
src/System/HeartBeat.cpp
[»] Compiling src/Window/Window.cpp
[»] Compiling src/Window/GlfwContext.cpp

I suppose that it is some kind of synchronization problem with my printing. I should note that i am using the following as an output command:

shakeOutput = const $ BS.putStr . BS.pack

And the status message printing section my rules looks like this:

liftIO $ setSGR [SetColor Foreground Vivid Green]
putNormal "[\175] Compiling "
liftIO $ setSGR [SetColor Foreground Vivid Yellow]
putNormal $ c ++ "\n"
liftIO $ setSGR [Reset]

Is there a way to avoid that kind of printing problems with my output built in in shake? If not what kind of haskell syncronization method would be appropriate to use, knowing that the printing code is inside a shake rule?

Fr0stBit
  • 1,455
  • 1
  • 13
  • 22

2 Answers2

1

The reason shakeOutput defaults to const $ BS.putStr . BS.pack is because the BS.putStr takes the Haskell console lock, and thus ensures output isn't interleaved. I don't believe this is a contractual guarantee of BS.putStr, but if it ever stops being so, I will add a lock around shakeOutput by default. There are two approaches to fix the problem:

Add a lock

One approach is to add a lock, ideally a renterant Mutex (not something I've seen in Haskell already, but can be synthesised relatively easily on top of MVar and myThreadId). Then you make shakeOutput take the lock, and in your snippets which call shakeOutput multiple times you also take the lock around the entire block. The Mutex probably wants to be stored in a top-level unsafePerformIO CAF.

Use a single shakeOutput call

Since shakeOutput is already atomic you can just reuse that property by rewriting your code as:

putNormal $
    setSGRCode [SetColor Foreground Vivid Green] ++
    "[\175] Compiling " ++
     setSGRCode [SetColor Foreground Vivid Yellow] ++
     c ++ "\n" ++
     setSGRCode [Reset]

I'd encourage the second approach, since it's much simpler, and also makes sure that if the verbosity is turned to quiet the codes don't still get printed.

Neil Mitchell
  • 9,090
  • 1
  • 27
  • 85
  • If you do decide to go the first approach, and have difficulties with either of the two "bits" in it (the recursive mutex or the CAF) do ping me and I'll happily expand, but I don't want to complicate the answer going off on tangents I recommend people don't take :) – Neil Mitchell Nov 13 '15 at 13:36
  • I fixed the problem by using an MVar as a mutex, but your second solution just seems superb to me! Nice find on the setSGRCode function, i don't know why i missed it. – Fr0stBit Nov 13 '15 at 13:43
0

My approach was to use resources:

con <- newResource "Console" 1
let withConsole = withResource con 1 . liftIO
clavijo
  • 77
  • 6