From 838a2d41764b5e2d506e113eac0d78c6b06ade89 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Fri, 28 Feb 2020 17:41:51 +0100 Subject: [PATCH 01/16] Build ghcide using stack_snapshot --- WORKSPACE | 72 ++++++++++++++++++++++++++++++++++++++ ghcide-stack-snapshot.yaml | 16 +++++++++ 2 files changed, 88 insertions(+) create mode 100644 ghcide-stack-snapshot.yaml diff --git a/WORKSPACE b/WORKSPACE index bf07c4215..e422c3f10 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -125,6 +125,78 @@ stack_snapshot( snapshot = test_stack_snapshot, ) +stack_snapshot( + name = "stackage_ghcide", + extra_deps = {"zlib": ["@zlib.win//:zlib" if is_windows else "@zlib.dev//:zlib"]}, + haddock = False, + local_snapshot = "//:ghcide-stack-snapshot.yaml", + packages = [ + "base", + "base16-bytestring", + "binary", + "bytestring", + "containers", + "cryptohash-sha1", + "data-default", + "deepseq", + "directory", + "extra", + "filepath", + "ghc", + "ghc-paths", + "ghcide", + "gitrev", + "hashable", + "haskell-lsp", + "hie-bios", + "hslogger", + "optparse-applicative", + "shake", + "text", + "unordered-containers", + ], +) + +http_archive( + name = "ghcide", + build_file_content = """ +load("@rules_haskell//haskell:cabal.bzl", "haskell_cabal_binary") +haskell_cabal_binary( + name = "ghcide", + srcs = glob(["**"]), + deps = [ + "@stackage_ghcide//:hslogger", + "@stackage_ghcide//:base", + "@stackage_ghcide//:binary", + "@stackage_ghcide//:base16-bytestring", + "@stackage_ghcide//:bytestring", + "@stackage_ghcide//:containers", + "@stackage_ghcide//:cryptohash-sha1", + "@stackage_ghcide//:data-default", + "@stackage_ghcide//:deepseq", + "@stackage_ghcide//:directory", + "@stackage_ghcide//:extra", + "@stackage_ghcide//:filepath", + "@stackage_ghcide//:ghc-paths", + "@stackage_ghcide//:ghc", + "@stackage_ghcide//:gitrev", + "@stackage_ghcide//:hashable", + "@stackage_ghcide//:haskell-lsp", + "@stackage_ghcide//:hie-bios", + "@stackage_ghcide//:ghcide", + "@stackage_ghcide//:optparse-applicative", + "@stackage_ghcide//:shake", + "@stackage_ghcide//:text", + "@stackage_ghcide//:unordered-containers", + ], + visibility = ["//visibility:public"], +) + """, + sha256 = "bdac4be9b2b9254876edefc788d56ff15dbf6d861dc4bf9ad4fa5ffb795e7c0d", + strip_prefix = "ghcide-ff62fdd87de813573167419809273fe07893678d", + urls = ["https://github.com/digital-asset/ghcide/archive/ff62fdd87de813573167419809273fe07893678d.tar.gz"], +) + load( "@io_tweag_rules_nixpkgs//nixpkgs:nixpkgs.bzl", "nixpkgs_cc_configure", diff --git a/ghcide-stack-snapshot.yaml b/ghcide-stack-snapshot.yaml new file mode 100644 index 000000000..78d287e57 --- /dev/null +++ b/ghcide-stack-snapshot.yaml @@ -0,0 +1,16 @@ +resolver: nightly-2019-09-21 +packages: + - github: digital-asset/ghcide + commit: "ff62fdd87de813573167419809273fe07893678d" + sha256: "bdac4be9b2b9254876edefc788d56ff15dbf6d861dc4bf9ad4fa5ffb795e7c0d" + - haskell-lsp-0.20.0.0 + - haskell-lsp-types-0.20.0.0 + - lsp-test-0.10.1.0 + - hie-bios-0.4.0 + - fuzzy-0.1.0.0 + - regex-pcre-builtin-0.95.1.1.8.43 + - regex-base-0.94.0.0 + - regex-tdfa-1.3.1.0 + - shake-0.18.5 + - parser-combinators-1.2.1 + - haddock-library-1.8.0 From 9f003101f16801f0bd2d8dca7180eb2e80521e55 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Sat, 29 Feb 2020 12:57:47 +0100 Subject: [PATCH 02/16] Configure hie-bios --- .ghcide | 4 ++++ .hie-bios | 19 +++++++++++++++++++ hie.yaml | 1 + tests/BUILD.bazel | 9 +++++++++ 4 files changed, 33 insertions(+) create mode 100755 .ghcide create mode 100755 .hie-bios create mode 100644 hie.yaml diff --git a/.ghcide b/.ghcide new file mode 100755 index 000000000..43fe7f29a --- /dev/null +++ b/.ghcide @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +bazel build @ghcide//:ghcide +bazel-bin/external/ghcide/_install/bin/ghcide "$@" diff --git a/.hie-bios b/.hie-bios new file mode 100755 index 000000000..eb28c5ba2 --- /dev/null +++ b/.hie-bios @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +hie_bios_flags() { + bazel build //tests:hie-bios \ + --output_groups=hie_bios \ + --experimental_show_artifacts \ + 2>&1 \ + | awk ' + /^>>>/ { + while ((getline line < substr($1, 4)) > 0) { + print line + } + }' +} +if [[ -z "${HIE_BIOS_OUTPUT-}" ]]; then + hie_bios_flags +else + hie_bios_flags >"$HIE_BIOS_OUTPUT" +fi diff --git a/hie.yaml b/hie.yaml new file mode 100644 index 000000000..26ea7d20d --- /dev/null +++ b/hie.yaml @@ -0,0 +1 @@ +cradle: {bios: {program: ".hie-bios"}} diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel index af6413f25..e8b09cad9 100644 --- a/tests/BUILD.bazel +++ b/tests/BUILD.bazel @@ -10,6 +10,7 @@ load( "haskell_binary", "haskell_doc", "haskell_library", + "haskell_repl", ) load( "//haskell:doctest.bzl", @@ -386,3 +387,11 @@ haskell_doc( tags = ["requires_lz4"], deps = [":utils"], ) + +haskell_repl( + name = "hie-bios", + collect_data = False, + deps = [ + "//tests:run-tests", + ], +) From 285715743b1faabdce85ae47c1b50807b43079bf Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 7 Apr 2020 18:34:10 +0200 Subject: [PATCH 03/16] Document ghcide setup in use-cases --- WORKSPACE | 20 ++-- docs/haskell-use-cases.rst | 225 +++++++++++++++++++++++++++++++++++++ ghcide-stack-snapshot.yaml | 17 ++- 3 files changed, 249 insertions(+), 13 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index e422c3f10..df2339931 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -131,9 +131,11 @@ stack_snapshot( haddock = False, local_snapshot = "//:ghcide-stack-snapshot.yaml", packages = [ + "hslogger", + "aeson", "base", - "base16-bytestring", "binary", + "base16-bytestring", "bytestring", "containers", "cryptohash-sha1", @@ -142,14 +144,15 @@ stack_snapshot( "directory", "extra", "filepath", - "ghc", + "ghc-check", "ghc-paths", - "ghcide", + "ghc", "gitrev", "hashable", "haskell-lsp", + "haskell-lsp-types", "hie-bios", - "hslogger", + "ghcide", "optparse-applicative", "shake", "text", @@ -166,6 +169,7 @@ haskell_cabal_binary( srcs = glob(["**"]), deps = [ "@stackage_ghcide//:hslogger", + "@stackage_ghcide//:aeson", "@stackage_ghcide//:base", "@stackage_ghcide//:binary", "@stackage_ghcide//:base16-bytestring", @@ -177,11 +181,13 @@ haskell_cabal_binary( "@stackage_ghcide//:directory", "@stackage_ghcide//:extra", "@stackage_ghcide//:filepath", + "@stackage_ghcide//:ghc-check", "@stackage_ghcide//:ghc-paths", "@stackage_ghcide//:ghc", "@stackage_ghcide//:gitrev", "@stackage_ghcide//:hashable", "@stackage_ghcide//:haskell-lsp", + "@stackage_ghcide//:haskell-lsp-types", "@stackage_ghcide//:hie-bios", "@stackage_ghcide//:ghcide", "@stackage_ghcide//:optparse-applicative", @@ -192,9 +198,9 @@ haskell_cabal_binary( visibility = ["//visibility:public"], ) """, - sha256 = "bdac4be9b2b9254876edefc788d56ff15dbf6d861dc4bf9ad4fa5ffb795e7c0d", - strip_prefix = "ghcide-ff62fdd87de813573167419809273fe07893678d", - urls = ["https://github.com/digital-asset/ghcide/archive/ff62fdd87de813573167419809273fe07893678d.tar.gz"], + sha256 = "47cca96a6e5031b3872233d5b9ca14d45f9089da3d45a068e1b587989fec4364", + strip_prefix = "ghcide-39605333c34039241768a1809024c739df3fb2bd", + urls = ["https://github.com/digital-asset/ghcide/archive/39605333c34039241768a1809024c739df3fb2bd.tar.gz"], ) load( diff --git a/docs/haskell-use-cases.rst b/docs/haskell-use-cases.rst index c9df66a63..83cbf207e 100644 --- a/docs/haskell-use-cases.rst +++ b/docs/haskell-use-cases.rst @@ -143,6 +143,231 @@ This works for any ``haskell_binary`` or ``haskell_library`` target. Modules of all libraries will be loaded in interpreted mode and can be reloaded using the ``:r`` GHCi command when source files change. +Configuring IDE integration with ghcide +--------------------------------------- + +rules_haskell has preliminary support for IDE integration using `ghcide`_. The +ghcide project provides IDE features for Haskell projects through the Language +Server Protocol. To set this up you can define a `haskell_repl`_ target that +will collect the required compiler flags for your Haskell targets and pass them +to `hie-bios`_ which will then forward them to ghcide. + +Let's set this up for the following example project:: + + haskell_toolchain_library( + name = "base", + ) + + haskell_library( + name = "library-a", + srcs = ["Lib/A.hs"], + deps = [":base"], + ) + + haskell_library( + name = "library-b", + srcs = ["Lib/B.hs"], + deps = [":base"], + ) + + haskell_binary( + name = "binary", + srcs = ["Main.hs"], + deps = [ + ":base", + ":library-a", + ":library-b", + ], + ) + +We want to configure ghcide to provide IDE integration for all these three +targets. Start by defining a ``haskell_repl`` target as follows:: + + haskell_repl( + name = "hie-bios", + collect_data = False, + deps = [ + ":binary", + # ":library-a", + # ":library-b", + ], + ) + +Note, that ``library-a`` and ``library-b`` do not have to be listed explicitly. +By default haskell_repl will include all transitive dependencies that are not +external dependencies. Refer to the API documentation of `haskell_repl`_ for +details. + +We also disable building runtime dependencies using ``collect_data = False`` as +they are not required for an IDE session. + +You can test if this provides the expected compiler flags by running the +following Bazel command and taking a look at the generated file:: + + bazel build //:hie-bios --output_groups=hie_bios + +Next, we need to hook this up to `hie-bios`_ using the `bios cradle`_. To that +end, define a small shell script named ``.hie-bios`` that looks as follows:: + + #!/usr/bin/env bash + set -euo pipefail + bazel build //:hie-bios --output_groups=hie_bios + cat bazel-bin/hie-bios@hie-bios >"$HIE_BIOS_OUTPUT" + +Then configure `hie-bios`_ to use this script in the bios cradle with the +following ``hie.yaml`` file:: + + cradle: + bios: + program: ".hie-bios" + +Now the hie-bios cradle is ready to use. The last step is to install ghcide. +Unfortunately, ghcide has to be compiled with the exact same GHC that you're +using to build your project. The easiest way to do this is in this context is +to build it with Bazel as part of your rules_haskell project. + +First, define a custom stack snapshot that provides the package versions that +ghcide requires based on `ghcide's stack.yaml`_ file. Let's call it +``ghcide-stack-snapshot.yaml``. Copy the ``resolver`` field and turn the +``extra-deps`` field into a ``packages`` field. Then add another entry to +``packages`` for the ghcide library itself:: + + # Taken from ghcide's stack.yaml + resolver: nightly-2019-09-21 + packages: + # Taken from the extra-deps field. + - haskell-lsp-0.21.0.0 + - haskell-lsp-types-0.21.0.0 + - lsp-test-0.10.2.0 + - hie-bios-0.4.0 + - fuzzy-0.1.0.0 + - regex-pcre-builtin-0.95.1.1.8.43 + - regex-base-0.94.0.0 + - regex-tdfa-1.3.1.0 + - shake-0.18.5 + - parser-combinators-1.2.1 + - haddock-library-1.8.0 + - tasty-rerun-1.1.17 + - ghc-check-0.1.0.3 + # Point to the ghcide revision that you would like to use. + - github: digital-asset/ghcide + commit: "39605333c34039241768a1809024c739df3fb2bd" + sha256: "47cca96a6e5031b3872233d5b9ca14d45f9089da3d45a068e1b587989fec4364" + +Then define a dedicated ``stack_snapshot`` for ghcide in your ``WORKSPACE`` +file. In the ``packages`` attribute we expose all dependencies of the ghcide +executable:: + + stack_snapshot( + name = "stackage_ghcide", + # The rules_haskell example project shows how to import libz. + # https://github.com/tweag/rules_haskell/blob/123e3817156f9135dfa44dcb5a796c424df1f436/examples/WORKSPACE#L42-L63 + extra_deps = {"zlib": ["@zlib.hs"]}, + haddock = False, + local_snapshot = "//:ghcide-stack-snapshot.yaml", + packages = [ + "hslogger", + "aeson", + "base", + "binary", + "base16-bytestring", + "bytestring", + "containers", + "cryptohash-sha1", + "data-default", + "deepseq", + "directory", + "extra", + "filepath", + "ghc-check", + "ghc-paths", + "ghc", + "gitrev", + "hashable", + "haskell-lsp", + "haskell-lsp-types", + "hie-bios", + "ghcide", + "optparse-applicative", + "shake", + "text", + "unordered-containers", + ], + ) + +Finally, define a ``haskell_cabal_binary`` target for the ghcide executable +itself. (Unfortunately, ``stack_snapshot`` does not support building +executables):: + + http_archive( + name = "ghcide", + build_file_content = """ + load("@rules_haskell//haskell:cabal.bzl", "haskell_cabal_binary") + haskell_cabal_binary( + name = "ghcide", + srcs = glob(["**"]), + deps = [ + # From build-depends field of executable section in ghcide.cabal + "@stackage_ghcide//:hslogger", + "@stackage_ghcide//:aeson", + "@stackage_ghcide//:base", + "@stackage_ghcide//:binary", + "@stackage_ghcide//:base16-bytestring", + "@stackage_ghcide//:bytestring", + "@stackage_ghcide//:containers", + "@stackage_ghcide//:cryptohash-sha1", + "@stackage_ghcide//:data-default", + "@stackage_ghcide//:deepseq", + "@stackage_ghcide//:directory", + "@stackage_ghcide//:extra", + "@stackage_ghcide//:filepath", + "@stackage_ghcide//:ghc-check", + "@stackage_ghcide//:ghc-paths", + "@stackage_ghcide//:ghc", + "@stackage_ghcide//:gitrev", + "@stackage_ghcide//:hashable", + "@stackage_ghcide//:haskell-lsp", + "@stackage_ghcide//:haskell-lsp-types", + "@stackage_ghcide//:hie-bios", + "@stackage_ghcide//:ghcide", + "@stackage_ghcide//:optparse-applicative", + "@stackage_ghcide//:shake", + "@stackage_ghcide//:text", + "@stackage_ghcide//:unordered-containers", + ], + visibility = ["//visibility:public"], + ) + """, + # Keep these in sync with ghcide-stack-snapshot.yaml + sha256 = "47cca96a6e5031b3872233d5b9ca14d45f9089da3d45a068e1b587989fec4364", + strip_prefix = "ghcide-39605333c34039241768a1809024c739df3fb2bd", + urls = ["https://github.com/digital-asset/ghcide/archive/39605333c34039241768a1809024c739df3fb2bd.tar.gz"], + ) + +You can test if this worked by building and executing ghcide as follows:: + + bazel build @ghcide//:ghcide + bazel-bin/external/ghcide/_install/bin/ghcide + +Write a small shell script to make it easy to invoke ghcide from your editor:: + + #!/usr/bin/env bash + set -euo pipefail + bazel build @ghcide//:ghcide + bazel-bin/external/ghcide/_install/bin/ghcide "$@" + +And, the last step, configure your editor to use ghcide. The upstream +documentation provides `ghcide setup instructions`_ for a few popular editors. +Note, that if you are using Nix, then you may need to invoke ghcide within a +``nix-shell``. + +.. _ghcide: https://github.com/digital-asset/ghcide +.. _haskell_repl: https://api.haskell.build/haskell/defs.html#haskell_repl +.. _hie-bios: https://github.com/mpickering/hie-bios +.. _bios cradle: https://github.com/mpickering/hie-bios#bios +.. _ghcide's stack.yaml: https://github.com/digital-asset/ghcide/blob/39605333c34039241768a1809024c739df3fb2bd/stack.yaml +.. _ghcide setup instructions: https://github.com/digital-asset/ghcide#using-with-vs-code + Building Cabal packages ----------------------- diff --git a/ghcide-stack-snapshot.yaml b/ghcide-stack-snapshot.yaml index 78d287e57..25c29653b 100644 --- a/ghcide-stack-snapshot.yaml +++ b/ghcide-stack-snapshot.yaml @@ -1,11 +1,10 @@ +# Taken from ghcide's stack.yaml resolver: nightly-2019-09-21 packages: - - github: digital-asset/ghcide - commit: "ff62fdd87de813573167419809273fe07893678d" - sha256: "bdac4be9b2b9254876edefc788d56ff15dbf6d861dc4bf9ad4fa5ffb795e7c0d" - - haskell-lsp-0.20.0.0 - - haskell-lsp-types-0.20.0.0 - - lsp-test-0.10.1.0 + # Taken from the extra-deps field. + - haskell-lsp-0.21.0.0 + - haskell-lsp-types-0.21.0.0 + - lsp-test-0.10.2.0 - hie-bios-0.4.0 - fuzzy-0.1.0.0 - regex-pcre-builtin-0.95.1.1.8.43 @@ -14,3 +13,9 @@ packages: - shake-0.18.5 - parser-combinators-1.2.1 - haddock-library-1.8.0 + - tasty-rerun-1.1.17 + - ghc-check-0.1.0.3 + # Point to the ghcide revision that you would like to use. + - github: digital-asset/ghcide + commit: "39605333c34039241768a1809024c739df3fb2bd" + sha256: "47cca96a6e5031b3872233d5b9ca14d45f9089da3d45a068e1b587989fec4364" From ce5b81b1277c3fe0cb9a648dabd0e29928589245 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Wed, 8 Apr 2020 09:58:15 +0200 Subject: [PATCH 04/16] buildifier-fix --- WORKSPACE | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index df2339931..797660bfc 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -131,11 +131,10 @@ stack_snapshot( haddock = False, local_snapshot = "//:ghcide-stack-snapshot.yaml", packages = [ - "hslogger", "aeson", "base", - "binary", "base16-bytestring", + "binary", "bytestring", "containers", "cryptohash-sha1", @@ -144,15 +143,16 @@ stack_snapshot( "directory", "extra", "filepath", + "ghc", "ghc-check", "ghc-paths", - "ghc", + "ghcide", "gitrev", "hashable", "haskell-lsp", "haskell-lsp-types", "hie-bios", - "ghcide", + "hslogger", "optparse-applicative", "shake", "text", From 5f113fcdb24bdf8e061c29691e28a62fc978f7c2 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Wed, 8 Apr 2020 10:10:51 +0200 Subject: [PATCH 05/16] Add a test-case for ghcide to RunTests.h --- tests/RunTests.hs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/RunTests.hs b/tests/RunTests.hs index afb286397..222f4a759 100644 --- a/tests/RunTests.hs +++ b/tests/RunTests.hs @@ -67,6 +67,10 @@ main = hspec $ do it "allows to manually load modules" $ do assertSuccess (bazel ["run", "//tests/multi_repl:c_multi_repl", "--", "-ignore-dot-ghci", "-e", ":load BC.C", "-e", "c"]) + describe "ghcide" $ do + it "loads RunTests.hs" $ + assertSuccess (Process.proc "./.ghcide" ["tests/RunTests.hs"]) + describe "failures" $ do -- Make sure not to include haskell_repl (@repl) or alias (-repl) targets -- in the query. Those would not fail under bazel test. From b3f776f8f087906eb4e001a521730db68d9e8bbd Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Wed, 8 Apr 2020 10:34:22 +0200 Subject: [PATCH 06/16] Add ghcide smoke test Verifies that the ghcide binary builds and can be executed. Does not test actual loading of sources into ghcide. Also ensures that ghcide is built during the build stage in CI. --- tests/BUILD.bazel | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel index e8b09cad9..8c6bd8730 100644 --- a/tests/BUILD.bazel +++ b/tests/BUILD.bazel @@ -395,3 +395,9 @@ haskell_repl( "//tests:run-tests", ], ) + +sh_test( + name = "ghcide-smoke-test", + srcs = ["@ghcide"], + args = ["--version"], +) From 7339bdf4c75b616871c98c5a45e62654ffc297e7 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Wed, 8 Apr 2020 11:28:22 +0200 Subject: [PATCH 07/16] only use zlib.dev on Nix else zlib.win --> zlib.hs --- WORKSPACE | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index 797660bfc..f4dceaeb4 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -120,14 +120,14 @@ stack_snapshot( # In a separate repo because not all platforms support zlib. stack_snapshot( name = "stackage-zlib", - extra_deps = {"zlib": ["@zlib.win//:zlib" if is_windows else "@zlib.dev//:zlib"]}, + extra_deps = {"zlib": ["@zlib.dev//:zlib" if is_nix_shell else "@zlib.hs//:zlib"]}, packages = ["zlib"], snapshot = test_stack_snapshot, ) stack_snapshot( name = "stackage_ghcide", - extra_deps = {"zlib": ["@zlib.win//:zlib" if is_windows else "@zlib.dev//:zlib"]}, + extra_deps = {"zlib": ["@zlib.dev//:zlib" if is_nix_shell else "@zlib.hs//:zlib"]}, haddock = False, local_snapshot = "//:ghcide-stack-snapshot.yaml", packages = [ @@ -386,7 +386,7 @@ filegroup( ) http_archive( - name = "zlib.win", + name = "zlib.hs", build_file_content = """ load("@rules_cc//cc:defs.bzl", "cc_library") cc_library( From 949eb33bc1cfd4768b002218ef518c101bd9c7e4 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Fri, 17 Apr 2020 12:26:17 +0200 Subject: [PATCH 08/16] .ghcide: Don't hard-code bazel-bin --- .ghcide | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.ghcide b/.ghcide index 43fe7f29a..f1c2c2fa0 100755 --- a/.ghcide +++ b/.ghcide @@ -1,4 +1,13 @@ #!/usr/bin/env bash set -euo pipefail -bazel build @ghcide//:ghcide -bazel-bin/external/ghcide/_install/bin/ghcide "$@" +build_ghcide() { + bazel build @ghcide//:ghcide \ + --experimental_show_artifacts \ + 2>&1 \ + | awk ' + /^>>>/ { print substr($1, 4); next } + { print $0 > "/dev/stderr" } + ' +} +ghcide="$(build_ghcide)" +"$ghcide" "$@" From 0dc31601c36fdc4f1e73ea5157d99032182a8c9f Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Fri, 17 Apr 2020 12:28:09 +0200 Subject: [PATCH 09/16] .hie-bios don't hide error output --- .hie-bios | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.hie-bios b/.hie-bios index eb28c5ba2..0a704c11f 100755 --- a/.hie-bios +++ b/.hie-bios @@ -10,7 +10,12 @@ hie_bios_flags() { while ((getline line < substr($1, 4)) > 0) { print line } - }' + next + } + { + print $0 > "/dev/stderr" + } + ' } if [[ -z "${HIE_BIOS_OUTPUT-}" ]]; then hie_bios_flags From 0b99395c1dcf22ed266e4e8c4ac5980e0835a274 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Wed, 29 Apr 2020 18:10:41 +0200 Subject: [PATCH 10/16] Disable ghcide in profiling mode --- tests/BUILD.bazel | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel index 8c6bd8730..f46f759c4 100644 --- a/tests/BUILD.bazel +++ b/tests/BUILD.bazel @@ -400,4 +400,12 @@ sh_test( name = "ghcide-smoke-test", srcs = ["@ghcide"], args = ["--version"], + tags = [ + # Building ghcide fails in profiling mode with: + # + # exe/Rules.hs:106:28: fatal: + # cannot find object file ‘/run/user/1000/tmp7b54rlve/build/ghcide/ghcide-tmp/Util.dyn_o’ + # while linking an interpreted expression + "requires_dynamic", + ], ) From 90cdf938936e0b0d67050101061c27ec6e337082 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Wed, 6 May 2020 14:01:12 +0200 Subject: [PATCH 11/16] zlib: linkstatic = is_darwin --- WORKSPACE | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/WORKSPACE b/WORKSPACE index f4dceaeb4..7e1d13b76 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -388,6 +388,7 @@ filegroup( http_archive( name = "zlib.hs", build_file_content = """ +load("@os_info//:os_info.bzl", "is_darwin") load("@rules_cc//cc:defs.bzl", "cc_library") cc_library( name = "zlib", @@ -396,9 +397,18 @@ cc_library( srcs = [":z"], hdrs = glob(["*.h"]), includes = ["."], + linkstatic = 1, visibility = ["//visibility:public"], ) -cc_library(name = "z", srcs = glob(["*.c"]), hdrs = glob(["*.h"])) +cc_library( + name = "z", + srcs = glob(["*.c"]), + hdrs = glob(["*.h"]), + # Cabal packages depending on dynamic C libraries fail on MacOS + # due to `-rpath` flags being forwarded indiscriminately. + # See https://github.com/tweag/rules_haskell/issues/1317 + linkstatic = is_darwin, +) """, sha256 = "c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1", strip_prefix = "zlib-1.2.11", From 6741849e46a82379a11a5a9651bff8a2f119a50b Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Fri, 8 May 2020 11:38:28 +0200 Subject: [PATCH 12/16] .hie-bios: Make warnings non-fatal Addressing review comment https://github.com/tweag/rules_haskell/pull/1262#discussion_r421022619 --- .hie-bios | 2 ++ docs/haskell-use-cases.rst | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.hie-bios b/.hie-bios index 0a704c11f..31f3736a8 100755 --- a/.hie-bios +++ b/.hie-bios @@ -16,6 +16,8 @@ hie_bios_flags() { print $0 > "/dev/stderr" } ' + # Make warnings non-fatal + echo -Wwarn } if [[ -z "${HIE_BIOS_OUTPUT-}" ]]; then hie_bios_flags diff --git a/docs/haskell-use-cases.rst b/docs/haskell-use-cases.rst index 83cbf207e..02e3a045b 100644 --- a/docs/haskell-use-cases.rst +++ b/docs/haskell-use-cases.rst @@ -213,6 +213,8 @@ end, define a small shell script named ``.hie-bios`` that looks as follows:: set -euo pipefail bazel build //:hie-bios --output_groups=hie_bios cat bazel-bin/hie-bios@hie-bios >"$HIE_BIOS_OUTPUT" + # Make warnings non-fatal + echo -Wwarn >>"$HIE_BIOS_OUTPUT" Then configure `hie-bios`_ to use this script in the bios cradle with the following ``hie.yaml`` file:: From 5128ac3a7ec9b40d3b40a39f6dcb78a74ea7bb46 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Fri, 8 May 2020 11:43:46 +0200 Subject: [PATCH 13/16] explicit ghcide docs about invoking correct ghcide --- docs/haskell-use-cases.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/haskell-use-cases.rst b/docs/haskell-use-cases.rst index 02e3a045b..30aa564da 100644 --- a/docs/haskell-use-cases.rst +++ b/docs/haskell-use-cases.rst @@ -360,8 +360,9 @@ Write a small shell script to make it easy to invoke ghcide from your editor:: And, the last step, configure your editor to use ghcide. The upstream documentation provides `ghcide setup instructions`_ for a few popular editors. -Note, that if you are using Nix, then you may need to invoke ghcide within a -``nix-shell``. +Be sure to configure your editor to invoke the above wrapper script instead of +another instance of `ghcide`. Also note, that if you are using Nix, then you +may need to invoke ghcide within a ``nix-shell``. .. _ghcide: https://github.com/digital-asset/ghcide .. _haskell_repl: https://api.haskell.build/haskell/defs.html#haskell_repl From c55245674ff382c6443096035192cbb13f5f84a0 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Thu, 28 May 2020 18:02:27 +0200 Subject: [PATCH 14/16] Use static libraries for ghcide The ghcide binary is built as a static binary and uses the static RTS. That means that GHCi's linker within ghcide will not look for dynamic libraries of the form `libHSfoo-ghc8.8.2.so`, but only for static libraries of the form `libHSfoo.a` (oddly also for `libHSfoo.so`). Closes https://github.com/tweag/rules_haskell/issues/1342 --- haskell/repl.bzl | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/haskell/repl.bzl b/haskell/repl.bzl index af2d5366b..328458fbf 100644 --- a/haskell/repl.bzl +++ b/haskell/repl.bzl @@ -25,6 +25,7 @@ load( "deps_HaskellCcLibrariesInfo", "get_cc_libraries", "get_ghci_library_files", + "get_library_files", "haskell_cc_libraries_aspect", "link_libraries", "merge_HaskellCcLibrariesInfo", @@ -222,7 +223,10 @@ def _create_HaskellReplInfo(from_source, from_binary, collect_info): dep_info = dep_info, ) -def _compiler_flags_and_inputs(hs, repl_info, path_prefix = ""): +def _concat(lists): + return [item for l in lists for item in l] + +def _compiler_flags_and_inputs(hs, repl_info, static = False, path_prefix = ""): """Collect compiler flags and inputs. Compiler flags: @@ -238,7 +242,9 @@ def _compiler_flags_and_inputs(hs, repl_info, path_prefix = ""): Args: hs: Haskell context. - args: list of string, output, the arguments to extend. + repl_info: HaskellReplInfo. + static: bool, Whether we're collecting libraries for static RTS. + Contrary to GHCi, ghcide is built as a static executable using the static RTS. path_prefix: string, optional, Prefix for package db paths. Returns: @@ -265,10 +271,11 @@ def _compiler_flags_and_inputs(hs, repl_info, path_prefix = ""): ]) all_libraries = cc_info.linking_context.libraries_to_link.to_list() cc_libraries = get_cc_libraries(cc_libraries_info, all_libraries) - link_libraries( - get_ghci_library_files(hs, cc_libraries_info, cc_libraries), - args, - ) + if static: + cc_library_files = _concat(get_library_files(hs, cc_libraries_info, cc_libraries)) + else: + cc_library_files = get_ghci_library_files(hs, cc_libraries_info, cc_libraries) + link_libraries(cc_library_files, args) # The `-pgmP` argument needs to be quoted. args.extend([ @@ -282,10 +289,14 @@ def _compiler_flags_and_inputs(hs, repl_info, path_prefix = ""): for import_dir in repl_info.load_info.import_dirs.to_list(): args.append("-i" + (import_dir if import_dir else ".")) + if static: + all_library_files = _concat(get_library_files(hs, cc_libraries_info, all_libraries)) + else: + all_library_files = get_ghci_library_files(hs, cc_libraries_info, all_libraries) inputs = depset(transitive = [ repl_info.load_info.source_files, repl_info.dep_info.package_databases, - depset(get_ghci_library_files(hs, cc_libraries_info, all_libraries)), + depset(all_library_files), depset([hs.toolchain.locale_archive] if hs.toolchain.locale_archive else []), ]) @@ -398,7 +409,7 @@ def _create_hie_bios(hs, posix, ctx, repl_info): List of providers: OutputGroupInfo provider for the hie-bios argument file. """ - args, inputs = _compiler_flags_and_inputs(hs, repl_info) + args, inputs = _compiler_flags_and_inputs(hs, repl_info, static = True) args.extend(hs.toolchain.compiler_flags) args.extend(repl_info.load_info.compiler_flags) From d13bee86186c6561ab43b657a8fdef744cd4b807 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Fri, 29 May 2020 11:54:02 +0200 Subject: [PATCH 15/16] Update ghcide to GHC 8.8 --- WORKSPACE | 6 +++--- ghcide-stack-snapshot.yaml | 26 +++++++++----------------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index 7e1d13b76..12bece874 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -198,9 +198,9 @@ haskell_cabal_binary( visibility = ["//visibility:public"], ) """, - sha256 = "47cca96a6e5031b3872233d5b9ca14d45f9089da3d45a068e1b587989fec4364", - strip_prefix = "ghcide-39605333c34039241768a1809024c739df3fb2bd", - urls = ["https://github.com/digital-asset/ghcide/archive/39605333c34039241768a1809024c739df3fb2bd.tar.gz"], + sha256 = "fa1f0cfb0357e7bfa6c86076493f038e0ea5fcd75c470473f2ede7e32566cd9a", + strip_prefix = "ghcide-0c9a0961abbeef851b4117e6408f15a6d46eb1f1", + urls = ["https://github.com/digital-asset/ghcide/archive/0c9a0961abbeef851b4117e6408f15a6d46eb1f1.tar.gz"], ) load( diff --git a/ghcide-stack-snapshot.yaml b/ghcide-stack-snapshot.yaml index 25c29653b..a02ec25e6 100644 --- a/ghcide-stack-snapshot.yaml +++ b/ghcide-stack-snapshot.yaml @@ -1,21 +1,13 @@ -# Taken from ghcide's stack.yaml -resolver: nightly-2019-09-21 +# Taken from ghcide's stack88.yaml +resolver: nightly-2020-02-13 packages: # Taken from the extra-deps field. - - haskell-lsp-0.21.0.0 - - haskell-lsp-types-0.21.0.0 - - lsp-test-0.10.2.0 - - hie-bios-0.4.0 - - fuzzy-0.1.0.0 - - regex-pcre-builtin-0.95.1.1.8.43 - - regex-base-0.94.0.0 - - regex-tdfa-1.3.1.0 - - shake-0.18.5 - - parser-combinators-1.2.1 - - haddock-library-1.8.0 - - tasty-rerun-1.1.17 - - ghc-check-0.1.0.3 + - haskell-lsp-0.22.0.0 + - haskell-lsp-types-0.22.0.0 + - lsp-test-0.11.0.1 + - ghc-check-0.3.0.1 + - hie-bios-0.5.0 # Point to the ghcide revision that you would like to use. - github: digital-asset/ghcide - commit: "39605333c34039241768a1809024c739df3fb2bd" - sha256: "47cca96a6e5031b3872233d5b9ca14d45f9089da3d45a068e1b587989fec4364" + commit: "0c9a0961abbeef851b4117e6408f15a6d46eb1f1" + sha256: "fa1f0cfb0357e7bfa6c86076493f038e0ea5fcd75c470473f2ede7e32566cd9a" From da560fd41428b0bdfbc4c444c45779934437cd92 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Fri, 29 May 2020 12:09:24 +0200 Subject: [PATCH 16/16] Fix -pgm argument quoting for hie-bios The -pgm arguments contain spaces and need to be quoted for the REPL script. However, hie-bios expects unquoted arguments one per line of the hie-bios file. --- haskell/repl.bzl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/haskell/repl.bzl b/haskell/repl.bzl index 328458fbf..34fe0feec 100644 --- a/haskell/repl.bzl +++ b/haskell/repl.bzl @@ -277,14 +277,6 @@ def _compiler_flags_and_inputs(hs, repl_info, static = False, path_prefix = ""): cc_library_files = get_ghci_library_files(hs, cc_libraries_info, cc_libraries) link_libraries(cc_library_files, args) - # The `-pgmP` argument needs to be quoted. - args.extend([ - '"{}"'.format(arg) - for arg in ghc_cc_program_args( - paths.join(path_prefix, hs.toolchain.cc_wrapper.executable.path), - ) - ]) - # Add import directories for import_dir in repl_info.load_info.import_dirs.to_list(): args.append("-i" + (import_dir if import_dir else ".")) @@ -323,6 +315,13 @@ def _create_repl(hs, posix, ctx, repl_info, output): compiler_flags, inputs = _compiler_flags_and_inputs(hs, repl_info, path_prefix = "$RULES_HASKELL_EXEC_ROOT") args.extend(compiler_flags) + args.extend([ + '"{}"'.format(arg) + for arg in ghc_cc_program_args(paths.join( + "$RULES_HASKELL_EXEC_ROOT", + hs.toolchain.cc_wrapper.executable.path, + )) + ]) # Load source files # Force loading by source with `:add *...`. @@ -410,6 +409,7 @@ def _create_hie_bios(hs, posix, ctx, repl_info): OutputGroupInfo provider for the hie-bios argument file. """ args, inputs = _compiler_flags_and_inputs(hs, repl_info, static = True) + args.extend(ghc_cc_program_args(hs.toolchain.cc_wrapper.executable.path)) args.extend(hs.toolchain.compiler_flags) args.extend(repl_info.load_info.compiler_flags)