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

Problem interfacing yesod devel with the new hsenv #480

Closed
dudebout opened this issue Jan 15, 2013 · 21 comments
Closed

Problem interfacing yesod devel with the new hsenv #480

dudebout opened this issue Jan 15, 2013 · 21 comments

Comments

@dudebout
Copy link
Contributor

hsenv from https://github.com/Paczesiowa/hsenv has always been working flawlessly with yesod devel. However, @Paczesiowa stopped development and @tmhedberg took over. One major change was to work with Cabal 1.16. @tmhedberg recently released the current version of hsenv (0.3) to Hackage which will make it even easier to use with yesod.

I suspect however that somewhere between yesod devel and hsenv there is a slight problem. Installing from hackage hsenv and then a yesod scaffold inside a new hsenv I get the following strang behavior:

  • cabal install works
  • yesod devel starts the server correctly and serves the app properly
  • as soon as a file changes (even a simple extra new line) I get an error during rebuild
Yesod devel server. Press ENTER to quit
Configuring Test-0.0.0...
Rebuilding application... (using Cabal library)
Starting development server...
Starting devel application
Devel application launched: http://localhost:3000
Stopping development server...
Exit code: ExitSuccess
Rebuilding application... (using GHC API)
exception building package: <command line>: cannot satisfy -package-id aeson-0.6.1.0-d3cce98c352f191afb3e1dd2e9d05df5
    (use -v for more information)
Build failure, pausing...

I find puzzling that it is doing twice Rebuilding application... (using Cabal library) but only failing the second time. I tried to do yesod devel -v but would not get more information. I do not even know what command fails.

@dudebout
Copy link
Contributor Author

An additional note:

  • If I change the Test.cabal file, the app is reconfigured and everything works.
  • If I change Handler/Home.hs or Applications.hs for example, then yesod devel crashes.

It seems that a step is taken or not taken when the configuration does not happen:

Yesod devel server. Press ENTER to quit
Configuring Test-0.0.0...
Rebuilding application... (using Cabal library)
Starting development server...
Starting devel application
Devel application launched: http://localhost:3000

**changing Test.cabal**

Stopping development server...
Exit code: ExitSuccess
Configuring Nico-0.0.0...
Rebuilding application... (using Cabal library)
Starting development server...
Starting devel application
Devel application launched: http://localhost:3000

**changing Handler/Home.hs**

Stopping development server...
Exit code: ExitSuccess
Rebuilding application... (using GHC API)
exception building package: <command line>: cannot satisfy -package-id aeson-0.6.1.0-d3cce98c352f191afb3e1dd2e9d05df5
    (use -v for more information)
Build failure, pausing...

@dudebout dudebout reopened this Jan 15, 2013
@dudebout
Copy link
Contributor Author

Silly me, there is a difference between the two rebuildings. The rebuild failing is from rebuildGhc while rebuildCabal seems to work fine.

@tmhedberg
Copy link

Here's a little more detail on hsenv and the recent changes made to it.

The gist of how it works is probably not too different from the other sandboxing mechanisms that are out there. It creates an alternative storage location for Cabal packages and then instructs the various tools that depend on those packages (e.g. GHC, GHCi, ghc-pkg, cabal-install, etc.) where to find them.

It used to accomplish this by setting the GHC_PACKAGE_PATH environment variable, which GHC and related tools would pick up on. Unfortunately, for reasons which I am not fully aware of, this environment variable was deprecated and in fact, recent cabal-install will simply refuse to operate if it is set.

The new approach is a bit more involved. We now wrap the common Haskell tools on the user's PATH with shell scripts that determine the correct combination of options to pass to the underlying tool in order for it to look for packages in the sandbox location, then exec that tool with those options. In most cases, this ends up being something like --no-user-package-db --package-db=/some/path/.hsenv_foo/ghc_pkg_db, but there are subtle variations in this pattern depending on which tool is being invoked and which version (prior to GHC 7.6, the --*-package-db options were instead called --*-package-conf).

So the crux of the matter is: how can we best inform yesod devel of hsenv's alternative package database so that when it invokes the GHC API to rebuild a Yesod project, GHC looks for the dependencies in the correct location?

@dudebout
Copy link
Contributor Author

Actually, I have made one more test and it is not related to Cabal 1.16. I have the same problem with Cabal 1.14.

So the problem shows up with ghc 7.4 and Cabal 1.14 or 1.16 equally.

@tmhedberg
Copy link

That's not surprising. hsenv is now using the wrapper scripts instead of the environment variable regardless of which versions of GHC and Cabal you're using. So the previous point stands: we need a way to pass the necessary options through yesod devel to the GHC API so it will use the correct (sandboxed) package database. The older version of hsenv likely worked with Yesod because the Yesod process inherited the environment variable from the shell it was launched from, and GHC configured itself accordingly, without Yesod having to do anything specific.

@dudebout
Copy link
Contributor Author

Does cabal still use environment variables or is it also using a wrapper script?

If it is using a wrapper script, this means that Distribution uses the wrappers properly and we should try to reproduce what it is doing in the function buildPackage from GhcBuild.hs.

@tmhedberg
Copy link

Does cabal still use environment variables or is it also using a wrapper script?

The cabal command has used a wrapper from the start. It was the only wrapped command until the recent updates, which just extended that approach to various other Haskell development-related tools.

If it is using a wrapper script, this means that Distribution uses the wrappers properly and we should try to reproduce what it is doing in the function buildPackage from GhcBuild.hs.

I don't quite understand what you mean by this. Neither the Distribution.* modules (the Cabal library) nor the cabal command-line tool (a.k.a. cabal-install) know anything about hsenv or its wrapper scripts. The wrappers exist solely to pass some additional arguments to cabal-install and other tools without the user having to explicitly type them out on each invocation.

By the way, from a cursory glance around the source code, I found that yesod devel can take a --disable-api option, which prevents it from using the GHC API for rebuilds in favor of building via Cabal. I just scaffolded a simple Yesod project and tried it, and it seems to work OK with hsenv. It is a bit slower than using GHC directly though.

@dudebout
Copy link
Contributor Author

I meant that the cabal part is handled without a problem by yesod devel and only the ghc part seems to be a problem

Whatever is done in rebuildCabal (which seems to come mostly from Distribution) is working. So there might be some ideas on how to translate it to rebuildGhc.

I do not have a deep understanding of how everything works at a deeper level though.

Thank you for your comments and the workaround.

@gregwebs
Copy link
Member

@dudebout I think --disable-api forces rebuildCabal.

@tmhedberg do you know how we can use the GHC API in a way that is compatible with hsenv?
https://github.com/yesodweb/yesod/blob/master/yesod/GhcBuild.hs#L70

@dudebout
Copy link
Contributor Author

@gregwebs I confirm that this is what happens.

@dudebout
Copy link
Contributor Author

The line throwing the exception in GhcBuild.hs seems to be GHC.setSessionDynFlags dflags3.
At that point the content of dflags3 is:

[("Project name","The Glorious Glasgow Haskell Compilation System"),("GCC extra via C opts"," -fwrapv"),("C 
compiler command","/usr/bin/gcc"),("C compiler flags"," -fno-stack-protector  -Wl,--hash-size=31 -Wl,--reduce-memory-
overheads"),("ar command","/usr/bin/ar"),("ar flags","q"),("ar supports at file","YES"),("touch command","touch"),
("dllwrap command","/bin/false"),("windres command","/bin/false"),("perl command","/usr/bin/perl"),("target 
os","OSLinux"),("target arch","ArchX86_64"),("target word size","8"),("target has GNU nonexec stack","True"),("target 
has subsections via symbols","False"),("Project version","7.4.1"),("Booter version","7.4.1"),("Stage","2"),("Build 
platform","x86_64-unknown-linux"),("Host platform","x86_64-unknown-linux"),("Target platform","x86_64-unknown-
linux"),("Have interpreter","YES"),("Object splitting supported","YES"),("Have native code generator","YES"),("Support 
SMP","YES"),("Unregisterised","NO"),("Tables next to code","YES"),("RTS ways","l debug  thr thr_debug thr_l thr_p  
dyn debug_dyn thr_dyn thr_debug_dyn"),("Leading underscore","NO"),("Debug on","False"),("LibDir","/usr/lib/ghc"),
("Global Package DB","/usr/lib/ghc/package.conf.d"),("Gcc Linker flags","[\"-Wl,--hash-size=31\",\"-Wl,--reduce-
memory-overheads\"]"),("Ld Linker flags","[\"--hash-size=31\",\"--reduce-memory-overheads\"]")]

There is no mention of the User Package DB which might be why it crashes.

(I am not sure that line is actually throwing an exception but I was printing dflags before and after each modification and I cannot putStrLn anything after that line)

@dudebout
Copy link
Contributor Author

This is indeed the problem. I could fix it by adding GHC.extraPkgConfs = [<hard-coded-string>] in the definition of dflags2. I will look into getting that information directly from hsenv.

@dudebout
Copy link
Contributor Author

This information is exported in a global variable by hsenv. It has the following form:

PACKAGE_DB_FOR_GHC= -no-user-package-conf -package-conf=<dir>/.hsenv_<dir>/ghc_pkg_db.

I just put the part after the equal sign in <hard-coded-string>.

@tmhedberg
Copy link

Yesod could look for that environment variable and modify its GHC API calls appropriately. However, I'm not sure it is really appropriate for Yesod to have to "know" about hsenv or how it operates. A better solution would probably be to add a command-line argument to the yesod executable for specifying an alternative package DB location, and then hsenv can wrap yesod to always pass that argument when using an hsenv sandbox.

@luite
Copy link
Member

luite commented Jan 17, 2013

yesod devel uses a ghc wrapper to capture the arguments passed to GHC by cabal. The problem is that this now is another wrapper which adds -package-db args to the real GHC, so these are misssed, right?

It's already possible to add extra cabal arguments with yesod devel (see the help or the source code), you can probably add the required GHC arguments this way.

It's probably easiest if yesod devel just picks up the PACKAGE_DB_FOR_GHC environment variable, and modifies the dynflags accordingly. But it worries me a bit that this adds even more cruft to the already hacky system of build options.

@dudebout
Copy link
Contributor Author

This is corret. hsenv used to set GHC_PACKAGE_PATH and was working fine. Now that we need to use -package-db and the wrapper, it became uglier.

@dudebout
Copy link
Contributor Author

One way to fix the problem would be to run ghc -v to detect what package databases have been configured and use that information.

@dudebout
Copy link
Contributor Author

The simplest/cleanest solution might be to do what was done in the following two pull-requests:

GHC_PACKAGE_PATH is still a valid option to tell ghc what we want. We could set it when activating hsenv and unset it only in the cabal wrapper. This way, yesod and hsenv would not have to know about each other.

@tmhedberg
Copy link

Yes, that's probably worth a shot. I am a bit reluctant to go back to using GHC_PACKAGE_PATH given its strongly deprecated status (according to the Cabal developers), but it does seem to be the simplest solution to the problem, and in theory should not require any modification to Yesod.

@dudebout
Copy link
Contributor Author

As @tmhedberg mentionned in tmhedberg/hsenv#9 (comment) it will not be viable to put back GHC_PACKAGE_PATH as any program using the Cabal library (for example through Distribution) without using the cabal wrapper will choke if Cabal >= 1.16. Therefore, the GHC_PACKAGE_PATH is a definite no no for hsenv.

@luite
Copy link
Member

luite commented Jan 23, 2013

yesod devel now uses the correct package database by checking the hsenv environment variables

@luite luite closed this as completed Jan 23, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants