-- really fragile hack to build the assembly code into the library
-- unfortunately, cabal is not exactly helpful for this task, so to speak...
{-# LANGUAGE CPP #-}
import Control.Monad
import Data.Maybe
import Distribution.Simple
import Distribution.Simple.Setup
import Distribution.Simple.UserHooks
import Distribution.Simple.LocalBuildInfo
import Distribution.Simple.Program
import Distribution.PackageDescription
import System.Process -- System.Cmd
import System.Exit
import System.FilePath
import System.Directory
--------------------------------------------------------------------------------
-- * system-dependent configuration
data OS
= Linux
| Windows
| MacOSX
deriving (Eq,Show)
data CallConv
= CDecl
| Win64
| SystemV
deriving (Eq,Show)
host_bits :: Int
#if defined i386_HOST_ARCH
host_bits = 32
#elif defined x86_64_HOST_ARCH
host_bits = 64
#else
#error cannot figure out host architecture (for nasm)
#endif
host_os :: OS
#if defined mingw32_HOST_OS
host_os = Windows
#elif defined linux_HOST_OS
host_os = Linux
#elif defined darwin_HOST_OS
host_os = MacOSX
#else
#error cannot figure out target operating system (for nasm)
#endif
objfmt :: String
objfmt = case host_os of
Windows -> "-fwin" ++ show host_bits
Linux -> "-felf" ++ show host_bits
MacOSX -> "-fmacho" ++ show host_bits
callConv :: CallConv
callConv = case host_bits of
32 -> CDecl
64 -> case host_os of
Windows -> Win64
_ -> SystemV
--------------------------------------------------------------------------------
mySubDir :: FilePath
mySubDir = "Bitcoin/Crypto/cbits/"
theFlags :: LocalBuildInfo -> FlagAssignment
theFlags lbi = configConfigurationsFlags $ configFlags lbi
doCompileWithAsm :: LocalBuildInfo -> Bool
doCompileWithAsm lbi =
case lookup (FlagName "x86asm") (theFlags lbi) of
Nothing -> False
Just b -> b
targetDir :: LocalBuildInfo -> FilePath
targetDir lbi = buildDir lbi </> mySubDir
--------------------------------------------------------------------------------
myBuildHook pkgdesc localbuildinfo userhooks buildflags = do
when (doCompileWithAsm localbuildinfo) $ do
putStrLn "now trying to run nasm to compile our sweet hand-written assembly code..."
let nasmpath = "nasm"
findExecutable nasmpath >>= \mb -> case mb of
Nothing -> error "nasm executable not found in path - either install it or use the cabal flag -f-X86ASM"
Just p -> putStrLn $ "nasm executable is: " ++ p
let srcdir = "." </> mySubDir
tgtdir = targetDir localbuildinfo
createDirectoryIfMissing True tgtdir -- in a clean build, the dist/build directory doesn't exist yet...
let dcallconv = case callConv of
CDecl -> "-DCALLCONV_CDECL"
Win64 -> "-DCALLCONV_WIN64"
SystemV -> "-DCALLCONV_SYSTEMV"
let asmsrc = case host_bits of
32 -> srcdir </> "asm_modp_x86.asm"
64 -> srcdir </> "asm_modp_x64.asm"
let objfile = case host_bits of
32 -> tgtdir </> "asm_modp_x86.o"
64 -> tgtdir </> "asm_modp_x64.o"
let cmd = unwords [ nasmpath , objfmt , dcallconv , asmsrc , "-o" , objfile ]
exitcode <- system cmd
case exitcode of
ExitSuccess -> return ()
ExitFailure k -> error ("nasm failed with exist code " ++ show k)
{-
putStrLn "now let's create a library out of the object file..."
let cmd = unwords ["ar", "rcs" , tgtdir </> "libmodp.a" , tgtdir </> "asm_modp.o" ]
exitcode <- system cmd
case exitcode of
ExitSuccess -> return ()
ExitFailure k -> error ("ar failed with exist code " ++ show k)
-}
-- print localbuildinfo
(buildHook simpleUserHooks) pkgdesc localbuildinfo userhooks buildflags
--------------------------------------------------------------------------------
myConfHook (genpkgdesc,hookbuildinfo) cfgflags = do
lbi <- (confHook simpleUserHooks) (genpkgdesc,hookbuildinfo) cfgflags
print $ theFlags lbi
putStrLn $ "word size: " ++ show host_bits ++ " bits"
putStrLn $ "obj format: " ++ objfmt
if (not $ doCompileWithAsm lbi)
then return lbi
else do
putStrLn "now trying configure this mess to use our object file later on..."
let lpd = localPkgDescr lbi
lib = fromJust (library lpd)
libbi = libBuildInfo lib
let tgtdir = targetDir lbi
createDirectoryIfMissing True tgtdir -- in a clean build, the dist/build directory doesn't exist yet...
fulltgtdir <- canonicalizePath tgtdir -- this may fail if the directory does not exist???
let objfile = case host_bits of
32 -> fulltgtdir </> "asm_modp_x86.o"
64 -> fulltgtdir </> "asm_modp_x64.o"
-- now, seriously, cabal please...
let progconf = withPrograms lbi
progconf' = userSpecifyArgs "ar" [objfile]
$ userSpecifyArgs "ld" [objfile]
$ progconf
libbi' = libbi
{-
let libbi' = libbi { ldOptions = ldOptions libbi ++ [objfile] }
let libbi' = libbi { options = options libbi ++ [(GHC,[objfile])] }
let libbi' = libbi
{ extraLibs = extraLibs libbi ++ ["modp"]
, extraLibDirs = extraLibDirs libbi ++ [fulltgtdir]
}
-}
-- print libbi'
let lib' = lib { libBuildInfo = libbi' }
lpd' = lpd { library = Just lib' }
return $ lbi { localPkgDescr = lpd' , withPrograms = progconf' }
--------------------------------------------------------------------------------
main :: IO ()
main = do
defaultMainWithHooks $ simpleUserHooks { confHook = myConfHook , buildHook = myBuildHook }