Preliminary bindist (#558)
authorAlp Mestanogullari <alpmestan@gmail.com>
Tue, 3 Apr 2018 19:42:39 +0000 (21:42 +0200)
committerAndrey Mokhov <andrey.mokhov@gmail.com>
Tue, 3 Apr 2018 19:42:39 +0000 (20:42 +0100)
* Preliminary bindist rule

For now, we only ship `<build root>/{bin, lib}` and the few make build system
related files that are needed to support a simple

```
./configure [--prefix=PATH] && make install
```

workflow. The current binary distributions of GHC support a wider range
of parameters, but I figured it would be a good thing to start with this
and enhance it as we all see fit and perhaps using feedback from GHC HQ
(@bgamari in particular) and bindist users.

* document binary distribution rule in README

* sdist-ghc -> source-dist, Rules.Bindist -> Rules.BinaryDist

* add missing src/Rules/BinaryDist.hs

README.md
cfg/system.config.in
hadrian.cabal
src/Builder.hs
src/Builder.hs-boot
src/Rules.hs
src/Rules/BinaryDist.hs [new file with mode: 0644]
src/Rules/SourceDist.hs

index 620d405..2509dae 100644 (file)
--- a/README.md
+++ b/README.md
@@ -125,7 +125,18 @@ are currently not supported.
 
 #### Source distribution
 
-To build a GHC source distribution tarball, run `build sdist-ghc`.
+To build a GHC source distribution tarball, run `build source-dist`.
+
+#### Binary distribution
+
+To build a GHC binary distribution, run `build binary-dist`. The resulting
+tarball contains just enough to support the
+
+``` sh
+$ ./configure [--prefix=PATH] && make install
+```
+
+workflow, for now.
 
 #### Testing
 
index c983ae4..72bef12 100644 (file)
@@ -7,6 +7,7 @@
 
 alex           = @AlexCmd@
 ar             = @ArCmd@
+autoreconf     = autoreconf
 cc             = @CC@
 happy          = @HappyCmd@
 hs-cpp         = @HaskellCPPCmd@
index 486148f..ca339fb 100644 (file)
@@ -51,6 +51,7 @@ executable hadrian
                        , Oracles.Setting
                        , Oracles.ModuleFiles
                        , Rules
+                       , Rules.BinaryDist
                        , Rules.Clean
                        , Rules.Compile
                        , Rules.Configure
index 5ca6c20..0fb8be5 100644 (file)
@@ -89,6 +89,7 @@ instance NFData   HaddockMode
 -- @GhcPkg Stage1@ is the one built in Stage0.
 data Builder = Alex
              | Ar ArMode Stage
+             | Autoreconf FilePath
              | DeriveConstants
              | Cc CcMode Stage
              | Configure FilePath
@@ -174,6 +175,7 @@ instance H.Builder Builder where
 
     runtimeDependencies :: Builder -> Action [FilePath]
     runtimeDependencies = \case
+        Autoreconf dir -> return [dir -/- "configure.ac"]
         Configure dir -> return [dir -/- "configure"]
 
         Ghc _ Stage0 -> return []
@@ -232,6 +234,7 @@ instance H.Builder Builder where
 
                 Ar Unpack _ -> cmd echo [Cwd output] [path] buildArgs
 
+                Autoreconf dir -> cmd echo [Cwd dir] [path] buildArgs
                 Configure dir -> do
                     -- Inject /bin/bash into `libtool`, instead of /bin/sh,
                     -- otherwise Windows breaks. TODO: Figure out why.
@@ -287,6 +290,7 @@ systemBuilderPath builder = case builder of
     Alex            -> fromKey "alex"
     Ar _ Stage0     -> fromKey "system-ar"
     Ar _ _          -> fromKey "ar"
+    Autoreconf _    -> fromKey "autoreconf"
     Cc  _  Stage0   -> fromKey "system-cc"
     Cc  _  _        -> fromKey "cc"
     -- We can't ask configure for the path to configure!
index bd38891..1d10434 100644 (file)
@@ -13,6 +13,7 @@ data HaddockMode = BuildPackage | BuildIndex
 
 data Builder = Alex
              | Ar ArMode Stage
+            | Autoreconf FilePath
              | DeriveConstants
              | Cc CcMode Stage
              | Configure FilePath
index 982d249..100720f 100644 (file)
@@ -8,15 +8,16 @@ import qualified Hadrian.Oracles.TextFile
 import Expression
 import GHC
 import qualified Oracles.ModuleFiles
+import qualified Rules.BinaryDist
 import qualified Rules.Compile
-import qualified Rules.PackageData
+import qualified Rules.Configure
 import qualified Rules.Dependencies
 import qualified Rules.Documentation
 import qualified Rules.Generate
-import qualified Rules.Configure
 import qualified Rules.Gmp
 import qualified Rules.Libffi
 import qualified Rules.Library
+import qualified Rules.PackageData
 import qualified Rules.Program
 import qualified Rules.Register
 import Settings
@@ -122,6 +123,7 @@ packageRules = do
 
 buildRules :: Rules ()
 buildRules = do
+    Rules.BinaryDist.bindistRules
     Rules.Configure.configureRules
     Rules.Generate.copyRules
     Rules.Generate.generateRules
diff --git a/src/Rules/BinaryDist.hs b/src/Rules/BinaryDist.hs
new file mode 100644 (file)
index 0000000..db73622
--- /dev/null
@@ -0,0 +1,121 @@
+module Rules.BinaryDist where
+
+import Expression
+import GHC
+import Oracles.Setting
+import Settings
+import Target
+import Utilities
+
+bindistRules :: Rules ()
+bindistRules = do
+    root <- buildRootRules
+    phony "binary-dist" $ do
+      -- We 'need' all binaries and libraries
+      targets <- mapM pkgTarget =<< stagePackages Stage1
+      need targets
+
+      version <- setting ProjectVersion
+      targetPlatform <- setting TargetPlatformFull
+
+      let ghcBuildDir      = root -/- stageString Stage1
+          bindistFilesDir  = root -/- "bindist" -/- ghcVersionPretty
+          ghcVersionPretty = "ghc-" ++ version ++ "-" ++ targetPlatform
+
+      -- we create the bindist directory at <root>/bindist/ghc-X.Y.Z-platform/
+      -- and populate it with a stage2 build
+      createDirectory bindistFilesDir
+      copyDirectory (ghcBuildDir -/- "bin") bindistFilesDir
+      copyDirectory (ghcBuildDir -/- "lib") bindistFilesDir
+      {- SHOULD WE SHIP DOCS?
+      need ["docs"]
+      copyDirectory (root -/- "docs") bindistFilesDir
+      -}
+
+      -- we then 'need' all the files necessary to configure and install
+      -- (as in, './configure [...] && make install') this build on some
+      -- other machine.
+      need $ map (bindistFilesDir -/-)
+                 (["configure", "Makefile"] ++ bindistInstallFiles)
+
+      -- finally, we create the archive, at
+      -- <root>/bindist/ghc-X.Y.Z-platform.tar.xz
+      command [Cwd $ root -/- "bindist"] "tar"
+        [ "-c", "--xz", "-f"
+        , ghcVersionPretty <.> "tar.xz"
+        , ghcVersionPretty
+        ]
+
+    -- prepare binary distribution configure script
+    -- (generated under <ghc root>/distrib/configure by 'autoreconf')
+    root -/- "bindist" -/- "ghc-*" -/- "configure" %> \configurePath -> do
+      ghcRoot <- topDirectory
+      copyFile (ghcRoot -/- "aclocal.m4") (ghcRoot -/- "distrib" -/- "aclocal.m4")
+      buildWithCmdOptions [] $
+        target (vanillaContext Stage1 ghc) (Autoreconf $ ghcRoot -/- "distrib") [] []
+      -- we clean after ourselves, moving the configure script we generated in
+      -- our bindist dir
+      removeFile (ghcRoot -/- "distrib" -/- "aclocal.m4")
+      moveFile (ghcRoot -/- "distrib" -/- "configure") configurePath
+
+    -- generate the Makefile that enables the "make install" part
+    root -/- "bindist" -/- "ghc-*" -/- "Makefile" %> \makefilePath ->
+      writeFile' makefilePath bindistMakefile
+
+    -- copy over the various configure-related files needed for a working
+    -- './configure [...] && make install' workflow
+    -- (see the list of files needed in the 'binary-dist' rule above, before
+    -- creating the archive).
+    forM_ bindistInstallFiles $ \file ->
+      root -/- "bindist" -/- "ghc-*" -/- file %> \dest -> do
+        ghcRoot <- topDirectory
+        copyFile (ghcRoot -/- fixup file) dest
+
+  where fixup f
+          | f `elem` ["INSTALL", "README"] = "distrib" -/- f
+          | otherwise                      = f
+
+-- | A list of files that allow us to support a simple
+--   @./configure [--prefix=PATH] && make install@ workflow.
+--
+--   NOTE: the list surely is incomplete
+bindistInstallFiles :: [FilePath]
+bindistInstallFiles =
+  [ "config.sub", "config.guess", "install-sh"
+  , "mk" -/- "config.mk.in", "mk" -/- "install.mk.in"
+  , "settings.in", "README", "INSTALL"
+  ]
+
+-- | Auxiliary function that gives us a 'Filepath' we can 'need' for
+--   all libraries and programs that are needed for a complete build.
+--
+--   For libraries, it returns the path to the .conf file in the package db.
+--   For executables, it returns the path to the compiled executable.
+pkgTarget :: Package -> Action FilePath
+pkgTarget pkg
+  | isLibrary pkg = pkgConfFile (Context Stage1 pkg $ read "v")
+  | otherwise     = programPath =<< programContext Stage1 pkg
+
+-- TODO: augment this makefile to match the various parameters that
+-- the current bindist scripts support.
+-- | A trivial makefile that only takes @$prefix@ into account,
+--   and not e.g @$datadir@ (for docs) and other variables, yet.
+bindistMakefile :: String
+bindistMakefile = unlines
+  [ "MAKEFLAGS += --no-builtin-rules"
+  , ".SUFFIXES:"
+  , ""
+  , "include mk/install.mk"
+  , ""
+  , ".PHONY: default"
+  , "default:"
+  , "\t@echo 'Run \"make install\" to install'"
+  , "\t@false"
+  , ""
+  , ".PHONY: install"
+  , "install:"
+  , "\tmkdir -p $(prefix)"
+  , "\tcp settings lib/settings"
+  , "\tcp -R bin $(prefix)/"
+  , "\tcp -R lib $(prefix)/"
+  ]
index 6ef7929..8bec3f3 100644 (file)
@@ -9,7 +9,7 @@ import Rules.Clean
 
 sourceDistRules :: Rules ()
 sourceDistRules = do
-    "sdist-ghc" ~> do
+    "source-dist" ~> do
         -- We clean the source tree first.
         -- See https://github.com/snowleopard/hadrian/issues/384.
         -- TODO: Do we still need to clean the tree?