title: Running a custom per-component `IO ()` before building components, interleaved with actual building
body: <p>I have a per-component custom action that I would like to run before the given component is built:</p>
  <pre><code>justBeforeBuilding :: LocalBuildInfo -&gt; BuildFlags -&gt; Component -&gt; IO BuildInfo
  </code></pre>
  <p>Because the action might require dependencies to be already built, for example, if a given Cabal package has both a library and executables using that library, it is important that each component's <code>justBeforeBuilding</code> is run only before the actual component is built, but after all its dependencies are built.</p>
  <p>So here's what I tried: instead of calling the default build hook once, I go over all enabled components one by one in dependency order, call my <code>justBeforeBuilding</code> function, and then sneakily change the <code>buildArgs</code> so that the default build hook would only build the single current component:</p>
  <pre><code>restrictBuildFlags :: PackageDescription -&gt; Component -&gt; BuildFlags -&gt; BuildFlags
  restrictBuildFlags pkg c buildFlags = buildFlags
      { buildArgs = selectedArgs
      }
    where
      selectedArgs = [showBuildTarget (packageId pkg) $ BuildTargetComponent $ componentName c]
  
  type BuildHook = PackageDescription -&gt; LocalBuildInfo -&gt; UserHooks -&gt; BuildFlags -&gt; IO ()
  
  myBuildHook :: BuildHook -&gt; BuildHook
  myBuildHook nextBuildHook pkg lbi userHooks flags = do
      let reqSpec = componentEnabledSpec lbi
      withAllComponentsInBuildOrder pkg lbi $ \c clbi -&gt; do
          flags &lt;- return $ restrictBuildFlags pkg c flags
          when (componentEnabled reqSpec c &amp;&amp; not (null $ buildArgs flags)) $ do
              justBeforeBuilding lbi flags c
              nextBuildHook pkg lbi userHooks flags
  
  main :: IO ()
  main = defaultMainWithHooks simpleUserHooks
      { buildHook = myBuildHook $ buildHook simpleUserHooks
      }
  </code></pre>
  <p>The problem is that when <code>justBeforeBuilding</code> runs, it does not have access to library dependencies <strong>even if they are already built by that point</strong>. To demonstrate, here's a function that prints the contents of the Cabal-provided package DBs:</p>
  <pre><code>justBeforeBuilding :: LocalBuildInfo -&gt; BuildFlags -&gt; Component -&gt; IO ()
  justBeforeBuilding lbi flags c = do
      pkgdbs &lt;- absolutePackageDBPaths $ withPackageDB lbi
      let dbpaths = nub . sort $ [ path | SpecificPackageDB path &lt;- pkgdbs ]
          dbflags = concat [ [&quot;-package-db&quot;, path] | path &lt;- dbpaths ]
  
      putStrLn $ &quot;!!! Processing component &quot; &lt;&gt; show (componentName c)
      putStrLn &quot;!!! At this point, the package DB paths are:&quot;
      forM_ dbpaths $ \dir -&gt; do
          putStrLn dir
          files &lt;- listDirectory dir
          mapM_ (printf &quot;    %s\n&quot;) files
  </code></pre>
  <p>For testing, I am using a Cabal package with one library and one exe; in HPack format:</p>
  <pre><code>name: cabal-component-hook
  version: 0.1.0
  
  custom-setup:
    dependencies:
      - base
      - Cabal
      - directory
  
  dependencies:
    - base &gt;= 4.7 &amp;&amp; &lt; 5
  
  library:
    source-dirs: lib
    exposed-modules:
      - Foo
      
  executables:
    bar:
      source-dirs: app
      main: bar.hs
      dependencies:
        - cabal-component-hook
  </code></pre>
  <p>If I then do a <code>stack build</code>, first, the library is built, and the package DB of course doesn't contain the library yet:</p>
  <pre><code>!!! Processing component CLibName LMainLibName
  !!! At this point, the package DB paths are:
  /home/cactus/prog/clash/bugs/cabal-component-hook/.stack-work/install/x86_64-linux-tinfo6/82781a0829e0e0da301c1db4825858dea8980a6a982b679eb178870c6c0ec1ee/8.10.4/pkgdb
      package.cache.lock
      package.cache
  /home/cactus/sdk/stack/snapshots/x86_64-linux-tinfo6/82781a0829e0e0da301c1db4825858dea8980a6a982b679eb178870c6c0ec1ee/8.10.4/pkgdb
      package.cache.lock
      StateVar-1.2.1-7vo3tV8mPssJqOV48TU4OF.conf
      call-stack-0.2.0-4YzMVPI02PxAK0TxyBY7Iv.conf
      cabal-doctest-1.0.8-I4vvWDvrsGA6v5uZj1lZJi.conf
      base-orphans-0.8.4-JVJ8ttw51H7Dc3tJYgx6uK.conf
      parallel-3.2.2.0-HTf2o2horULDwL7cXUB9uv.conf
      hashable-1.3.0.0-K3FFBNAmsvaIvBv4Qg15rQ.conf
      semigroups-0.19.1-CdJZL8lQRXTEuOuxFhFNIa.conf
      contravariant-1.5.3-A4NbUFeaP6W4UzkL1ejoXa.conf
      indexed-traversable-0.1.1-Dw8MIJyvCj8IZQDXOa8TBp.conf
      tagged-0.8.6.1-A3E8I7zg2qBFE9O5vQsg6C.conf
      void-0.7.3-FJLCa6y31Qt20kSi8TCcBC.conf
      transformers-compat-0.6.6-CZr4aajtyBTi4Enjszw8H.conf
      reflection-2.1.6-CzOlI803nFuvt8AikdOut.conf
      distributive-0.6.2.1-Lhog8B4NdHk7JJdshqpkhJ.conf
      transformers-base-0.4.5.2-2JwY8UMK4YFHH9faaNEDAI.conf
      th-abstraction-0.4.2.0-CPMLTlyMgmr6dbHxHL95CG.conf
      comonad-5.0.8-EA0Scey7jOW6LX5RvNTIb8.conf
      primitive-0.7.1.0-Jxsyd70oUttYiCXCa0HqV.conf
      unordered-containers-0.2.13.0-3awuPgUx2yvAACRZkw6am3.conf
      bifunctors-5.5.10-1Xyw3zBBKdPGoolSEEYrSo.conf
      profunctors-5.5.2-Jd7sxJvE4zaBkftBvoi6oJ.conf
      semigroupoids-5.3.5-A5MCqcbuwFnHzZu6aqZxm4.conf
      invariant-0.5.4-Ca6182XTMBJ4627vLKNFdU.conf
      free-5.1.5-JCTHYv08sV0j7gsEXshfc.conf
      adjunctions-4.4-4Q0IXuLBVoCBKmI2ZpS7bE.conf
      kan-extensions-5.2.2-Z55rpCSAQY7rC9ino1jlr.conf
      vector-0.12.1.2-6jlbObSa8iuJfxUVGBQC5r.conf
      lens-4.19.2-86eTsWPqcVQ3qs5KiS7cYu.conf
      package.cache
  Preprocessing library for cabal-component-hook-0.1.0..
  Building library for cabal-component-hook-0.1.0..
  [1 of 2] Compiling Foo
  [2 of 2] Compiling Paths_cabal_component_hook
  </code></pre>
  <p>However, then the executable is built, <strong>and the package DB still doesn't contain the just-built library</strong>:</p>
  <pre><code>!!! Processing component CExeName (UnqualComponentName &quot;bar&quot;)
  !!! At this point, the package DB paths are:
  /home/cactus/prog/clash/bugs/cabal-component-hook/.stack-work/install/x86_64-linux-tinfo6/82781a0829e0e0da301c1db4825858dea8980a6a982b679eb178870c6c0ec1ee/8.10.4/pkgdb
      package.cache.lock
      package.cache
  /home/cactus/sdk/stack/snapshots/x86_64-linux-tinfo6/82781a0829e0e0da301c1db4825858dea8980a6a982b679eb178870c6c0ec1ee/8.10.4/pkgdb
      package.cache.lock
      StateVar-1.2.1-7vo3tV8mPssJqOV48TU4OF.conf
      call-stack-0.2.0-4YzMVPI02PxAK0TxyBY7Iv.conf
      cabal-doctest-1.0.8-I4vvWDvrsGA6v5uZj1lZJi.conf
      base-orphans-0.8.4-JVJ8ttw51H7Dc3tJYgx6uK.conf
      parallel-3.2.2.0-HTf2o2horULDwL7cXUB9uv.conf
      hashable-1.3.0.0-K3FFBNAmsvaIvBv4Qg15rQ.conf
      semigroups-0.19.1-CdJZL8lQRXTEuOuxFhFNIa.conf
      contravariant-1.5.3-A4NbUFeaP6W4UzkL1ejoXa.conf
      indexed-traversable-0.1.1-Dw8MIJyvCj8IZQDXOa8TBp.conf
      tagged-0.8.6.1-A3E8I7zg2qBFE9O5vQsg6C.conf
      void-0.7.3-FJLCa6y31Qt20kSi8TCcBC.conf
      transformers-compat-0.6.6-CZr4aajtyBTi4Enjszw8H.conf
      reflection-2.1.6-CzOlI803nFuvt8AikdOut.conf
      distributive-0.6.2.1-Lhog8B4NdHk7JJdshqpkhJ.conf
      transformers-base-0.4.5.2-2JwY8UMK4YFHH9faaNEDAI.conf
      th-abstraction-0.4.2.0-CPMLTlyMgmr6dbHxHL95CG.conf
      comonad-5.0.8-EA0Scey7jOW6LX5RvNTIb8.conf
      primitive-0.7.1.0-Jxsyd70oUttYiCXCa0HqV.conf
      unordered-containers-0.2.13.0-3awuPgUx2yvAACRZkw6am3.conf
      bifunctors-5.5.10-1Xyw3zBBKdPGoolSEEYrSo.conf
      profunctors-5.5.2-Jd7sxJvE4zaBkftBvoi6oJ.conf
      semigroupoids-5.3.5-A5MCqcbuwFnHzZu6aqZxm4.conf
      invariant-0.5.4-Ca6182XTMBJ4627vLKNFdU.conf
      free-5.1.5-JCTHYv08sV0j7gsEXshfc.conf
      adjunctions-4.4-4Q0IXuLBVoCBKmI2ZpS7bE.conf
      kan-extensions-5.2.2-Z55rpCSAQY7rC9ino1jlr.conf
      vector-0.12.1.2-6jlbObSa8iuJfxUVGBQC5r.conf
      lens-4.19.2-86eTsWPqcVQ3qs5KiS7cYu.conf
      package.cache
  Preprocessing library for cabal-component-hook-0.1.0..
  Building library for cabal-component-hook-0.1.0..
  Preprocessing executable 'bar' for cabal-component-hook-0.1.0..
  Building executable 'bar' for cabal-component-hook-0.1.0..
  [1 of 2] Compiling Main
  [2 of 2] Compiling Paths_cabal_component_hook
  Linking .stack-work/dist/x86_64-linux-tinfo6/Cabal-3.2.1.0/build/bar/bar ...
  </code></pre>
  <p>At the end of this whole process, though the package DB directory is correctly populated:</p>
  <pre><code>/home/cactus/prog/clash/bugs/cabal-component-hook/.stack-work/install/x86_64-linux-tinfo6/82781a0829e0e0da301c1db4825858dea8980a6a982b679eb178870c6c0ec1ee/8.10.4/pkgdb
  ├── cabal-component-hook-0.1.0-8kPvy0LMfqKAbvXmH5zWaP.conf
  ├── package.cache
  └── package.cache.lock
  </code></pre>
  <p>So my question is, <strong>how can I arrange for <code>justBeforeBuilding</code> to run just before building each individual component, when its dependencies are already <em>fully</em> processed, i.e. library dependencies are copied to the build-internal package DB?</strong></p>