From d725ac794286e3464d80f5bce69da98ff4b2ebbf Mon Sep 17 00:00:00 2001
From: Isaac Shapira <fresheyeball@protonmail.com>
Date: Fri, 23 Apr 2021 13:55:38 -0600
Subject: [PATCH 1/3] Add haskell.lib.setBuiltTarget, and support non library
 compiling of a single target

---
 .../haskell-modules/generic-builder.nix       |  7 ++++-
 pkgs/development/haskell-modules/lib.nix      | 10 +++++++
 pkgs/test/haskell/default.nix                 |  1 +
 pkgs/test/haskell/setBuildTarget/Bar.hs       |  4 +++
 pkgs/test/haskell/setBuildTarget/Foo.hs       |  4 +++
 pkgs/test/haskell/setBuildTarget/Setup.hs     |  2 ++
 pkgs/test/haskell/setBuildTarget/default.nix  | 26 +++++++++++++++++++
 .../haskell-setBuildTarget.cabal              | 16 ++++++++++++
 8 files changed, 69 insertions(+), 1 deletion(-)
 create mode 100644 pkgs/test/haskell/setBuildTarget/Bar.hs
 create mode 100644 pkgs/test/haskell/setBuildTarget/Foo.hs
 create mode 100644 pkgs/test/haskell/setBuildTarget/Setup.hs
 create mode 100644 pkgs/test/haskell/setBuildTarget/default.nix
 create mode 100644 pkgs/test/haskell/setBuildTarget/haskell-setBuildTarget.cabal

diff --git a/pkgs/development/haskell-modules/generic-builder.nix b/pkgs/development/haskell-modules/generic-builder.nix
index faf80da0c7d9..2f9127e30f3b 100644
--- a/pkgs/development/haskell-modules/generic-builder.nix
+++ b/pkgs/development/haskell-modules/generic-builder.nix
@@ -464,7 +464,12 @@ stdenv.mkDerivation ({
   installPhase = ''
     runHook preInstall
 
-    ${if !isLibrary then "${setupCommand} install" else ''
+    ${if !isLibrary && buildTarget == "" then "${setupCommand} install"
+      # ^^ if the project is not a library, and no build target is specified, we can just use "install".
+      else if !isLibrary then "${setupCommand} copy ${buildTarget}"
+      # ^^ if the project is not a library, and we have a build target, then use "copy" to install
+      # just the target specified; "install" will error here, since not all targets have been built.
+    else ''
       ${setupCommand} copy
       local packageConfDir="$out/lib/${ghc.name}/package.conf.d"
       local packageConfFile="$packageConfDir/${pname}-${version}.conf"
diff --git a/pkgs/development/haskell-modules/lib.nix b/pkgs/development/haskell-modules/lib.nix
index 1537cd6466cd..682953c3ce9c 100644
--- a/pkgs/development/haskell-modules/lib.nix
+++ b/pkgs/development/haskell-modules/lib.nix
@@ -196,6 +196,16 @@ rec {
   appendPatch = drv: x: appendPatches drv [x];
   appendPatches = drv: xs: overrideCabal drv (drv: { patches = (drv.patches or []) ++ xs; });
 
+  /* Set a specific build target instead of compiling all targets in the package.
+   * For example, imagine we have a .cabal file with a library, and 2 executables "dev" and "server".
+   * We can build only "server" and not wait on the compilation of "dev" by useing setBuildTarget as follows:
+   *
+   *   setBuildTarget (callCabal2nix "thePackageName" thePackageSrc {}) "server"
+   *
+   */
+  setBuildTargets = drv: xs: overrideCabal drv (drv: { buildTarget = lib.concatStringsSep " " xs; });
+  setBuildTarget = drv: x: setBuildTargets drv [x];
+
   doHyperlinkSource = drv: overrideCabal drv (drv: { hyperlinkSource = true; });
   dontHyperlinkSource = drv: overrideCabal drv (drv: { hyperlinkSource = false; });
 
diff --git a/pkgs/test/haskell/default.nix b/pkgs/test/haskell/default.nix
index 8171f929311b..eb389f4051f8 100644
--- a/pkgs/test/haskell/default.nix
+++ b/pkgs/test/haskell/default.nix
@@ -3,4 +3,5 @@
 lib.recurseIntoAttrs {
   shellFor = callPackage ./shellFor { };
   documentationTarball = callPackage ./documentationTarball { };
+  setBuildTarget = callPackage ./setBuildTarget { };
 }
diff --git a/pkgs/test/haskell/setBuildTarget/Bar.hs b/pkgs/test/haskell/setBuildTarget/Bar.hs
new file mode 100644
index 000000000000..010014082c7d
--- /dev/null
+++ b/pkgs/test/haskell/setBuildTarget/Bar.hs
@@ -0,0 +1,4 @@
+module Main where
+
+main :: IO ()
+main = putStrLn "Hello, Bar!"
diff --git a/pkgs/test/haskell/setBuildTarget/Foo.hs b/pkgs/test/haskell/setBuildTarget/Foo.hs
new file mode 100644
index 000000000000..fec7bb11fe6c
--- /dev/null
+++ b/pkgs/test/haskell/setBuildTarget/Foo.hs
@@ -0,0 +1,4 @@
+module Main where
+
+main :: IO ()
+main = putStrLn "Hello, Foo!"
diff --git a/pkgs/test/haskell/setBuildTarget/Setup.hs b/pkgs/test/haskell/setBuildTarget/Setup.hs
new file mode 100644
index 000000000000..9a994af677b0
--- /dev/null
+++ b/pkgs/test/haskell/setBuildTarget/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/pkgs/test/haskell/setBuildTarget/default.nix b/pkgs/test/haskell/setBuildTarget/default.nix
new file mode 100644
index 000000000000..161cecd9ec37
--- /dev/null
+++ b/pkgs/test/haskell/setBuildTarget/default.nix
@@ -0,0 +1,26 @@
+{ pkgs, haskellPackages }: with pkgs.haskell.lib;
+
+
+let
+  drv     = haskellPackages.callCabal2nix "haskell-setBuildTarget" ./. {};
+  test    = target: excluded:
+
+    let only = setBuildTarget drv target;
+    in ''
+         if [[ ! -f "${only}/bin/${target}" ]]; then
+           echo "${target} was not built"
+           exit 1
+         fi
+
+         if [[ -f "${only}/bin/${excluded}" ]]; then
+           echo "${excluded} was built, when it should not have been"
+           exit 1
+         fi
+     '';
+
+in pkgs.runCommand "test haskell.lib.setBuildTarget" {} ''
+  ${test "foo" "bar"}
+  ${test "bar" "foo"}
+  touch "$out"
+''
+
diff --git a/pkgs/test/haskell/setBuildTarget/haskell-setBuildTarget.cabal b/pkgs/test/haskell/setBuildTarget/haskell-setBuildTarget.cabal
new file mode 100644
index 000000000000..7395e139451c
--- /dev/null
+++ b/pkgs/test/haskell/setBuildTarget/haskell-setBuildTarget.cabal
@@ -0,0 +1,16 @@
+cabal-version:       >=1.10
+name:                haskell-setBuildTarget
+version:             0.1.0.0
+author:              Isaac Shapira
+maintainer:          fresheyeball@protonmail.com
+build-type:          Simple
+
+executable foo
+  main-is:             Foo.hs
+  build-depends:       base
+  default-language:    Haskell2010
+
+executable bar
+  main-is:             Bar.hs
+  build-depends:       base
+  default-language:    Haskell2010

From ba354d5ad802cdba3bf3d7436385020fa07a30b9 Mon Sep 17 00:00:00 2001
From: Dennis Gosnell <cdep.illabout@gmail.com>
Date: Sun, 25 Apr 2021 16:16:25 +0900
Subject: [PATCH 2/3] haskell.lib.setBuildTargets: fix spelling in doc string

---
 pkgs/development/haskell-modules/lib.nix | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pkgs/development/haskell-modules/lib.nix b/pkgs/development/haskell-modules/lib.nix
index 682953c3ce9c..b0d036e0e3e8 100644
--- a/pkgs/development/haskell-modules/lib.nix
+++ b/pkgs/development/haskell-modules/lib.nix
@@ -198,7 +198,7 @@ rec {
 
   /* Set a specific build target instead of compiling all targets in the package.
    * For example, imagine we have a .cabal file with a library, and 2 executables "dev" and "server".
-   * We can build only "server" and not wait on the compilation of "dev" by useing setBuildTarget as follows:
+   * We can build only "server" and not wait on the compilation of "dev" by using setBuildTarget as follows:
    *
    *   setBuildTarget (callCabal2nix "thePackageName" thePackageSrc {}) "server"
    *

From 88d9f2419e58b1570e0fed5d9a871f72b9423855 Mon Sep 17 00:00:00 2001
From: "(cdep)illabout" <cdep.illabout@gmail.com>
Date: Fri, 30 Apr 2021 12:12:07 +0900
Subject: [PATCH 3/3] tests.haskell-setBuildTarget: inline haskell package def
 to avoid IFD

---
 pkgs/test/haskell/setBuildTarget/default.nix | 22 +++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)

diff --git a/pkgs/test/haskell/setBuildTarget/default.nix b/pkgs/test/haskell/setBuildTarget/default.nix
index 161cecd9ec37..b1335e2a74cf 100644
--- a/pkgs/test/haskell/setBuildTarget/default.nix
+++ b/pkgs/test/haskell/setBuildTarget/default.nix
@@ -1,11 +1,23 @@
-{ pkgs, haskellPackages }: with pkgs.haskell.lib;
-
+{ pkgs, haskellPackages }:
 
 let
-  drv     = haskellPackages.callCabal2nix "haskell-setBuildTarget" ./. {};
-  test    = target: excluded:
+  # This can be regenerated by running `cabal2nix .` in the current directory.
+  pkgDef =
+    { mkDerivation, base, lib }:
+      mkDerivation {
+        pname = "haskell-setBuildTarget";
+        version = "0.1.0.0";
+        src = ./.;
+        isLibrary = false;
+        isExecutable = true;
+        executableHaskellDepends = [ base ];
+        license = lib.licenses.bsd3;
+      };
 
-    let only = setBuildTarget drv target;
+  drv = haskellPackages.callPackage pkgDef {};
+
+  test  = target: excluded:
+    let only = pkgs.haskell.lib.setBuildTarget drv target;
     in ''
          if [[ ! -f "${only}/bin/${target}" ]]; then
            echo "${target} was not built"