From 87b48d473bdb41670c9f3b26a628f34c3c5c9481 Mon Sep 17 00:00:00 2001 From: Ben Sima Date: Fri, 3 Apr 2020 13:20:29 -0700 Subject: Rewrite buildGhc and buildGhcjs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I wanted to even further simplify the build tooling overhead. My general goal is to not have to think about declaring packages, or dependencies, or really anything that you might find in a cabal file. Not all of these goals are possible, but we can get pretty close. With this commit all I need for the 'buildGhc/buildGhcjs' functions is the path to the entrypoint file; everything else is either inferred by the Nix code or declared in the Haskell code comments. The strategy is to map a Haskell module to an executable artifact, and pass just that module to 'ghc --make'. Then we can rely on ghc to handle walking the local filesystem for imports. The only thing ghc really needs to know is a name for the output executable; it is hard to automatically infer this, so we have a simple comment syntax to declare this in the file. The comment syntax is inspired by existing Haskell 'LANGUAGE' pragmas; having this in the same file keeps the configuration as close to the real code as possible. The Nix code then extracts this info from the code comments, and sets the required ghc flags. Second, we need to declare the set of 3rd-party packages that our program relies on. For this we can re-use the same comment syntax and just list the dependencies, then extract them in Nix and construct a package set as we were before. This reduces the amount of "package declaration" code we have to write in default.nix, and reduces the amount of time we have to spend switching between the Haskell code and the Nix code (I find such context switching super annoying). I also think having the configuration in with the Haskell code encourages us to write smaller, simpler modules and only write code that we need. Additionally, I refactored the bild and ghci (now called 'repl') scripts to work in any directory. The .envrc uses direnv to set the path so that you can run these scripts anywhere. That means the following works: $ cd Run/Que $ bild Website $ repl Server λ> :l Run.Que.Server I find this to be a rather nice workflow. --- Com/MusicMeetsComics/Client.hs | 14 ++++++++++++++ Com/MusicMeetsComics/Server.hs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) (limited to 'Com/MusicMeetsComics') diff --git a/Com/MusicMeetsComics/Client.hs b/Com/MusicMeetsComics/Client.hs index 2dad3b7..2361939 100644 --- a/Com/MusicMeetsComics/Client.hs +++ b/Com/MusicMeetsComics/Client.hs @@ -1,6 +1,20 @@ {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE NoImplicitPrelude #-} +-- | Hero app frontend +-- +-- : exe mmc.js +-- +-- : dep aeson +-- : dep clay +-- : dep containers +-- : dep miso +-- : dep protolude +-- : dep servant +-- : dep split +-- : dep string-quote +-- : dep text +-- : dep ghcjs-base module Com.MusicMeetsComics.Client where import Com.MusicMeetsComics.App ( Action(..) diff --git a/Com/MusicMeetsComics/Server.hs b/Com/MusicMeetsComics/Server.hs index 7bb94a2..5b12861 100644 --- a/Com/MusicMeetsComics/Server.hs +++ b/Com/MusicMeetsComics/Server.hs @@ -9,6 +9,38 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE NoImplicitPrelude #-} +-- | Hero web app +-- +-- : exe mmc +-- +-- : dep aeson +-- : dep clay +-- : dep containers +-- : dep miso +-- : dep protolude +-- : dep servant +-- : dep split +-- : dep string-quote +-- : dep text +-- : dep dhall +-- : dep ekg +-- : dep fast-logger +-- : dep http-types +-- : dep katip +-- : dep lucid +-- : dep monad-logger +-- : dep monad-metrics +-- : dep mtl +-- : dep network-uri +-- : dep safe +-- : dep servant-lucid +-- : dep servant-server +-- : dep split +-- : dep wai +-- : dep wai-app-static +-- : dep wai-extra +-- : dep wai-middleware-metrics +-- : dep warp module Com.MusicMeetsComics.Server where import qualified Clay -- cgit v1.2.3