nix-shell as #! interpreter for runghc

别等时光非礼了梦想. 提交于 2019-12-22 04:28:26

问题


I'm trying to use nix-shell as a #! wrapper for runghc, as suggested in the manpage. But it cannot find the libraries. Given the following example, cut-down from the manpage

#! /usr/bin/env nix-shell
#! nix-shell -i runghc -p haskellPackages.HTTP

import Network.HTTP

main = return ()

I get the following result:

[~:0]$ ./nixshelltest 

nixshelltest:4:1: error:
    Failed to load interface for ‘Network.HTTP’
    Use -v to see a list of the files searched for.
[~:1]$ 

to my mind, that's exactly what nix-shell -p is to avoid.

Am I doing something wrong, missing the point, or is there a bug? This is both on a nixOS 17.03 host, and also a host running nix 17.09 on top of Ubuntu.

Thanks,


回答1:


The environment that you're using to run the script is missing a step. It's got a GHC and a HTTP package, but the compiler doesn't know about the package.

The way GHC and library packages work in nix might be a little "inside out" from what you're expecting. You actually need to install a compiler that "depends on" all of the libraries you want, rather than simply installing the compiler and the library separately. The reason is that GHC is designed to have library packages added by modifying the file tree where GHC is installed. On a mutable file system with only a single system GHC install you would just modify GHC whenever a library was installed, but nix can't. Nix has to be able to install a frozen GHC that never changes, and potentially many of them.

So what happens instead is that you install a tiny wrapper which depends on the both the underlying "raw" GHC install and all of the libraries that you want to use. The wrapper then acts like an install of GHC that had those libraries registered, without actually needing to duplicate an entire GHC install. When you just install a library package on its own it just sits there inert, without any GHC being able to find it just by it existing.

In fact, the script you've shown here doesn't actually specify that it should have a compiler installed at all; it just asks for the HTTP library. When I tried your script I got command not found: runghc. The runghc is only working on your system because it happened to already be in your path when you ran this (perhaps because you have GHC installed in your profile?), and that GHC wasn't installed with the HTTP package and so can't see it. The nix-shell adding just the library to the environment doesn't help.

What you need to do instead is use this line:

#! nix-shell -i runghc -p "ghc.withPackages (ps: [ ps.HTTP ])"

You're not installing either ghc or HTTP directly; instead the ghc.withPackages function computes a nix package that installs a GHC wrapper that knows about the HTTP Haskell package. Under the hood this depends on a "raw" GHC with no additional libraries, and also on the HTTP library and will cause those to be installed too.

If you use lots of different Haskell environments (possibly via nix-shell scripts like this that each need a different set of libraries), then you will end up with a unique withPackages wrapper installed on your system for each combination of libraries you ever use. But that's okay because the wrappers themselves are tiny, and nix is able to share and reuse the underlying GHCs and library packages between all of those environments.



来源:https://stackoverflow.com/questions/45022141/nix-shell-as-interpreter-for-runghc

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!