Search code examples
pluginshookcustomizationcabal

Custom fields that somehow get all the way to buildHook?


I would like to pass some custom, per-executable/library configurations (ideally a whole bag of key-value pairs, but at the very least a single String) from my .cabal file all the way to Setup.hs's buildHook.

For reference, buildHook's parameters are:

buildHook 
    :: PackageDescription 
    -> LocalBuildInfo
    -> UserHooks
    -> BuildFlags -> IO ()

So what I am hoping for is something in the PackageDescription's library / executables field that gives me access to custom fields, without disrupting all other Cabal phases, that I could put in the .cabal file. Here's a made-up example that would basically be as good as it gets:

...

executable my-exe
  main-is: my-main.hs
  ...
  plugin-args:
    myplugin:
      foo: bar
      baz: quux 

so I could retrieve all myplugin key/value pairs to get "foo" |-> "bar", "baz" |-> "quux" in some kind of associative data structure like HashMap.

Note that I am already doing intense violence in my Setup.hs, so any kind of hacky suggestions are welcome. If need be, I can override ALL Setup.hs hooks to ignore some settings in everything-but-buildHook, if that is needed for some solution.


Solution

  • Although I haven't found it in the user documentation, there is this nugget in the BuildInfo type:

    customFieldsBI :: [(String, String)]
    

    Custom fields starting with x-, stored in a simple assoc-list.

    So it turns out you can write

    ...
    executable my-exe
      main-is: my-main.hs
      ...
      plugin-args:
        x-myplugin: foo
    

    and then access it with lookup "x-myplugin" . view customFieldsBI :: (HasBuildInfo bi) => bi -> Maybe String.

    In particular, Executable and Library has HasBuildInfo instances, so you can just traverse the PackageDescription in buildHook and process their String value there.