Skip to content

Instantly share code, notes, and snippets.

@merijn
Last active May 27, 2016 03:31
Show Gist options
  • Save merijn/c01405e6c5a78a1c4ccb to your computer and use it in GitHub Desktop.
Save merijn/c01405e6c5a78a1c4ccb to your computer and use it in GitHub Desktop.
Authors: Merijn Verstraaten
Date: 2014/11/22

So You Want to Be a Super Cool GHC Hacker?

So you have a pet peeve/bug/feature request that you'd like to see added to GHC. You made sure there was a Trac ticket for it, but despite your patient waiting no one is solving your problem. Those selfish GHC hackers!

What's an open source programmer like you supposed to do? Roll up your sleeves and get to work, of course! Now, I can already hear you say "I don't know how to get started hacking on GHC!". No worries, that's what this post is for!

The Prerequisites

So what do we need to start hacking GHC? If, like me, you're on OSX there's not a lot to do. You need the following:

  1. A working GHC and haskell build tools
  2. docbook-xsl, docbook-xml-4.2 & docbook-xml-4.5

I recommend just installing the Haskell platform to get #1 out of the way, this ensures you have alex, happy and whatever else I may be forgetting. You need #2 to build the docs (you were planning to document you work, right?). You can grab them from your favourite package manager. That's it for OSX users, you can skip to the next section.

Linux Sidebar

I generally don't use linux, so until someone who does fills me in, this section only includes the bits I just happen to know. At the very least you will need to have all the following available:

  1. Working GHC and build tools
  2. libgmp
  3. docbook-xsl, docbook-xml-4.2 & docbook-xml-4.5
  4. php5-cli & php5-curl

Getting the Sources

First check out the GHC sources and bootstrap libraries:

git clone --recursive git://git.haskell.org/ghc.git

Since you won't be able to push changes here, you may want to fork the GHC GitHub mirror and add it as default push target:

git remote add merijn git@github.com:merijn/ghc.git

git remote set-url --push origin git@github.com:merijn/ghc.git

git checkout -b merijn/master origin/master

Setting Up Phabricator

Set up a Phabricator account on https://phabricator.haskell.org/. You can browse around and review other people's changes to get a feel for the source and explore the interface. Once you're done playing around it's time to set up arcanist for our GHC checkout.

Clone the following repositories somewhere:

git clone https://github.com/phacility/libphutil.git

git clone https://github.com/phacility/arcanist.git

Add the arcanist/bin directory your PATH and we're ready to move on. Switch to the directory containing your GHC check out and run:

arc install-certificate

This will prompt you to a Phabricator URL, copy a token, and paste it into the arcanist command line prompt. Once this is done arcanist is configured for the GHC Phabricator instance and we can get to the fun part!

Building GHC

First we need to setup all the relevant build directories and run the configure script:

perl boot

./configure --prefix=$HOME/ghc-head

cp mk/build.mk.sample mk/build.mk

The --prefix flag, as usual, specifies the directory where GHC should be installed. To finish up this step, open up mk/build.mk in your favourite editor and uncomment BuildFlavour = quick on line 21.

To test everything works, and because we like wasting CPU cycles let's test if it builds:

make -j

Your shiny new compiler is now inplace/ghc-stage2, or you can run make install to have the compiler installed under your selected --prefix. If you make a few small changes to only the compiler and only want to rebuild the last stage of the compiler, simply use:

cd ghc

make stage=2

With all that out of the way, we can finally get to hacking!

Testing, Review & Revision

After hours of reckless hacking, frustration, grepping the GHC tree, and wrestling with Haskell your patch finally works. Hurray! Time to hit the bar and party!

Well, not quite yet, you should probably add some tests and verify you didn't break anything. You can find tests hiding under testsuite/tests in the tree and in the tests folder of the various libraries. You can use make test or the slightly more convenient validate script to run them. However, if you're lazy and don't want to burden your own CPU, we can offload those to Phabricator, so we'll skip running them for now.

To add your own tests to the test suite, choose a suitable category/directory under testsuite/tests and create a haskell file containing your test. The existing naming convention names the tests after the associated Trac ticket, so T8089 is a test corresponding to Trac ticket 8089. Every folder with tests contains an all.T file, listing the tests in the folder. A minimal entry in all.T looks like:

test('T8089', normal, compile, [''])

This entry corresponds to haskell source file named T8089.hs, which is compiled in the normal configuration. The test succeeds if the compilation succeeds with no errors. The empty list specifies that the test requires no flags during compilation. Besides compile There are two other common categories of tests. These are compile_fail and compile_and_run, the former expecting compilation to fail and the latter expecting the produced binary to run and exit with a 0 exit status.

Additionally each test can have an option T8089.stdin, T8089.stdout, and T8089.stderr file. If these files exist, the output of the test will be compared with the stored output. While we were too lazy to run the entire test suite, we should probably check that at least our new test(s) work correctly and pass! To run all variations of a single test, change to the testsuite/tests directory and run:

make TEST=T8089

If you forgot to add the proper stdin/stdout/stderr output for your test, or, if you were simply to lazy to add these files, the test suite will complain that the test failed due to a mismatch between stored and produced output. Fortunately, if we already checked the test output is correct, we have a convenient way to update the stored output:

make accept TEST=T8089

This will create the appropriate stdin/stdout/stderr files with the tests current output.

Patch done. Tests done. Finally done, right? Wrong! You weren't going to forget updating the documentation to explain your changes, right? That's why I told you to install docbook in the first place. You will find the user's guide under docs/users_guide. The most important files to update are: flags.xml, using.xml and glasgow_exts.xml. These files cover, GHC's command line flag reference, how to use different flags, and GHC specific extensions to Haskell.

Whew! Now it's time to get our new patch reviewed and check we didn't break anything else. For simplicity's sake I'll assume a patch consisting of a single commit for out interaction with Arcanist. First, commit the changes and tests. Don't bother specifying a long commit message, we'll deal with that in Arcanist:

git commit -sm "A short summary of the commit."

Note the use of -s to add a sign-off to the commit. Now that we have our commit ready to go, it's time to put a differential on phabricator so that it can be reviewed. If you are developing on a branch other than master (which you probably should be!), simply run:

arc diff

If you were developing on master and your changes are just a single commit, you can use the following:

arc diff HEAD^

If you run into more complex scenarios, just shoot an email to ghc-devs@ or ask on #ghc.

Arcanist will now turn the last commit on our branch into a differential. First it will prompt to ask whether you want to amend any untracked files to your commit, double check you're not missing anything. Next Arcanist drops you into an editor with the differential template and your commit message:

<Your commit message>

Summary:

Test Plan:

Reviewers:

Subscribers:

GHC Trac Issues:

You should write the long form summary of your commit/changes in the summary field. Set the test plan should be set to validate, add austin after reviewers, and update. Don't worry too much, these things can be updated later. You can leave the subscribers field empty, the GHC Trac Issues field should be set to all relevant Trac issues. For example, to add Trac issue 8089:

GHC Trac Issues: #8089

When you save and exit, Arcanist will lint your code and yell at you if you violate the style rules. If it complains, fix any problems, run git commit --amend to update your commit, and rerun arc diff HEAD^. You have now successfully opened a differential for review on Phabricator. You can go explore it in your browser and ask people in the #ghc channel on FreeNode to review it and comment.

Phabricator will automatically kick off a build and validate run of your patch. You can check whether your patch passes the test suite online via a link on your differential. If the validate run fails you'll get an email and you'll be able to check the tests output from the differential page.

After people have reviewed the patch and commented on the code, you probably want to revise your patch to accommodate the feedback. Simply make whatever changes are necessary, run git commit --amend to update your commit and rerun arc diff HEAD^ to update the differential. Any subscribed people and reviewers will be notified of your changes since the last comment. When, after several iterations, both you and the reviewers are happy with your commit and the test suite passes, you are finally done. One of the GHC committers will at some point (if you prod them enough) grab your patch, land it, and push it out to the GHC master branch. Congratulations, you are now a GHC contributor!.

Further Resources

If you have any more advanced questions about GHC development, want to do more complicated tests, or simply have some questions about some GHC code, don't hesitate to contact other developers:

Additionally, the following wiki pages may contain helpful information to supplement this quick start guide:

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