Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't introduce unnecessary dependencies for top-level requirements #832

Open
hlverstoep opened this issue Jul 27, 2022 · 2 comments
Open

Comments

@hlverstoep
Copy link

Given:

main = shake shakeOptions $ do
    action $ do
        b <- doesFileExist "file.src"
        when b $ need ["file.out"]
    ...
    action $ do
        need ["file2.out"]

file2.out is now built strictly after file.out (this can be observed during builds, and seen in the report). However, the actions are independent so there should not be a dependency. This is even more confusing if the actions are not defined so close to each other. I suspect actions are aggregated using parallel, which would cause the same behaviour.

If this is difficult to fix, perhaps an alternative style should be suggested in the documentation for actions such that shake can evaluate the actions independently:

main = shake shakeOptions $ do
    want ["toplevel1"]
    phony "toplevel1" $ do
        b <- doesFileExist "file.src"
        when b $ need ["file.out"]
    ...
    want ["toplevel2"]
    phony "toplevel2" $ do
        need ["file2.out"]
@ndmitchell
Copy link
Owner

I don't think this should be true, at least as far as I can tell from running the code (don't have Haskell on this box). Each action is queued into the Shake thread pool independently. Are you sure you are running with shakeThreads at 2 or higher? If you do:

action $ liftIO $ sleep 5
action $ liftIO $ sleep 5

Does that take 5 seconds or 10?

@hlverstoep
Copy link
Author

Ah, you're right. Actually running it works fine. However, the report does show a dependency between the two actions.

More detailed example:

module Main where

import Development.Shake
import Control.Monad (when)
import Extra (sleep, offsetTime)

main :: IO ()
main = do
    ot <- offsetTime
    let log s = liftIO $ do
            t <- ot
            putStrLn $ s <> ": " <> show t
    shakeArgs shakeOptions $ do
        "file-fast.*" %> \out -> do
            alwaysRerun
            writeFile' out ""
        "file-slow.*" %> \out -> do
            alwaysRerun
            liftIO $ sleep 5
            writeFile' out ""
        action $ do
            log "fast-0"
            need ["file-fast.1"]
            log "fast-1"
            need ["file-fast.2"]
            log "fast-2"
        action $ do
            log "slow-0"
            need ["file-slow.1"]
            log "slow-1"

Output:

# stack run -- -j10 --report
slow-0: 5.8205e-3
fast-0: 5.8217e-3
fast-1: 8.7907e-3
fast-2: 1.02942e-2
slow-1: 5.0181621000000005
Writing report to report.html
Build completed in 5.03s

So, fast-2 does indeed finish almost instantly. However, the report shows that fast-2 needs to wait for slow-1 to finish.

Report:
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants