1
1
mirror of https://github.com/anoma/juvix.git synced 2024-12-15 01:52:11 +03:00
juvix/test/BackendC/Positive.hs
Paul Cadman cfc11fecc5
Add minic-runtime for linking without libc (#113)
* [minic] Add minic-runtime for linking without libc

The C generated by minic now depends on `minic-runtime.h`. There are two
versions of this, one that depends on libc and one that doesn't (i.e standalone).

The standalone runtime implements the minimal set of functions required for
the tests to compile and run.

The standalone runtime also contains a copy of
https://github.com/wingo/walloc, a small memory allocator that's
indended for use with WASM.

The benefit of using the standalone runtime is that the resulting
binaries are much smaller. For example the Nat example compiles to about
24k WASM binary with libc, the standalone version is 2.8k.

This commit adds a dependency on
https://hackage.haskell.org/package/file-embed for finding the path to
the minic-runtime directory in tests. It does not add any additional
transitive dependencies to the project.
2022-05-19 09:48:23 +02:00

132 lines
3.8 KiB
Haskell

{-# LANGUAGE TemplateHaskell #-}
module BackendC.Positive where
import Base
import Data.FileEmbed
import Data.Text.IO qualified as TIO
import MiniJuvix.Pipeline
import MiniJuvix.Translation.MonoJuvixToMiniC as MiniC
import System.IO.Extra (withTempDir)
import System.Process qualified as P
data PosTest = PosTest
{ _name :: String,
_relDir :: FilePath
}
makeLenses ''PosTest
root :: FilePath
root = "tests/positive/MiniC"
mainFile :: FilePath
mainFile = "Input.mjuvix"
expectedFile :: FilePath
expectedFile = "expected.golden"
testDescr :: PosTest -> TestDescr
testDescr PosTest {..} =
let tRoot = root </> _relDir
in TestDescr
{ _testName = _name,
_testRoot = tRoot,
_testAssertion = Steps $ \step -> do
step "Check clang and wasmer are on path"
assertCmdExists "clang"
assertCmdExists "wasmer"
step "Lookup WASI_SYSROOT_PATH"
sysrootPath <-
assertEnvVar
"Env var WASI_SYSROOT_PATH missing. Set to the location of the wasi-clib sysroot"
"WASI_SYSROOT_PATH"
step "C Generation"
let entryPoint = EntryPoint "." (pure mainFile)
p :: MiniC.MiniCResult <- runIO (upToMiniC entryPoint)
expected <- TIO.readFile expectedFile
step "Compile C with standalone runtime"
actualStandalone <- clangCompile (standaloneArgs sysrootPath) p step
step "Compare expected and actual program output"
assertEqDiff ("check: WASM output = " <> expectedFile) actualStandalone expected
step "Compile C with libc runtime"
actualLibc <- clangCompile (libcArgs sysrootPath) p step
step "Compare expected and actual program output"
assertEqDiff ("check: WASM output = " <> expectedFile) actualLibc expected
}
clangCompile ::
(FilePath -> FilePath -> [String]) ->
MiniC.MiniCResult ->
(String -> IO ()) ->
IO Text
clangCompile mkClangArgs cResult step =
withTempDir
( \dirPath -> do
let cOutputFile = dirPath </> "out.c"
wasmOutputFile = dirPath </> "out.wasm"
TIO.writeFile cOutputFile (cResult ^. MiniC.resultCCode)
step "WASM generation"
P.callProcess
"clang"
(mkClangArgs wasmOutputFile cOutputFile)
step "WASM execution"
pack <$> P.readProcess "wasmer" [wasmOutputFile] ""
)
standaloneArgs :: FilePath -> FilePath -> FilePath -> [String]
standaloneArgs sysrootPath wasmOutputFile cOutputFile =
[ "-nodefaultlibs",
"-I",
takeDirectory minicRuntime,
"--target=wasm32-wasi",
"--sysroot",
sysrootPath,
"-o",
wasmOutputFile,
wallocPath,
cOutputFile
]
where
minicRuntime :: FilePath
minicRuntime = $(makeRelativeToProject "minic-runtime/standalone/minic-runtime.h" >>= strToExp)
wallocPath :: FilePath
wallocPath = $(makeRelativeToProject "minic-runtime/standalone/walloc.c" >>= strToExp)
libcArgs :: FilePath -> FilePath -> FilePath -> [String]
libcArgs sysrootPath wasmOutputFile cOutputFile =
[ "-nodefaultlibs",
"-I",
takeDirectory minicRuntime,
"-lc",
"--target=wasm32-wasi",
"--sysroot",
sysrootPath,
"-o",
wasmOutputFile,
cOutputFile
]
where
minicRuntime :: FilePath
minicRuntime = $(makeRelativeToProject "minic-runtime/libc/minic-runtime.h" >>= strToExp)
allTests :: TestTree
allTests =
testGroup
"Backend C positive tests"
(map (mkTest . testDescr) tests)
tests :: [PosTest]
tests =
[ PosTest "HelloWorld" "HelloWorld",
PosTest "Inductive types and pattern matching" "Nat",
PosTest "Polymorphic types" "Polymorphism",
PosTest "Multiple modules" "MultiModules",
PosTest "Higher Order Functions" "HigherOrder"
]