diff --git a/app/Commands/Doctor.hs b/app/Commands/Doctor.hs index dd6dfba443..585e29eb67 100644 --- a/app/Commands/Doctor.hs +++ b/app/Commands/Doctor.hs @@ -2,9 +2,9 @@ module Commands.Doctor where import Commands.Base hiding (info) import Commands.Doctor.Options -import Commands.Extra.Compile import Data.Aeson import Data.Aeson.TH +import Juvix.Extra.Clang import Juvix.Extra.Version qualified as V import Network.HTTP.Simple import Safe (headMay) diff --git a/app/Commands/Extra/Clang.hs b/app/Commands/Extra/Clang.hs index 47ec021f96..d08476518f 100644 --- a/app/Commands/Extra/Clang.hs +++ b/app/Commands/Extra/Clang.hs @@ -7,9 +7,9 @@ where import Commands.Base import Commands.Compile.CStage import Commands.Extra.Clang.Backend +import Juvix.Extra.Clang import Juvix.Extra.Paths import Juvix.Prelude.Env -import System.Environment import System.Process qualified as P data ClangArgs = ClangArgs @@ -135,42 +135,3 @@ runClang args = do clangNotFoundErr :: Text clangNotFoundErr = "Error: The clang executable was not found. Please install the LLVM toolchain" - -data ClangPath - = ClangSystemPath (Path Abs File) - | ClangEnvVarPath (Path Abs File) - --- | Try searching clang JUVIX_LLVM_DIST_PATH. Otherwise use the PATH -findClang :: (Member EmbedIO r) => Sem r (Maybe ClangPath) -findClang = do - envVarPath <- findClangUsingEnvVar - case envVarPath of - Just p -> return (Just (ClangEnvVarPath p)) - Nothing -> (fmap . fmap) ClangSystemPath findClangOnPath - -findClangUsingEnvVar :: forall r. (Member EmbedIO r) => Sem r (Maybe (Path Abs File)) -findClangUsingEnvVar = do - p <- clangBinPath - join <$> mapM checkExecutable p - where - checkExecutable :: Path Abs File -> Sem r (Maybe (Path Abs File)) - checkExecutable p = whenMaybeM (liftIO (isExecutable p)) (return p) - - clangBinPath :: Sem r (Maybe (Path Abs File)) - clangBinPath = fmap ( $(mkRelFile "bin/clang")) <$> llvmDistPath - - llvmDistPath :: Sem r (Maybe (Path Abs Dir)) - llvmDistPath = liftIO $ do - p <- lookupEnv llvmDistEnvironmentVar - mapM parseAbsDir p - -extractClangPath :: ClangPath -> Path Abs File -extractClangPath = \case - ClangSystemPath p -> p - ClangEnvVarPath p -> p - -llvmDistEnvironmentVar :: String -llvmDistEnvironmentVar = "JUVIX_LLVM_DIST_PATH" - -findClangOnPath :: (Member EmbedIO r) => Sem r (Maybe (Path Abs File)) -findClangOnPath = findExecutable $(mkRelFile "clang") diff --git a/app/Commands/Extra/Compile.hs b/app/Commands/Extra/Compile.hs index 9afa985255..f54ec0ac87 100644 --- a/app/Commands/Extra/Compile.hs +++ b/app/Commands/Extra/Compile.hs @@ -5,6 +5,7 @@ import Commands.Base import Commands.Extra.Compile.Options import Data.ByteString qualified as BS import Data.FileEmbed qualified as FE +import Juvix.Extra.Clang import Juvix.Extra.Paths import System.Environment import System.Process qualified as P @@ -229,42 +230,6 @@ wasiArgs buildDir o outfile inputFile sysrootPath = | otherwise -> [] ) -findClangOnPath :: (Member EmbedIO r) => Sem r (Maybe (Path Abs File)) -findClangOnPath = findExecutable $(mkRelFile "clang") - -findClangUsingEnvVar :: forall r. (Member EmbedIO r) => Sem r (Maybe (Path Abs File)) -findClangUsingEnvVar = do - p <- clangBinPath - join <$> mapM checkExecutable p - where - checkExecutable :: Path Abs File -> Sem r (Maybe (Path Abs File)) - checkExecutable p = whenMaybeM (liftIO (isExecutable p)) (return p) - - clangBinPath :: Sem r (Maybe (Path Abs File)) - clangBinPath = fmap ( $(mkRelFile "bin/clang")) <$> llvmDistPath - - llvmDistPath :: Sem r (Maybe (Path Abs Dir)) - llvmDistPath = liftIO $ do - p <- lookupEnv llvmDistEnvironmentVar - mapM parseAbsDir p - -data ClangPath - = ClangSystemPath (Path Abs File) - | ClangEnvVarPath (Path Abs File) - -extractClangPath :: ClangPath -> Path Abs File -extractClangPath = \case - ClangSystemPath p -> p - ClangEnvVarPath p -> p - ---- Try searching clang JUVIX_LLVM_DIST_PATH. Otherwise use the PATH -findClang :: (Member EmbedIO r) => Sem r (Maybe ClangPath) -findClang = do - envVarPath <- findClangUsingEnvVar - case envVarPath of - Just p -> return (Just (ClangEnvVarPath p)) - Nothing -> (fmap . fmap) ClangSystemPath findClangOnPath - runClang :: forall r. (Members '[App, EmbedIO] r) => @@ -290,6 +255,3 @@ debugClangOptimizationLevel = 1 defaultClangOptimizationLevel :: Int defaultClangOptimizationLevel = 1 - -llvmDistEnvironmentVar :: String -llvmDistEnvironmentVar = "JUVIX_LLVM_DIST_PATH" diff --git a/src/Juvix/Extra/Clang.hs b/src/Juvix/Extra/Clang.hs new file mode 100644 index 0000000000..8ab20cfd75 --- /dev/null +++ b/src/Juvix/Extra/Clang.hs @@ -0,0 +1,75 @@ +module Juvix.Extra.Clang where + +import Juvix.Config qualified as Config +import Juvix.Prelude +import System.Environment +import System.FilePath + +data ClangPath + = ClangSystemPath (Path Abs File) + | ClangEnvVarPath (Path Abs File) + +-- | If the path specified in Config is absolute, try using it. Otherwise, try +-- searching the relative path to clang in JUVIX_LLVM_DIST_PATH. Otherwise use +-- the PATH. +findClang :: (Member EmbedIO r) => Sem r (Maybe ClangPath) +findClang = do + mp <- findClangFromConfig + case mp of + Just p -> return (Just (ClangSystemPath p)) + Nothing -> do + envVarPath <- findClangUsingEnvVar + case envVarPath of + Just p -> return (Just (ClangEnvVarPath p)) + Nothing -> (fmap . fmap) ClangSystemPath findClangOnPath + +checkExecutable :: forall r. (Member EmbedIO r) => Path Abs File -> Sem r (Maybe (Path Abs File)) +checkExecutable p = whenMaybeM (liftIO (isExecutable p)) (return p) + +findClangFromConfig :: forall r. (Member EmbedIO r) => Sem r (Maybe (Path Abs File)) +findClangFromConfig = + if + | isAbsolute clangPath -> do + let p :: Maybe (Path Abs File) + p = parseAbsFile clangPath + join <$> mapM checkExecutable p + | otherwise -> return Nothing + where + clangPath :: FilePath + clangPath = unpack $ Config.config ^. Config.configClang + +findClangRelPath :: Maybe (Path Rel File) +findClangRelPath = parseRelFile (unpack $ Config.config ^. Config.configClang) + +findClangUsingEnvVar' :: forall r. (Member EmbedIO r) => Path Rel File -> Sem r (Maybe (Path Abs File)) +findClangUsingEnvVar' clangRelPath = do + p <- clangBinPath + join <$> mapM checkExecutable p + where + clangBinPath :: Sem r (Maybe (Path Abs File)) + clangBinPath = fmap ( $(mkRelDir "bin") clangRelPath) <$> llvmDistPath + + llvmDistPath :: Sem r (Maybe (Path Abs Dir)) + llvmDistPath = liftIO $ do + p <- lookupEnv llvmDistEnvironmentVar + mapM parseAbsDir p + +findClangUsingEnvVar :: forall r. (Member EmbedIO r) => Sem r (Maybe (Path Abs File)) +findClangUsingEnvVar = + case findClangRelPath of + Just clangRelPath -> findClangUsingEnvVar' clangRelPath + Nothing -> findClangUsingEnvVar' $(mkRelFile "clang") + +extractClangPath :: ClangPath -> Path Abs File +extractClangPath = \case + ClangSystemPath p -> p + ClangEnvVarPath p -> p + +llvmDistEnvironmentVar :: String +llvmDistEnvironmentVar = "JUVIX_LLVM_DIST_PATH" + +findClangOnPath :: (Member EmbedIO r) => Sem r (Maybe (Path Abs File)) +findClangOnPath = + case findClangRelPath of + Just clangRelPath -> findExecutable clangRelPath + Nothing -> findExecutable $(mkRelFile "clang") diff --git a/test/Runtime/Base.hs b/test/Runtime/Base.hs index ab18bc6368..4e6530d469 100644 --- a/test/Runtime/Base.hs +++ b/test/Runtime/Base.hs @@ -3,6 +3,7 @@ module Runtime.Base where import Base import Data.FileEmbed import Juvix.Config qualified as Config +import Juvix.Extra.Clang import System.Process qualified as P clangCompile :: @@ -12,28 +13,27 @@ clangCompile :: (Path Abs File -> IO Text) -> (String -> IO ()) -> IO Text -clangCompile mkClangArgs inputFile outputFile execute step = - withTempDir' - ( \dirPath -> do - let outputFile' = dirPath outputFile - step "C compilation" - P.callProcess - "clang" - (mkClangArgs outputFile' inputFile) - step "Execution" - execute outputFile' - ) +clangCompile mkClangArgs inputFile outputFile execute step = do + mp <- fmap extractClangPath <$> runM findClang + case mp of + Just clangPath -> + withTempDir' + ( \dirPath -> do + let outputFile' = dirPath outputFile + step "C compilation" + P.callProcess + (toFilePath clangPath) + (mkClangArgs outputFile' inputFile) + step "Execution" + execute outputFile' + ) + Nothing -> assertFailure "clang not found" clangAssertion :: Int -> Path Abs File -> Path Abs File -> Text -> ((String -> IO ()) -> Assertion) clangAssertion optLevel inputFile expectedFile stdinText step = do - if - | Config.config ^. Config.configWasm -> do - step "Check clang and wasmer are on path" - assertCmdExists $(mkRelFile "clang") - assertCmdExists $(mkRelFile "wasmer") - | otherwise -> do - step "Check clang is on path" - assertCmdExists $(mkRelFile "clang") + when (Config.config ^. Config.configWasm) $ do + step "Check wasmer is on path" + assertCmdExists $(mkRelFile "wasmer") expected <- readFile expectedFile