Cabal install binary to a directory

Hi,

My dahastes.cabal:

...
executable dahastes
  import:         common-options
  hs-source-dirs: app
  main-is:        Main.hs
  build-depends:
    , dahastes
    , turtle
    , text
    , foldl
    , extra
  ghc-options:    -threaded -rtsopts -with-rtsopts=-N

...

I’ve been trying this:

!?master ~/spaces/haskell/dahastes> cabal install exe:dahastes --installdir="~/.local/bin"
Wrote tarball sdist to
/home/alexey/spaces/haskell/dahastes/dist-newstyle/sdist/dahastes-0.tar.gz
Resolving dependencies...
Symlinking 'dahastes' to '~/.local/bin/dahastes'
!?master ~/spaces/haskell/dahastes> ls
'~'   app   bench   BUILDME.md   cabal.project   CHANGELOG.md   dahastes.cabal   dist-newstyle   flake.lock   flake.nix   hie.yaml   LICENSE   README.md   src   test
!?master ~/spaces/haskell/dahastes> ls '~'
!?master ~/spaces/haskell/dahastes> rm -rf '~'

Looks almost sensible, but I’ve got two problems:

  1. No symlink in ~/.local/bin. No real surprise: I expected a binary in ~/.local/bin, and was promised a symlink to ~/.local/bin, God knows where.
  2. It created an empty '~' directory in my project directory, which looks suspicious to me.

I hope my intention is clear: install a project executive to a common bin directory. What am I doing wrong?

I don’t think you are doing anything wrong, this simply looks like a bug.

Perhaps you could report this as a ticket in the cabal github issue tracker? No need to change the text, it is good as is.

Sounds incredible. I guess people install their binaries all the time, but another way. How, I wonder :blush:

In case you wonder the absolute path does work: cabal install ... --installdir=/home/<user>/.local/bin

I can reproduce it, but In my computer the ‘~’ isnt empty. You have to list all folders

> ls -a \~
.  ..  .local

My gues is that cabal uses the current dir if no absolute path is passed to --installdir

Notice installdir defaults to ~/.local/bin so you can just run cabal install exe:dahastes. Also, if you want the binary instead of a symlink

# by default cabal wont overwrite a binary/symlink if one already exist.
cabal install exe:dahastes --install-method=copy --overwrite-policy=always
1 Like

Thank you very much!

Absolute path, yes… While awaiting the answer, I figured out on my own:

cabal install exe:dahastes --installdir=${HOME}/.local/bin

This is not a bug.

Tilde expansion is done by the shell: Shell Command Language

If you quote (like OP did), it’s not supposed to be expanded. A tilde infix is also not supposed to be expanded (--foo=~/tmp is infix tilde).

Programs are not supposed to interpret tilde.


To reproduce, create Main.hs:

module Main where

import System.Environment

main :: IO ()
main = do
  getArgs >>= print

Compile it: ghc Main.hs

Then run:

$ ./Main ~/tmp
["/home/hasufell/tmp"]
$ ./Main "~/tmp"
["~/tmp"]
$ ./Main '~/tmp'
["~/tmp"]
$ ./Main --foo=~/tmp
["--foo=~/tmp"]
$ ./Main --foo="~/tmp"
["--foo=~/tmp"]


So this works fine:

cabal install --installdir ~/.local/bin --overwrite-policy=always --install-method=copy darcs
8 Likes

Thanks @hasufell, that is a useful explanation.

1 Like

I always just build and then get the executable from the build directory :man_shrugging:

(I mainly use stack build, which also builds binaries. Not sure if cabal build does the same, but I expect it would?)