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