How can I know in advance where cabal will place a generated executable?

Viewed 344

When I run cabal build for my project, it places my compiled executable in

dist-newstyle/build/$PLATFORM/$GHC/$PACKAGE-$VERSION/x/$PACKAGE/build/$PACKAGE/$PACKAGE

I'm using a Makefile to run cabal build as needed when I need to run the executable.

Since I'm working on different platforms at various times, I need a way to tell my Makefile what to expect the $PLATFORM value to be.

There's a couple ways I could go about this:

  • run cabal build once unconditionally, and then use wildcards:

    BIN := $(wildcard dist-newstyle/build/*/ghc-*/foo-*/x/foo/build/foo/foo)
    
  • use uname to predict what the platform will be

    BIN := dist-newstyle/build/$(shell uname -m)-$(shell uname -s | some magic)/ghc-$(shell ghc --version | some magic)/foo-$(VERSION)/x/foo/build/foo/foo
    
  • give up on making sure the binary is up to date within the Makefile and just run cabal run unconditionally

Any of those would work, but I would like to know if I could just ask cabal to tell me where it expects to place an executable.

Is there a cabal command I can run to tell me what $PLATFORM and/or $GHC values it detects?

3 Answers

Say you just ran cabal build and produced a foo binary somewhere in the dist-newstyle/ directory. You can now run:

cabal exec which foo

This will print out the absolute path to the foo executable.

Note: It may be necessary to run cabal exec --verbose=0 which foo so that cabal does not print out extra information about packages or configuration.

Why does this work?

cabal exec lets you run commands with the same environment used when running other cabal commands, like cabal build. So you can run printenv and cabal exec printenv to see how it adds and changes some environment variables. Notice that it adds the whole dist-newstyle/ path to your PATH variable!

So saying cabal exec which foo works because it is just like running which foo, but with the extended PATH variable.

This means you can extract the dist-newstyle/ path itself using a fancier command:

cabal exec --verbose=0 printenv PATH | tr ':' '\n' | grep dist-newstyle | head -1

This may be useful if you need to know the path before you run cabal build, in which case the binary will not exist yet.

cabal exec which $EXENAME$ will give you the full path of the compiled executable.

Since cabal 3.8, you can use the list-bin command:

$ cabal list-bin my-executable-name

That will print the path at which cabal will place the executable if built. Note that it doesn't actually guarantee that the executable is built, so depending on your use case you might want to check that too.

Related