Refactor package-specific settings (#622)
[hadrian.git] / src / Rules / Libffi.hs
1 module Rules.Libffi (libffiRules, libffiDependencies) where
2
3 import GHC
4 import Hadrian.Utilities
5 import Settings.Builders.Common
6 import Target
7 import Utilities
8
9 libffiDependencies :: [FilePath]
10 libffiDependencies = ["ffi.h", "ffitarget.h"]
11
12 libffiLibrary :: FilePath
13 libffiLibrary = "inst/lib/libffi.a"
14
15 rtsLibffiLibrary :: Way -> Action FilePath
16 rtsLibffiLibrary way = do
17 name <- libffiLibraryName
18 suf <- libsuf way
19 rtsPath <- rtsBuildPath
20 return $ rtsPath -/- "lib" ++ name ++ suf
21
22 fixLibffiMakefile :: FilePath -> String -> String
23 fixLibffiMakefile top =
24 replace "-MD" "-MMD"
25 . replace "@toolexeclibdir@" "$(libdir)"
26 . replace "@INSTALL@" ("$(subst ../install-sh," ++ top ++ "/install-sh,@INSTALL@)")
27
28 -- TODO: check code duplication w.r.t. ConfCcArgs
29 configureEnvironment :: Action [CmdOption]
30 configureEnvironment = do
31 cFlags <- interpretInContext libffiContext $ mconcat
32 [ cArgs
33 , getStagedSettingList ConfCcArgs ]
34 ldFlags <- interpretInContext libffiContext ldArgs
35 sequence [ builderEnvironment "CC" $ Cc CompileC Stage1
36 , builderEnvironment "CXX" $ Cc CompileC Stage1
37 , builderEnvironment "LD" (Ld Stage1)
38 , builderEnvironment "AR" (Ar Unpack Stage1)
39 , builderEnvironment "NM" Nm
40 , builderEnvironment "RANLIB" Ranlib
41 , return . AddEnv "CFLAGS" $ unwords cFlags ++ " -w"
42 , return . AddEnv "LDFLAGS" $ unwords ldFlags ++ " -w" ]
43
44 libffiRules :: Rules ()
45 libffiRules = do
46 root <- buildRootRules
47 fmap ((root <//> "rts/build") -/-) libffiDependencies &%> \_ -> do
48 libffiPath <- libffiBuildPath
49 need [libffiPath -/- libffiLibrary]
50
51 -- we set a higher priority because this overlaps
52 -- with the static lib rule from Rules.Library.libraryRules.
53 priority 2.0 $ root <//> libffiLibrary %> \_ -> do
54 useSystemFfi <- flag UseSystemFfi
55 rtsPath <- rtsBuildPath
56 if useSystemFfi
57 then do
58 ffiIncludeDir <- setting FfiIncludeDir
59 putBuild "| System supplied FFI library will be used"
60 forM_ ["ffi.h", "ffitarget.h"] $ \file ->
61 copyFile (ffiIncludeDir -/- file) (rtsPath -/- file)
62 putSuccess "| Successfully copied system FFI library header files"
63 else do
64 libffiPath <- libffiBuildPath
65 build $ target libffiContext (Make libffiPath) [] []
66
67 hs <- getDirectoryFiles "" [libffiPath -/- "inst/include/*"]
68 forM_ hs $ \header ->
69 copyFile header (rtsPath -/- takeFileName header)
70
71 ways <- interpretInContext libffiContext (getLibraryWays <> getRtsWays)
72 forM_ (nubOrd ways) $ \way -> do
73 rtsLib <- rtsLibffiLibrary way
74 copyFileUntracked (libffiPath -/- libffiLibrary) rtsLib
75
76 putSuccess "| Successfully built custom library 'libffi'"
77
78 root <//> "libffi/build/Makefile.in" %> \mkIn -> do
79 libffiPath <- libffiBuildPath
80 removeDirectory libffiPath
81 tarball <- unifyPath . fromSingleton "Exactly one LibFFI tarball is expected"
82 <$> getDirectoryFiles "" ["libffi-tarballs/libffi*.tar.gz"]
83
84 need [tarball]
85 -- Go from 'libffi-3.99999+git20171002+77e130c.tar.gz' to 'libffi-3.99999'
86 let libname = takeWhile (/= '+') $ takeFileName tarball
87
88 root <- buildRoot
89 removeDirectory (root -/- libname)
90 -- TODO: Simplify.
91 actionFinally (do
92 build $ target libffiContext (Tar Extract) [tarball] [root]
93 moveDirectory (root -/- libname) libffiPath) $
94 removeFiles root [libname <//> "*"]
95
96 top <- topDirectory
97 fixFile mkIn (fixLibffiMakefile top)
98
99 -- TODO: Get rid of hard-coded @libffi@.
100 root <//> "libffi/build/Makefile" %> \mk -> do
101 need [mk <.> "in"]
102 libffiPath <- libffiBuildPath
103 forM_ ["config.guess", "config.sub"] $ \file ->
104 copyFile file (libffiPath -/- file)
105
106 env <- configureEnvironment
107 buildWithCmdOptions env $
108 target libffiContext (Configure libffiPath) [mk <.> "in"] [mk]