cabal
cabal copied to clipboard
"cabal new-exec ghc" should work outside of .cabal projects
Nearly half my time in Haskell development is spend running ghc
on individual files, outside of .cabal
projects, which might have some number of dependencies. Prevously, I could just old-install
all of my dependencies, point ghc
to the right file, and everything would Just Work™. Unfortunately, there isn't really a new-*
equivalent of this. There's cabal new-exec ghc
, but that assumes that you're in a .cabal
project, which usually isn't the case for me.
Similarly to how you can run cabal new-repl -b dep1,...,depn
outside of a .cabal
project today, I'd like to request that cabal new-exec -b dep1,...,depn ghc -- Foo.hs
work outside of .cabal
projects. This would operate conceptually in a similar manner to stack exec ghc
.
cc @phadej
See https://github.com/haskell/cabal/issues/5544#issuecomment-442106712 for a similar feature request for cabal new-repl -b dep1,...,depn Foo.hs
.
Because we cannot know for sure what compiler user will use in a v2-exec
shell, I'll propose that we'll setup
-
HC
- points toghc
orghcjs
or ... -
HCFLAGS
needed flags (to find package-db) -
HCPKG
-ghc-pkg
analogue - and maybe others
Then, however
cabal new-exec -w /some/local/ghc -b dep1,dep2,dep3 $HC $HCPKG -- Foo.hs
wont work as environment variables are expanded too early. Maybe we could use shell aliases (when shell supports such), with hc = $HC HCFLAGS
, and hc-pkg=$HCPKG $HCFLAGS
.
cabal new-exec -w /some/local/ghc -b dep1,dep2,dep3 hc -- Foo.hs
Would be nice, won't it?
I think we can start implementing this by adding support for environment variables and aliases in project setting, and then generalise. Maybe it's easy to do all a once.
Supporting -z
(ignore cabal.project
) flag is :+1:
note (please ignore if I'm stating the obvious) that cabal v2-exec ghc -- ...
is already magic; the string ghc
gets substituted with whatever --with-compiler
is pointing to, which may not even be named ghc
.
In other words, cabal v2-exec bash -- -c "ghc ..."
is semantically differnet from cabal v2-exec ghc -- ...
; iow, it's a very leaky abstraction. In general I consider v2-exec
an anti-feature and I try to avoid it whenever I can. So I'd rather suggest to not go down the path of v2-exec
but instead try to work out a workflow based on ghc package environment files and v2-install --lib
which is far more flexible than having to snoehorn stuff via v2-exec
, and also avoids to re-run the solver for every single invocation (also note that v2-exec
is the wrong place anyway, as it does not build any goals, hence it never would be able to install any deps or run the solver).
PS: as for -z
, this reminds me we need to add support for -z
to v2-install
and v2-update
-- but I don't rememeber if I ever filed a ticket for that
@RyanGlScott
Similarly to how you can run
cabal new-repl -b dep1,...,depn
outside of a.cabal
project today, I'd like to request thatcabal new-exec -b dep1,...,depn ghc -- Foo.hs
work outside of.cabal
projects. This would operate conceptually in a similar manner tostack exec ghc
.
What's wrong with specifying the dependencies inside Foo.hs
and using cabal scripts?
{- cabal:
build-depends: base, lens, lens-aeson, aeson, text
-}
{-# LANGUAGE QuasiQuotes, OverloadedStrings #-}
import Data.Aeson.Lens
import Control.Lens
import Data.Aeson
import qualified Data.Text as T
import Data.Aeson.QQ.Simple
import Data.Text.Lens
--- ... and so on
You can run these anywhere outside a cabal project as cabal Toy.hs
(or cabal new-run --with-ghc ghc-head Toy.hs
).
cabal new-run
isn't adequate for my purposes for a couple of reasons:
- ~~
cabal new-run
uses the bytecode interpreter, whereas I need compiled code.~~ EDIT: Never mind, this is incorrect. -
cabal new-run
doesn't support scripts with multiple files.
-
cabal new-run
doesn't produce an executable file that I can run.
Possibly stupid question: why not indeed run ghc
inside cabal v2-exec ghc
but put an appropriately-wrapped GHC at the front of PATH
so that ghc
(or another user-provided command that invokes it) refers to the right GHC?
@michaelpj because e.g. of ghcjs.
In fact I agree with @hvr, and tried to convince Ryan to use environment files based approach. Yet, until https://github.com/haskell/cabal/issues/5559 is fixed, that's a non-argument.
@phadej can you expand on that?
Ok. To fix my own comment: the expanding of environment variables is not a problem.
You can create as script.sh
which reads environment and run
cabal new-exec -w /some/local/ghc -b dep1,dep2,dep3 sh script.sh
Then AFAICS the problem is to add -b / --build-depends
to cabal v2-exec
.
related with the mega issue about a possible replacement of cabal install --lib
and not project centric workflows: #6481
@RyanGlScott cabal script has been improved a lot in master, maybe they could help better in your workflow nowadays
What in particular has changed about scripts in master
?
What in particular has changed about scripts in
master
?
- You can now use cabal.project fields like
compiler: ghc-x.y.z
in the script metadata: https://github.com/haskell/cabal/pull/7997 - The verbosity has been reduced: https://github.com/haskell/cabal/pull/7990
-
cabal list-bin
give you the path to the executable generated by the script: https://github.com/haskell/cabal/pull/7925 - the script is now cached and executions after the first build executes it immediately
- you can run
cabal build script.hs
andcabal repl script.hs
and the metadata (deps for example) will be honoured: https://github.com/haskell/cabal/pull/7851
All thanks to the amazing work of @bacchanalia
and there are workarounds (create a package, which you dont want i guess :-P ) over the multiple file thing see f.e.: https://github.com/haskell/haskell-language-server/blob/1.6.1.0-hackage/install.hs
Ah, I was looking at the wrong place for cabal-install
's changelog (i.e., changelog.d
). That's indeed quite a lot of improvements, and it would likely address limitation (3) from https://github.com/haskell/cabal/issues/5895#issuecomment-464742273. I'm not sure if limitation (2) from https://github.com/haskell/cabal/issues/5895#issuecomment-464739179 it still relevant—I'd have to build a more recent cabal-install
to tell for sure.
Ultimately, the thing I care about the most (call it limitation (0), if you will) is having a mechanism for quickly compiling one-off files with a small number of Hackage dependencies that is more lightweight than setting up an entire .cabal
project. At the moment, the closest thing to that mechanism appears to be cabal
scripts, which is certainly an improvement over the status quo when I filed this issue.
I do think things could be even more lightweight, however. 99% of the time, all I really want to do is run something like cabal exec ghc -b lens Main.hs && ./Main
. It sounds like I could accomplish the same thing by making Main.hs
a cabal
script, but that requires that I:
- Remember the funny
#!/bin/env cabal
header that is only used incabal
scripts, - Remember the funny
{- cabal: ... -}
comment syntax that, again, is only used incabal
scripts, and - Having done all that, figure out how to actually run the compiled script. IIUC, with a
cabal
script you'd have to first usecabal list-bin
to look up the executable before I can run it directly. Alternatively, I could usecabal run
, but in my experience this usually incurs some extra startup time each time you run the executable. Perhaps this has changed onmaster
—I haven't checked.
Certainly not insurmountable obstacles by any means, but there are some extra steps and cognitive overhead there. For this reason, I usually reach for cabal repl -b lens
followed by :load Main.hs
for most one-off experiments these days, as clunky as it may be. If cabal exec
(or a comparable command) has a -b
flag, I'd switch in a heartbeat.
In any case, that's my two cents on the issue. If the consensus is that what I'm asking for is an anti-pattern and that I should use cabal
scripts instead, I'd be happy to close this issue. Just let me know what the intended direction of travel is.
I usually reach for cabal repl -b lens followed by :load Main.hs for most one-off experiments these days, as clunky as it may be. If cabal exec (or a comparable command) has a -b flag, I'd switch in a heartbeat.
to be fair to have an uniform interface is a good thing in its own
I could use cabal run, but in my experience this usually incurs some extra startup time each time you run the executable. Perhaps this has changed on master—I haven't checked.
just checked and it continues being 10x slower so find the executable would be needed to speed up the thing:
$(cabal list-bin script.hs) --script-arg
Remember the funny #!/bin/env cabal header that is only used in cabal scripts, Remember the funny {- cabal: ... -} comment syntax that, again, is only used in cabal scripts, and
The first one is optional only needed for the ./script.hs
direct call so you can skip it if you are not gonna use it
In the second one you exchange add a line in the file for save the -b dep
in each call. If you use two or more dependencies it could be more attractive. And if you need more flags for whatever reason it would be even more.
In any case, that's my two cents on the issue. If the consensus is that what I'm asking for is an anti-pattern and that I should use cabal scripts instead
I somewhat agree with some of the hvr and other maintainers arguments on the hackiness of cabal exec
so not sure if investing in would worth.
For your use case, focused in use ghc directly, i would try the cabal install --lib lens --package-env=./ && ghc(i) file.hs
.
I linked #6481 for that reason. Hopefully the new cabal env
command would let us doing a simpler cabal env lens && ghc file.hs
in a safer way, not using global ghc environment files.
For your use case, focused in use ghc directly, i would try the
cabal install --lib lens --package-env=./ && ghc(i) file.hs
.
Admittedly, I've never been able to figure out how cabal install --lib
is supposed to work, due in no small part to running into #5559 any time I try to use it. If I'm reading #6481 correctly, should I think of cabal install --lib
's current behavior as broken and cabal env
being the thing that cabal install --lib
will eventually become over time?
well afaik the --package-env=./
make the command safer as it creates the ghc env file in cwd, so ghc only will honour it in the same cwd
In front of any problem you can remove such file manually and regenerate it.
Not ideal, sure, and the new cabal env
should make the ux better