Use Extra library
[hadrian.git] / src / Rules / Libffi.hs
1 module Rules.Libffi (libffiRules, libffiDependencies) where
2
3 import Base
4 import Expression
5 import Extra (replace)
6 import GHC
7 import Oracles
8 import Rules.Actions
9 import Settings.Builders.Common
10 import Settings.Packages.Rts
11 import Settings.TargetDirectory
12 import Settings.User
13
14 rtsBuildPath :: FilePath
15 rtsBuildPath = targetPath Stage1 rts -/- "build"
16
17 libffiDependencies :: [FilePath]
18 libffiDependencies = (rtsBuildPath -/-) <$> [ "ffi.h", "ffitarget.h" ]
19
20 libffiBuild :: FilePath
21 libffiBuild = "libffi/build"
22
23 libffiLibrary :: FilePath
24 libffiLibrary = libffiBuild -/- "inst/lib/libffi.a"
25
26 libffiMakefile :: FilePath
27 libffiMakefile = libffiBuild -/- "Makefile.in"
28
29 fixLibffiMakefile :: String -> String
30 fixLibffiMakefile = unlines . map
31 ( replace "-MD" "-MMD"
32 . replace "@toolexeclibdir@" "$(libdir)"
33 . replace "@INSTALL@" "$(subst ../install-sh,C:/msys/home/chEEtah/ghc/install-sh,@INSTALL@)"
34 ) . lines
35
36 target :: PartialTarget
37 target = PartialTarget Stage0 libffi
38
39 -- TODO: remove code duplication (see Settings/Builders/GhcCabal.hs)
40 configureEnvironment :: Action [CmdOption]
41 configureEnvironment = do
42 cFlags <- interpretPartial target . fromDiffExpr $ mconcat
43 [ cArgs
44 , argStagedSettingList ConfCcArgs ]
45 ldFlags <- interpretPartial target $ fromDiffExpr ldArgs
46 sequence [ builderEnv "CC" $ Gcc Stage1
47 , builderEnv "CXX" $ Gcc Stage1
48 , builderEnv "LD" Ld
49 , builderEnv "AR" Ar
50 , builderEnv "NM" Nm
51 , builderEnv "RANLIB" Ranlib
52 , return . AddEnv "CFLAGS" $ unwords cFlags ++ " -w"
53 , return . AddEnv "LDFLAGS" $ unwords ldFlags ++ " -w" ]
54 where
55 builderEnv var builder = do
56 needBuilder False builder
57 path <- builderPath builder
58 return $ AddEnv var path
59
60 configureArguments :: Action [String]
61 configureArguments = do
62 top <- topDirectory
63 targetPlatform <- setting TargetPlatform
64 return [ "--prefix=" ++ top ++ "/libffi/build/inst"
65 , "--libdir=" ++ top ++ "/libffi/build/inst/lib"
66 , "--enable-static=yes"
67 , "--enable-shared=no" -- TODO: add support for yes
68 , "--host=" ++ targetPlatform ]
69
70 libffiRules :: Rules ()
71 libffiRules = do
72 libffiDependencies &%> \_ -> do
73 when trackBuildSystem $ need [sourcePath -/- "Rules/Libffi.hs"]
74 liftIO $ removeFiles libffiBuild ["//*"]
75 tarballs <- getDirectoryFiles "" ["libffi-tarballs/libffi*.tar.gz"]
76 when (length tarballs /= 1) $
77 putError $ "libffiRules: exactly one libffi tarball expected"
78 ++ "(found: " ++ show tarballs ++ ")."
79
80 need tarballs
81 build $ fullTarget target Tar tarballs ["libffi-tarballs"]
82
83 let libname = dropExtension . dropExtension . takeFileName $ head tarballs
84 moveDirectory ("libffi-tarballs" -/- libname) libffiBuild
85
86 fixFile libffiMakefile fixLibffiMakefile
87
88 forM_ ["config.guess", "config.sub"] $ \file ->
89 copyFile file (libffiBuild -/- file)
90
91 envs <- configureEnvironment
92 args <- configureArguments
93 runConfigure libffiBuild envs args
94
95 runMake libffiBuild ["MAKEFLAGS="]
96 runMake libffiBuild ["MAKEFLAGS=", "install"]
97
98 forM_ ["ffi.h", "ffitarget.h"] $ \file -> do
99 let src = libffiBuild -/- "inst/lib" -/- libname -/- "include" -/- file
100 copyFile src (rtsBuildPath -/- file)
101
102 libffiName <- rtsLibffiLibraryName
103 copyFile libffiLibrary (rtsBuildPath -/- "lib" ++ libffiName <.> "a")
104
105 putSuccess $ "| Successfully built custom library 'libffi'"
106
107 -- chmod +x libffi/ln
108 -- # wc on OS X has spaces in its output, which libffi's Makefile
109 -- # doesn't expect, so we tweak it to sed them out
110 -- mv libffi/build/Makefile libffi/build/Makefile.orig
111 -- sed "s#wc -w#wc -w | sed 's/ //g'#" < libffi/build/Makefile.orig > libffi/build/Makefile