flags = fmap (filter (not . null) . lines) . readFile
asum <$> mapM findExecutable cmds
cdir = "src"
incdir = "include"
builddir = "_build"
data BuildTypes = Default | Test | Bench
data OptLevels = Release | Debug
data Options
= BuildType BuildTypes
| OptLevel OptLevels
| DisableCCACHE
| EmitLLVM
| BuildFromASM
| Prefix FilePath
| Runner String
[ Option "t" ["build-type"] (ReqArg (Right . BuildType . read) "default") "[default|test|bench]"
, Option "o" ["opt-level"] (ReqArg (Right . OptLevel . read) "g") "[0-3|g]"
, Option "" ["disable-ccache"] (NoArg $ Right DisableCCACHE) ""
, Option "" ["emit-llvm"] (NoArg $ Right EmitLLVM) ""
, Option "" ["build-from-asm"] (NoArg $ Right BuildFromASM) ""
, Option "p" ["prefix"] (ReqArg (Right . Prefix) "/usr/local") ""
, Option "r" ["runner"] (ReqArg (Right . Runner) "gdb") ""
]
shakeArgsWith shakeOptions options $ \opts targets -> pure $ Just $ do
cwd <- liftIO $ getCurrentDirectory
let proj = takeFileName cwd
gitBranch <- liftIO $ readProcess "git" ["branch", "--show-current"] ""
inNixShell <- liftIO $ System.Environment.getEnv "IN_NIX_SHELL"
cflags <- liftIO $ flags "build/cflags"
ldflags <- liftIO $ flags "build/ldflags"
asmflags <- liftIO $ flags "build/asmflags"
optflags <- liftIO $ flags "build/optflags"
debugflags <- liftIO $ flags "build/debugflags"
optldflags <- liftIO $ flags "build/optldflags"
let typeFlag = [a | BuildType a <- opts] & listToMaybe & fromMaybe Default
let optFlag = [a | OptLevel a <- opts] & listToMaybe & fromMaybe Debug
let prefix = [a | Prefix a <- opts] & listToMaybe & fromMaybe (error "")
let runner = [a | Runner a <- opts]
compile <- do
Just cc <- liftIO $ findExe ["clang-21", "clang-20", "clang-19", "clang"]
ccache <- liftIO $ findExe ["ccache"]
let p DisableCCACHE = True
p _ = False
let disable_ccache = any p opts
case (disable_ccache, ccache) of
(False, Just ch) -> return [ch, cc]
_ -> return [cc]
let typeFlags Default = []
typeFlags Test = ["-DTEST_MODE"]
typeFlags Bench = ["-DBENCHMARK_MODE"]
let optFlags Release = optflags
optFlags Debug = debugflags
let optLDFlags Release = optldflags
optLDFlags Debug = debugflags
let compileFlags = cflags ++ typeFlags typeFlag ++ optFlags optFlag ++ ["-I" ++ incdir]
let linkFlags = ldflags ++ optLDFlags optFlag
let seed = unwords compile ++ unwords compileFlags ++ unwords linkFlags ++ gitBranch ++ inNixShell
let h = abs $ hash seed
let outDir = builddir </> show h
let target = outDir </> proj
let bin = builddir </> proj
want targets
phony "all" $ do
need [bin]
bin %> \out -> do
need [target]
copyFileChanged target out
target %> \out -> do
cs <- getDirectoryFiles cdir ["*.c"]
let os = [outDir </> c -<.> "o" | c <- map takeFileName cs]
need os
cmd_ compile "-o" [out] os linkFlags
outDir </> "*.o" %> \out -> do
let c = cdir </> (takeFileName $ out -<.> "c")
let m = out -<.> "m"
cmd_ compile "-o" [out] "-c" [c] "-MMD -MF" [m] compileFlags
neededMakefileDependencies m
phony "install" $ do
copyFileChanged bin (prefix </> "bin" </> proj)
phony "clear" $ do
liftIO $ removeDirectoryRecursive outDir
phony "clear-all" $ do
liftIO $ removeDirectoryRecursive builddir