Skip to content
This repository was archived by the owner on Oct 7, 2020. It is now read-only.

Commit 03dcb8a

Browse files
authored
Merge pull request #991 from fendor/master
Add Shakefile as possible build script
2 parents b037cb7 + 0b29bc6 commit 03dcb8a

File tree

4 files changed

+314
-0
lines changed

4 files changed

+314
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,6 @@ test-logs/
6565
.hspec-failures
6666
/test/testdata/addPragmas/stack.yaml
6767
.vscode
68+
69+
# shake build information
70+
_build/

README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ we talk to clients.__
2626
- [macOS](#installation-on-macos)
2727
- [Nix](#installation-with-nix)
2828
- [ArchLinux](#installation-on-archlinux)
29+
- [Shake](#installation-with-shake)
2930
- [Configuration](#configuration)
3031
- [Editor Integration](#editor-integration)
3132
- Using HIE with [VS Code](#using-hie-with-vs-code), [Sublime Text](#using-hie-with-sublime-text), [Vim/Neovim](#using-hie-with-vim-or-neovim), [Atom](#using-hie-with-atom), [Oni](#using-hie-with-oni), [Emacs](#using-hie-with-emacs), [Spacemacs](#using-hie-with-spacemacs) or [Spacemacs+Nix](#using-hie-with-spacemacs-on-nix-based-projects)
@@ -295,6 +296,62 @@ Using [Aura](https://github.com/aurapm/aura):
295296
# aura -A haskell-ide-engine-git
296297
```
297298

299+
### Installation with Shake
300+
301+
Experimental build script for HIE. Feedback is appreciated.
302+
Uses the [shake](https://shakebuild.com/) build system for predictable builds.
303+
The build script is platform independent and the only prerequisites are that `git` and `stack` are installed. The dependency on `make` and other linux specific commands has been dropped.
304+
305+
Note, on first invocation of the build script, a GHC is being installed for execution. However, if you build HIE for every GHC, no GHC is downloaded twice.
306+
The GHC used for the `Shakefile.hs` can be adjusted in `shake.yaml` by using a different resolver.
307+
308+
Available commands can be seen with:
309+
310+
```bash
311+
stack ./Shakefile.hs help
312+
```
313+
314+
Remember, this will take time to download a Stackage-LTS and an appropriate GHC. However, afterwards all commands should work as expected.
315+
316+
#### Install specific GHC Version with Shake
317+
318+
Install **Nightly** (and hoogle docs):
319+
320+
```bash
321+
stack ./Shakefile.hs hie-8.6.3
322+
stack ./Shakefile.hs build-doc-8.6.3
323+
```
324+
325+
Install **LTS** (and hoogle docs):
326+
327+
```bash
328+
stack ./Shakefile.hs hie-8.4.4
329+
stack ./Shakefile.hs build-doc-8.4.4
330+
```
331+
332+
#### Install *all* available GHC versions with Shake
333+
334+
*Warning*: Requires 20+ GB of space and potentially more than 2 hours to install, so please be patient!
335+
336+
This will:
337+
338+
* install all supported GHC versions (8.2.1 - 8.6.3)
339+
* name them as expected by the VS Code plugin
340+
* build local hoogle docs for each version
341+
342+
```bash
343+
stack ./Shakefile.hs build-all
344+
```
345+
346+
Then add
347+
348+
```json
349+
"languageServerHaskell.useCustomHieWrapper": true,
350+
"languageServerHaskell.useCustomHieWrapperPath": "hie-wrapper",
351+
```
352+
353+
to VS Code user settings.
354+
298355
## Configuration
299356
There are some settings that can be configured via a `settings.json` file:
300357

Shakefile.hs

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
#!/usr/bin/env stack
2+
{- stack
3+
--stack-yaml=shake.yaml
4+
--install-ghc runghc
5+
--package shake
6+
--package tar
7+
--package zlib
8+
-}
9+
10+
import qualified Data.ByteString.Lazy as BS
11+
import qualified Codec.Archive.Tar as Tar
12+
import qualified Codec.Compression.GZip as GZip
13+
14+
import Development.Shake
15+
import Development.Shake.Command
16+
import Development.Shake.FilePath
17+
import Control.Monad
18+
import System.Environment ( unsetEnv )
19+
import System.Info ( os
20+
, arch
21+
)
22+
23+
import Data.List ( dropWhileEnd )
24+
import Data.Char ( isSpace )
25+
26+
type VersionNumber = String
27+
type GhcPath = String
28+
29+
-- |Defines all different hie versions that are buildable.
30+
-- If they are edited,
31+
hieVersions :: [VersionNumber]
32+
hieVersions = ["8.2.2", "8.4.3", "8.4.4", "8.6.1", "8.6.2", "8.6.3"]
33+
34+
-- |Most recent version of hie.
35+
-- Important for `dist`, the `hie-wrapper` of the most recent hie
36+
-- will be copied to the tar-archive.
37+
mostRecentHieVersion :: VersionNumber
38+
mostRecentHieVersion = last hieVersions
39+
40+
main :: IO ()
41+
main = do
42+
-- unset GHC_PACKAGE_PATH for cabal
43+
unsetEnv "GHC_PACKAGE_PATH"
44+
shakeArgs shakeOptions { shakeFiles = "_build" } $ do
45+
want ["help"]
46+
phony "ghc" $ do
47+
ghc <- getGhcPath
48+
command_ [] ghc ["--version"]
49+
liftIO $ putStrLn "GHC"
50+
phony "submodules" updateSubmodules
51+
phony "cabal" (getGhcPath >>= installCabal)
52+
phony "all" helpMessage
53+
phony "help" helpMessage
54+
phony "build" (need (reverse $ map ("hie-" ++) hieVersions))
55+
phony "build-all" (need ["build"] >> need ["build-docs"])
56+
phony "dist" buildDist
57+
phony "build-docs" (need (reverse $ map ("build-doc-hie-" ++) hieVersions))
58+
phony "test" (forM_ hieVersions test)
59+
phony "build-copy-compiler-tool" $ forM_ hieVersions buildCopyCompilerTool
60+
61+
forM_
62+
hieVersions
63+
(\version -> phony ("build-doc-hie-" ++ version) $ do
64+
buildDoc version
65+
)
66+
67+
forM_
68+
hieVersions
69+
(\version -> phony ("hie-" ++ version) $ do
70+
need ["submodules"]
71+
need ["cabal"]
72+
buildHie version
73+
installHie version
74+
)
75+
76+
phony "icu-macos-fix"
77+
(need ["icu-macos-fix-install"] >> need ["icu-macos-fix-build"])
78+
phony "icu-macos-fix-install" (command_ [] "brew" ["install", "icu4c"])
79+
phony "icu-macos-fix-build" $ mapM_ buildIcuMacosFix hieVersions
80+
81+
-- |Creates a compressed tar-archive consisting of all hie versions and `hie-wrapper`.
82+
-- Creates a temporary folder, copies all hie versions to it and compresses it in the end.
83+
buildDist :: Action ()
84+
buildDist = do
85+
-- Create the name of the resulting tar file.
86+
Stdout gitRef' <- command [] "git" ["describe", "--tags"]
87+
let gitRef = trim gitRef'
88+
let hieDistName = concat ["hie-", gitRef, "-", arch, "-", os]
89+
-- define name constants for later use
90+
let hieWrapper = "hie-wrapper" <.> exe
91+
let hie = "hie" <.> exe
92+
let mkHie version = "hie-" ++ version <.> exe
93+
94+
withTempDir
95+
(\temporaryDir -> do
96+
forM_ hieVersions $ \hieVersion -> do
97+
buildHie hieVersion
98+
-- after building `hie` copy it to the temporary folder
99+
localInstallRoot <- getLocalInstallRoot hieVersion
100+
copyFile' (localInstallRoot </> "bin" </> hie)
101+
(temporaryDir </> mkHie hieVersion)
102+
103+
-- if the most recent hie-* version is copied,
104+
-- copy it again as the default hie version
105+
-- Also, add its hie-wrapper to the tar archive
106+
when (hieVersion == mostRecentHieVersion) $ do
107+
copyFile' (localInstallRoot </> "bin" </> hieWrapper)
108+
(temporaryDir </> hieWrapper)
109+
copyFile' (localInstallRoot </> "bin" </> hie) (temporaryDir </> hie)
110+
111+
-- After every hie has been built, pack them into a tar.
112+
-- Encrypt the resulting tar file with gzip
113+
liftIO
114+
$ BS.writeFile (hieDistName ++ ".tar.gz")
115+
. GZip.compress
116+
. Tar.write
117+
=<< Tar.pack temporaryDir (hieWrapper : hie : map mkHie hieVersions)
118+
)
119+
return ()
120+
121+
buildIcuMacosFix :: VersionNumber -> Action ()
122+
buildIcuMacosFix version = execStackWithYaml_
123+
version
124+
[ "build"
125+
, "text-icu"
126+
, "--extra-lib-dirs=/usr/local/opt/icu4c/lib"
127+
, "--extra-include-dirs=/usr/local/opt/icu4c/include"
128+
]
129+
130+
updateSubmodules :: Action ()
131+
updateSubmodules = do
132+
command_ [] "git" ["submodule", "sync"]
133+
command_ [] "git" ["submodule", "update", "--init"]
134+
135+
installCabal :: GhcPath -> Action ()
136+
installCabal ghc = do
137+
execStack_ ["install", "cabal-install"]
138+
execCabal_ ["v1-update"]
139+
execCabal_ ["v1-install", "Cabal-2.4.1.0", "--with-compiler=" ++ ghc]
140+
141+
buildHie :: VersionNumber -> Action ()
142+
buildHie versionNumber = do
143+
when (versionNumber `elem` ["hie-8.2.2", "hie-8.2.1"])
144+
$ execStackWithYaml_ versionNumber ["install", "happy"]
145+
execStackWithYaml_ versionNumber ["build"]
146+
147+
installHie :: VersionNumber -> Action ()
148+
installHie versionNumber = do
149+
execStackWithYaml_ versionNumber ["install"]
150+
localBinDir <- getLocalBin
151+
localInstallRoot <- getLocalInstallRoot versionNumber
152+
let hie = "hie" <.> exe
153+
copyFile' (localInstallRoot </> "bin" </> hie)
154+
(localBinDir </> "hie-" ++ versionNumber <.> exe)
155+
copyFile' (localInstallRoot </> "bin" </> hie)
156+
(localBinDir </> "hie-" ++ dropExtension versionNumber <.> exe)
157+
158+
buildCopyCompilerTool :: VersionNumber -> Action ()
159+
buildCopyCompilerTool versionNumber =
160+
execStackWithYaml_ versionNumber ["build", "--copy-compiler-tool"]
161+
162+
test :: VersionNumber -> Action ()
163+
test versionNumber = execStackWithYaml_ versionNumber ["test"]
164+
165+
buildDoc :: VersionNumber -> Action ()
166+
buildDoc versionNumber = do
167+
execStackWithYaml_ versionNumber ["install", "hoogle"]
168+
execStackWithYaml_ versionNumber ["exec", "hoogle", "generate"]
169+
170+
helpMessage :: Action ()
171+
helpMessage = do
172+
let out = liftIO . putStrLn
173+
out ""
174+
out "Usage:"
175+
out " stack Shakefile.hs <target>"
176+
out ""
177+
out "Targets:"
178+
out
179+
" build Builds hie for all supported GHC versions (8.2.1, 8.2.2, 8.4.2, 8.4.3, 8.4.4, 8.6.1, 8.6.2 and 8.6.3)"
180+
out
181+
" build-all Builds hie and hoogle databases for all supported GHC versions"
182+
out " hie-8.2.1 Builds hie for GHC version 8.2.1 only"
183+
out " hie-8.2.2 Builds hie for GHC version 8.2.2 only"
184+
out " hie-8.4.2 Builds hie for GHC version 8.4.2 only"
185+
out " hie-8.4.3 Builds hie for GHC version 8.4.3 only"
186+
out " hie-8.4.4 Builds hie for GHC version 8.4.4 only"
187+
out " hie-8.6.1 Builds hie for GHC version 8.6.1 only"
188+
out " hie-8.6.2 Builds hie for GHC version 8.6.2 only"
189+
out " hie-8.6.3 Builds hie for GHC version 8.6.3 only"
190+
out " submodules Updates local git submodules"
191+
out
192+
" cabal NOTE 3: This is needed for stack only projects too"
193+
out
194+
" build-docs Builds the Hoogle database for all supported GHC versions"
195+
out " test Runs hie tests"
196+
out " icu-macos-fix Fixes icu related problems in MacOS"
197+
out
198+
" dist Creates a tarball containing all the hie binaries"
199+
out " help Show help"
200+
out ""
201+
202+
execStackWithYaml_ :: VersionNumber -> [String] -> Action ()
203+
execStackWithYaml_ versionNumber args = do
204+
let stackFile = "stack-" ++ versionNumber ++ ".yaml"
205+
command_ [] "stack" (("--stack-yaml=" ++ stackFile) : args)
206+
207+
execStackWithYaml :: CmdResult r => VersionNumber -> [String] -> Action r
208+
execStackWithYaml versionNumber args = do
209+
let stackFile = "stack-" ++ versionNumber ++ ".yaml"
210+
command [] "stack" (("--stack-yaml=" ++ stackFile) : args)
211+
212+
execStack :: CmdResult r => [String] -> Action r
213+
execStack = command [] "stack"
214+
215+
execStack_ :: [String] -> Action ()
216+
execStack_ = command_ [] "stack"
217+
218+
execCabal_ :: [String] -> Action ()
219+
execCabal_ = command_ [] "cabal"
220+
221+
-- |Get the path to the GHC compiler executable linked to the local `stack.yaml`
222+
-- Equal to the command `stack path --compiler-exe`
223+
getGhcPath :: Action GhcPath
224+
getGhcPath = do
225+
Stdout ghc' <- execStack ["path", "--compiler-exe"]
226+
return $ trim ghc'
227+
228+
-- |Read the local install root of the stack project specified by the VersionNumber
229+
-- Returns the filepath of the local install root.
230+
-- Equal to the command `stack path --local-install-root`
231+
getLocalInstallRoot :: VersionNumber -> Action FilePath
232+
getLocalInstallRoot hieVersion = do
233+
Stdout localInstallRoot' <- execStackWithYaml
234+
hieVersion
235+
["path", "--local-install-root"]
236+
return $ trim localInstallRoot'
237+
238+
-- |Get the local binary path of stack.
239+
-- Equal to the command `stack path --local-bin`
240+
getLocalBin :: Action FilePath
241+
getLocalBin = do
242+
Stdout stackLocalDir' <- execStack ["path", "--local-bin"]
243+
return $ trim stackLocalDir'
244+
245+
-- |Trim the end of a string
246+
trim :: String -> String
247+
trim = dropWhileEnd isSpace

shake.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Used to provide a different environment for the shake build script
2+
resolver: lts-12.25 # GHC 8.4.4
3+
packages:
4+
- .
5+
6+
nix:
7+
packages: [ zlib ]

0 commit comments

Comments
 (0)