Project aims to provide solution to
- develop entire Ajax application in Haskell
Previous version of project is located at vir.mskhug.ru.
This version of GHCJS can be built stand alone or integrated into GHC. You can install both (if you know you want both do Integrated first).
- A full GHC that also outputs .js files and .jsexe directories when you build.
- A patched Cabal that installs the .js files along with the .hi ones.
- Takes a while to install (mostly just follow the regular GHC build instructions).
- Uses GHC API to make a ghcjs executable.
- Quicker to install (because you don't have actually build 7.4).
- Good for trying out changes in the code generator itself.
- Still requires some messing with GHC source.
- Google Closure Compiler https://developers.google.com/closure/compiler/
- Google Closure Library https://developers.google.com/closure/library/
- Java (to run the Closure Compiler)
- GHC install capable of building GHC 7.4.1
- OS X 10.7 using 32bit GHC 7.4.1 to build 32bit GHC
- Ubuntu 12.04 64bit VM with 3.5GB of system RAM using 64bit GHC 7.4.1 to build 64bit GHC
Getting The Source
git clone https://github.com/ghcjs/ghc cd ghc git checkout ghc-7.4 ./sync-all -r https://github.com/ghc get ./sync-all -r https://github.com/ghc get ./sync-all -r https://github.com/ghc get ./sync-all -r https://github.com/ghc get ./sync-all -r https://github.com/ghcjs --ghcjs get ./sync-all checkout ghc-7.4
(I find the gets from github often fail hence the 4 of them)
Build GHC as per the normal instructions (remember you can use this GHC to build binaries too).
Typical install goes something like this.
cp mk/build.mk.sample mk/build.mk perl boot ./configure --prefix=/home/hamish/ghcjs make make install hash -r
That last step takes a long time. To use this compiler add /home/hamish/ghcjs to your path ahead of any other ghc.
You should be able to switch back to your main compiler at any point by simply not including this in you path.
User cabal packages are installed to something like
Installing cabal-install with GHCJS
You need to make a version of cabal-install that uses the new Cabal package. So that which you run "cabal install" it will copy .js files and .jsexe directories to the install location.
export PATH=/home/hamish/ghcjs/bin:$PATH cd libraries/Cabal/cabal-install cabal install --prefix=/home/hamish/ghcjs hash -r
There is a catch. Because your old cabal install installed the dependencies the .js files for these libraries will not have been installed. So you should unregister then so they will be installed again with the new cabal-install.
You can get a list of all the packages that were installed by running
ghc-pkg list --user
The quickest way to do this delete the directory these are in
rm -rf ~/ghcjs/lib/ghc-126.96.36.19920501
or you can unregister them using ghc-pkg something like this
ghc-pkg unregister HTTP ghc-pkg unregister network ghc-pkg unregister parsec ghc-pkg unregister mtl ghc-pkg unregister transformers ghc-pkg unregister zlib ghc-pkg unregister random ghc-pkg unregister text ghc-pkg unregister time
- GHC 7.4.1 (it may work with earlier versions, but it has not been tested).
- GHC 7.4.1 source configured and used to do a build
If you built the integrated version you will have the source ready to go. If
not, you will need to follow the steps in Building Prelude. The unit tests
will look for the ghc source in
../ghc and the for the closure compiler
~/closure-compiler/compiler.jar and library in
Code builds as standard haskell package
$ cabal install --enable-tests
To build the test Java Script run.
$ cabal test
Open test.html (for minified code) or test_raw.html for unminified code. You may need to open these via HTTP for them to work.
$ ghcjs Test.hs
This command is merely equivalent to the following
$ ghc --make Test.hs
The code is in alpha stage. Feel free to experiment with it as you wish.
Compiler is implemented as GHC backend using GHC API. And been tested with 32bit GHC 7.4.1.
To play with any Haskell code you'll need Haskell standard library. GHC implements standard library as a "base" package. You'll need to compile modules from base package.
Download ghc source distribution for the same version of ghc that you use to build ghcjs.
$ cd ghc-x.xx.x $ cd mk $ cp build.mk.sample build.mk
Set build flower to the quikest: uncomment the line:
BuildFlavour = quickest
$ ./configure $ make
You should try to use BuildPackages.hs script. You can build ghc-prim, integer-simple and base packages in examples directory with the following command
$ cd examples $ ./BuildPackages.hs <path-to-ghc-directory>
You can build packages manually using instructions below.
=== Building ghc-prim
=== Building base
This last magic command line was guessed using
cabal build -v
to see what options are passed to GHC.
We should really use
option to get read of useless object files, but it seems to be a bug in ghc that cause GHC to rely on odir to be the same as hidir wich is mostly the case in "normal" GHC usage.
Differences from old version
vir.mskhug.ru contains the first implementation of the idea. This version is a rewrite that inherit little code from previous version. The differences are the following.
integer-gmp (using goog.math.Integer)
Function level linker
File Input (uses HTTP and is text only)
More closure compiler friendly output
Foreign function interface is not supported. Only minimum of primitive operations is supported.
Tail recursion optimization is on by default.
If you don't want it use
$ ghcjs --calling-convention=plain
Reading The Code
Many of the names used have been shortened to a single character to reduce the size of the java script. Here is a key so you can work out what they do.
Some functions include "info" strings that to try to make debugging easier (controlled with the HS_DEBUG flag). Also some of the functions have a list of things to keep alive with the thunk. This is also striped out if you disable support for finalizers and weak pointers (controlled with the HS_WEAKS flag). It is a nice feature of the Closure Compiler that if you pass more parameters than the function needs it will remove them from the call site.
|$f||function (first param is the arity)|
|$R and $r||are short for return|
|$M||evaluates its first param (if not already evaluated) and and passes the result to the function provided|
|$A||evaluates if not already evaluated and returns the result|
|.C||calls the function with the list of arguments and passes the result to the function provided|
|.J||jump t a function|