createExecutableLink :: FilePath -> FilePath -> FilePath -> Shake.Action ()
createExecutableLink root src dst = liftIO $ do
    srcExists <- doesFileExist src
    unless srcExists . error
        $ src <> ": File not found when trying to create symbolic link: "
        <> dst

    -- We need to force the symlink existence, since the configuration may have
    -- changed.
    dstExists <- doesFileExist dst
    when dstExists $ removeFile dst

    IO.putStrLn $ "Creating symbolic link:\n  " <> src <> " --> "
        <> FilePath.makeRelative root dst <> "\n"
    Posix.createSymbolicLink src dst
createExecutableLink :: FilePath -> FilePath -> FilePath -> Shake.Action ()
createExecutableLink root src dst = liftIO $ do
    srcExists <- doesFileExist src
    unless srcExists . error
        $ src <> ": File not found when trying to create symbolic link: "
        <> dst

    -- We need to force the symlink existence, since the configuration may have
    -- changed.
    dstExists <- doesFileExist dst
    when dstExists $ removeFile dst

    IO.putStrLn $ "Creating symbolic link:\n  " <> src <> " --> "
        <> FilePath.makeRelative root dst <> "\n"
    Posix.createSymbolicLink src dst
createExecutableLink root src dst = liftIO $ do
    srcExists <- doesFileExist src
    unless srcExists . error
        $ src <> ": File not found when trying to create symbolic link: "
        <> dst

    -- We need to force the symlink existence, since the configuration may have
    -- changed.
    dstExists <- doesFileExist dst
    when dstExists $ removeFile dst

    IO.putStrLn $ "Creating symbolic link:\n  " <> src <> " --> "
        <> FilePath.makeRelative root dst <> "\n"
    Posix.createSymbolicLink src dst