1
1
mirror of https://github.com/anoma/juvix.git synced 2024-12-16 02:22:25 +03:00
juvix/app/Commands/Extra/Compile.hs

215 lines
7.3 KiB
Haskell
Raw Normal View History

2022-12-06 13:33:20 +03:00
module Commands.Extra.Compile where
import Commands.Base
import Commands.Extra.Compile.Options
import Data.ByteString qualified as BS
import Data.FileEmbed qualified as FE
import Juvix.Extra.Paths
import System.Environment
import System.Process qualified as P
runCommand :: forall r. (Members '[Embed IO, App] r) => CompileOptions -> Sem r ()
2022-12-06 13:33:20 +03:00
runCommand opts = do
inputFile <- fromAppPathFile (opts ^. compileInputFile)
result <- runCompile inputFile opts
2022-12-06 13:33:20 +03:00
case result of
Left err -> printFailureExit err
_ -> return ()
runCompile ::
(Members '[App, Embed IO] r) =>
Path Abs File ->
CompileOptions ->
Sem r (Either Text ())
runCompile inputFile o = do
buildDir <- askBuildDir
ensureDir buildDir
ensureDir (juvixIncludeDir buildDir)
prepareRuntime buildDir o
2022-12-06 13:33:20 +03:00
case o ^. compileTarget of
2022-12-20 15:05:40 +03:00
TargetWasm32Wasi -> runError (clangWasmWasiCompile inputFile o)
TargetNative64 -> runError (clangNativeCompile inputFile o)
TargetGeb -> return $ Right ()
TargetVampIR -> return $ Right ()
TargetCore -> return $ Right ()
TargetAsm -> return $ Right ()
2022-12-06 13:33:20 +03:00
prepareRuntime :: forall r. (Members '[App, Embed IO] r) => Path Abs Dir -> CompileOptions -> Sem r ()
prepareRuntime buildDir o = do
2022-12-06 13:33:20 +03:00
mapM_ writeHeader headersDir
case o ^. compileTarget of
TargetWasm32Wasi | o ^. compileDebug -> writeRuntime wasiDebugRuntime
TargetWasm32Wasi -> writeRuntime wasiReleaseRuntime
TargetNative64 | o ^. compileDebug -> writeRuntime nativeDebugRuntime
TargetNative64 -> writeRuntime nativeReleaseRuntime
TargetGeb -> return ()
TargetVampIR -> return ()
TargetCore -> return ()
TargetAsm -> return ()
2022-12-06 13:33:20 +03:00
where
wasiReleaseRuntime :: BS.ByteString
wasiReleaseRuntime = $(FE.makeRelativeToProject "runtime/_build.wasm32-wasi/libjuvix.a" >>= FE.embedFile)
nativeReleaseRuntime :: BS.ByteString
nativeReleaseRuntime = $(FE.makeRelativeToProject "runtime/_build.native64/libjuvix.a" >>= FE.embedFile)
wasiDebugRuntime :: BS.ByteString
wasiDebugRuntime = $(FE.makeRelativeToProject "runtime/_build.wasm32-wasi-debug/libjuvix.a" >>= FE.embedFile)
nativeDebugRuntime :: BS.ByteString
nativeDebugRuntime = $(FE.makeRelativeToProject "runtime/_build.native64-debug/libjuvix.a" >>= FE.embedFile)
2022-12-20 15:05:40 +03:00
writeRuntime :: BS.ByteString -> Sem r ()
2022-12-06 13:33:20 +03:00
writeRuntime =
2022-12-20 15:05:40 +03:00
embed
. BS.writeFile (toFilePath (buildDir <//> $(mkRelFile "libjuvix.a")))
2022-12-06 13:33:20 +03:00
2022-12-20 15:05:40 +03:00
headersDir :: [(Path Rel File, BS.ByteString)]
headersDir = map (first relFile) $(FE.makeRelativeToProject "runtime/include" >>= FE.embedDir)
includeDir :: Path Abs Dir
includeDir = juvixIncludeDir buildDir
2022-12-20 15:05:40 +03:00
writeHeader :: (Path Rel File, BS.ByteString) -> Sem r ()
writeHeader (filePath, contents) = embed $ do
ensureDir (includeDir <//> parent filePath)
BS.writeFile (toFilePath (includeDir <//> filePath)) contents
2022-12-06 13:33:20 +03:00
outputFile :: forall r. Member App r => CompileOptions -> Path Abs File -> Sem r (Path Abs File)
outputFile opts inputFile =
maybe defaultOutputFile fromAppPathFile (opts ^? compileOutputFile . _Just)
where
defaultOutputFile :: Sem r (Path Abs File)
defaultOutputFile = do
invokeDir <- askInvokeDir
let baseOutputFile = invokeDir <//> filename inputFile
return $ case opts ^. compileTarget of
TargetNative64 ->
if
| opts ^. compileCOutput -> replaceExtension' ".c" inputFile
| opts ^. compilePreprocess -> addExtension' ".c" (addExtension' ".out" (removeExtension' inputFile))
| opts ^. compileAssembly -> replaceExtension' ".s" inputFile
| otherwise -> removeExtension' baseOutputFile
TargetWasm32Wasi ->
if
| opts ^. compileCOutput -> replaceExtension' ".c" inputFile
| opts ^. compilePreprocess -> addExtension' ".c" (addExtension' ".out" (removeExtension' inputFile))
| opts ^. compileAssembly -> replaceExtension' ".wat" inputFile
| otherwise -> replaceExtension' ".wasm" baseOutputFile
TargetGeb ->
if
| opts ^. compileTerm -> replaceExtension' ".geb" inputFile
| otherwise -> replaceExtension' ".lisp" baseOutputFile
TargetVampIR ->
replaceExtension' ".pir" baseOutputFile
TargetCore ->
replaceExtension' ".jvc" baseOutputFile
TargetAsm ->
replaceExtension' ".jva" baseOutputFile
2022-12-06 13:33:20 +03:00
clangNativeCompile ::
forall r.
(Members '[App, Embed IO, Error Text] r) =>
2022-12-20 15:05:40 +03:00
Path Abs File ->
2022-12-06 13:33:20 +03:00
CompileOptions ->
Sem r ()
2022-12-20 15:05:40 +03:00
clangNativeCompile inputFile o = do
outputFile' <- outputFile o inputFile
buildDir <- askBuildDir
if
| o ^. compileCOutput ->
copyFile inputFile outputFile'
| otherwise ->
runClang (native64Args buildDir o outputFile' inputFile)
2022-12-06 13:33:20 +03:00
clangWasmWasiCompile ::
forall r.
(Members '[App, Embed IO, Error Text] r) =>
2022-12-20 15:05:40 +03:00
Path Abs File ->
2022-12-06 13:33:20 +03:00
CompileOptions ->
Sem r ()
clangWasmWasiCompile inputFile o = do
outputFile' <- outputFile o inputFile
buildDir <- askBuildDir
if
| o ^. compileCOutput ->
copyFile inputFile outputFile'
| otherwise -> do
clangArgs <- wasiArgs buildDir o outputFile' inputFile <$> sysrootEnvVar
runClang clangArgs
2022-12-06 13:33:20 +03:00
where
2022-12-20 15:05:40 +03:00
sysrootEnvVar :: Sem r (Path Abs Dir)
2022-12-06 13:33:20 +03:00
sysrootEnvVar =
2022-12-20 15:05:40 +03:00
absDir
<$> fromMaybeM (throw msg) (embed (lookupEnv "WASI_SYSROOT_PATH"))
2022-12-06 13:33:20 +03:00
where
msg :: Text
msg = "Missing environment variable WASI_SYSROOT_PATH"
commonArgs :: Path Abs Dir -> CompileOptions -> Path Abs File -> [String]
commonArgs buildDir o outfile =
2022-12-06 13:33:20 +03:00
["-E" | o ^. compilePreprocess]
<> ["-S" | o ^. compileAssembly]
<> (if o ^. compileDebug then ["-DDEBUG"] else ["-DNDEBUG"])
<> [ "-W",
"-Wall",
"-Wno-unused-parameter",
"-Wno-unused-label",
"-Werror",
"-std=c11",
"-I",
toFilePath (juvixIncludeDir buildDir),
2022-12-06 13:33:20 +03:00
"-o",
toFilePath outfile
2022-12-06 13:33:20 +03:00
]
<> ( if
| not (o ^. compilePreprocess || o ^. compileAssembly) ->
[ "-L",
toFilePath buildDir
2022-12-06 13:33:20 +03:00
]
| otherwise -> []
)
native64Args :: Path Abs Dir -> CompileOptions -> Path Abs File -> Path Abs File -> [String]
native64Args buildDir o outfile inputFile =
commonArgs buildDir o outfile
2022-12-06 13:33:20 +03:00
<> [ "-DARCH_NATIVE64",
"-DAPI_LIBC",
"-m64",
"-O3",
2022-12-20 15:05:40 +03:00
toFilePath inputFile
2022-12-06 13:33:20 +03:00
]
<> ( if
| not (o ^. compilePreprocess || o ^. compileAssembly) ->
["-ljuvix"]
| otherwise -> []
)
wasiArgs :: Path Abs Dir -> CompileOptions -> Path Abs File -> Path Abs File -> Path Abs Dir -> [String]
wasiArgs buildDir o outfile inputFile sysrootPath =
commonArgs buildDir o outfile
2022-12-06 13:33:20 +03:00
<> [ "-DARCH_WASM32",
"-DAPI_WASI",
"-Os",
"-nodefaultlibs",
"--target=wasm32-wasi",
"--sysroot",
2022-12-20 15:05:40 +03:00
toFilePath sysrootPath,
toFilePath inputFile
2022-12-06 13:33:20 +03:00
]
<> ( if
| not (o ^. compilePreprocess || o ^. compileAssembly) ->
["-ljuvix"]
| otherwise -> []
)
runClang ::
(Members '[Embed IO, Error Text] r) =>
2022-12-06 13:33:20 +03:00
[String] ->
Sem r ()
runClang args = do
(exitCode, _, err) <- embed (P.readProcessWithExitCode "clang" args "")
case exitCode of
ExitSuccess -> return ()
_ -> throw (pack err)