Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"cabal new-exec ghc" should work outside of .cabal projects #5895

Open
RyanGlScott opened this issue Feb 18, 2019 · 17 comments
Open

"cabal new-exec ghc" should work outside of .cabal projects #5895

RyanGlScott opened this issue Feb 18, 2019 · 17 comments

Comments

@RyanGlScott
Copy link
Member

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

@RyanGlScott
Copy link
Member Author

See #5544 (comment) for a similar feature request for cabal new-repl -b dep1,...,depn Foo.hs.

@phadej
Copy link
Collaborator

phadej commented Feb 18, 2019

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 to ghc or ghcjs 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 👍

@hvr
Copy link
Member

hvr commented Feb 18, 2019

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

@harpocrates
Copy link
Collaborator

@RyanGlScott

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.

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).

@RyanGlScott
Copy link
Member Author

RyanGlScott commented Feb 18, 2019

cabal new-run isn't adequate for my purposes for a couple of reasons:

  1. cabal new-run uses the bytecode interpreter, whereas I need compiled code. EDIT: Never mind, this is incorrect.
  2. cabal new-run doesn't support scripts with multiple files.

@RyanGlScott
Copy link
Member Author

  1. cabal new-run doesn't produce an executable file that I can run.

@michaelpj
Copy link
Collaborator

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?

@phadej
Copy link
Collaborator

phadej commented Feb 19, 2019

@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 #5559 is fixed, that's a non-argument.

@michaelpj
Copy link
Collaborator

@phadej can you expand on that?

@phadej
Copy link
Collaborator

phadej commented Mar 18, 2020

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.

@jneira
Copy link
Member

jneira commented Mar 25, 2022

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

@RyanGlScott
Copy link
Member Author

What in particular has changed about scripts in master?

@jneira
Copy link
Member

jneira commented Mar 25, 2022

What in particular has changed about scripts in master?

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

@RyanGlScott
Copy link
Member Author

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 #5895 (comment). I'm not sure if limitation (2) from #5895 (comment) 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 in cabal scripts,
  • Remember the funny {- cabal: ... -} comment syntax that, again, is only used in cabal 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 use cabal list-bin to look up the executable before I can run it directly. Alternatively, 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.

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.

@jneira
Copy link
Member

jneira commented Mar 26, 2022

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.

@RyanGlScott
Copy link
Member Author

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?

@jneira
Copy link
Member

jneira commented Mar 26, 2022

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants