Generic library rules (#571)
[ghc.git] / src / Rules / Gmp.hs
1 module Rules.Gmp (
2 gmpRules, gmpBuildPath, gmpObjectsDir, gmpLibraryH
3 ) where
4
5 import Base
6 import Context
7 import GHC
8 import Oracles.Setting
9 import Target
10 import Utilities
11
12 gmpBase :: FilePath
13 gmpBase = pkgPath integerGmp -/- "gmp"
14
15 gmpLibraryInTreeH :: FilePath
16 gmpLibraryInTreeH = "include/gmp.h"
17
18 gmpLibrary :: FilePath
19 gmpLibrary = ".libs/libgmp.a"
20
21 -- | GMP is considered a Stage1 package. This determines GMP build directory.
22 gmpContext :: Context
23 gmpContext = vanillaContext Stage1 integerGmp
24
25 -- TODO: Location of 'gmpBuildPath' is important: it should be outside any
26 -- package build directory, as otherwise GMP's object files will match build
27 -- patterns of 'compilePackage' rules. We could make 'compilePackage' rules
28 -- more precise to avoid such spurious matching.
29 -- | Build directory for in-tree GMP library.
30 gmpBuildPath :: Action FilePath
31 gmpBuildPath = buildRoot <&> (-/- stageString (stage gmpContext) -/- "gmp")
32
33 -- | GMP library header, relative to 'gmpBuildPath'.
34 gmpLibraryH :: FilePath
35 gmpLibraryH = "include/ghc-gmp.h"
36
37 -- | Directory for GMP library object files, relative to 'gmpBuildPath'.
38 gmpObjectsDir :: FilePath
39 gmpObjectsDir = "objs"
40
41 configureEnvironment :: Action [CmdOption]
42 configureEnvironment = sequence [ builderEnvironment "CC" $ Cc CompileC Stage1
43 , builderEnvironment "AR" (Ar Unpack Stage1)
44 , builderEnvironment "NM" Nm ]
45
46 gmpRules :: Rules ()
47 gmpRules = do
48 -- Copy appropriate GMP header and object files
49 root <- buildRootRules
50 root <//> gmpLibraryH %> \header -> do
51 windows <- windowsHost
52 configMk <- readFile' =<< (buildPath gmpContext <&> (-/- "config.mk"))
53 if not windows && -- TODO: We don't use system GMP on Windows. Fix?
54 any (`isInfixOf` configMk) [ "HaveFrameworkGMP = YES", "HaveLibGmp = YES" ]
55 then do
56 putBuild "| GMP library/framework detected and will be used"
57 copyFile (gmpBase -/- "ghc-gmp.h") header
58 else do
59 putBuild "| No GMP library/framework detected; in tree GMP will be built"
60 gmpPath <- gmpBuildPath
61 need [gmpPath -/- gmpLibrary]
62 createDirectory (gmpPath -/- gmpObjectsDir)
63 top <- topDirectory
64 build $ target gmpContext (Ar Unpack Stage1)
65 [top -/- gmpPath -/- gmpLibrary] [gmpPath -/- gmpObjectsDir]
66 copyFile (gmpPath -/- "gmp.h") header
67 copyFile (gmpPath -/- "gmp.h") (gmpPath -/- gmpLibraryInTreeH)
68
69 -- Build in-tree GMP library, prioritised so that it matches "before"
70 -- the generic .a library rule in Rules.Library, whenever applicable.
71 priority 2.0 $ root <//> gmpLibrary %> \lib -> do
72 gmpPath <- gmpBuildPath
73 build $ target gmpContext (Make gmpPath) [gmpPath -/- "Makefile"] [lib]
74 putSuccess "| Successfully built custom library 'gmp'"
75
76 -- In-tree GMP header is built by the gmpLibraryH rule
77 root <//> gmpLibraryInTreeH %> \_ -> do
78 gmpPath <- gmpBuildPath
79 need [gmpPath -/- gmpLibraryH]
80
81 -- This causes integerGmp package to be configured, hence creating the files
82 root <//> "gmp/config.mk" %> \_ -> do
83 -- Calling 'need' on @setup-config@, triggers @ghc-cabal configure@
84 -- Building anything in a package transitively depends on its configuration.
85 setupConfig <- contextPath gmpContext <&> (-/- "setup-config")
86 need [setupConfig]
87
88 -- TODO: Get rid of hard-coded @gmp@.
89 -- Run GMP's configure script
90 root <//> "gmp/Makefile" %> \mk -> do
91 env <- configureEnvironment
92 gmpPath <- gmpBuildPath
93 need [mk <.> "in"]
94 buildWithCmdOptions env $
95 target gmpContext (Configure gmpPath) [mk <.> "in"] [mk]
96
97 -- Extract in-tree GMP sources and apply patches
98 root <//> "gmp/Makefile.in" %> \_ -> do
99 gmpPath <- gmpBuildPath
100 removeDirectory gmpPath
101 -- Note: We use a tarball like gmp-4.2.4-nodoc.tar.bz2, which is
102 -- gmp-4.2.4.tar.bz2 repacked without the doc/ directory contents.
103 -- That's because the doc/ directory contents are under the GFDL,
104 -- which causes problems for Debian.
105 tarball <- unifyPath . fromSingleton "Exactly one GMP tarball is expected"
106 <$> getDirectoryFiles "" [gmpBase -/- "gmp-tarballs/gmp*.tar.bz2"]
107
108 withTempDir $ \dir -> do
109 let tmp = unifyPath dir
110 need [tarball]
111 build $ target gmpContext (Tar Extract) [tarball] [tmp]
112
113 let patch = gmpBase -/- "gmpsrc.patch"
114 patchName = takeFileName patch
115 copyFile patch $ tmp -/- patchName
116 applyPatch tmp patchName
117
118 let name = dropExtension . dropExtension $ takeFileName tarball
119 unpack = fromMaybe . error $ "gmpRules: expected suffix "
120 ++ "-nodoc (found: " ++ name ++ ")."
121 libName = unpack $ stripSuffix "-nodoc" name
122
123 moveDirectory (tmp -/- libName) gmpPath