Older blog entries for rkrishnan (starting at number 260)

Installing Plan9 on Qemu (Oct/2013 Edition)

Posted on October 25, 2013 by rkrishnan

I have had several attempts at learning plan9, none succeeded. About 2 months ago, I tried it on my work MacBook Air with VMWare Fusion but didn’t get it going. I decided to try again, this time on my GNU/Linux box. Installing Plan9 is just one small step. Real fun starts once one starts to use it. I have just started and am already learning a lot, fondly bringing back the memories of the times when I was installing Slackware on my 486/DX66 with 4MB of RAM in 1996.

Which Plan9?

There are a few versions of Plan9.

  • the original from Bell Labs
  • 9front, a fork from the Bell Labs version.
  • 9atom (supports a lot of hardware)
  • 9legacy (Bell labs + patch set)
  • NxM (designed for multicore)

I got into the #plan9 irc channel and mischief (of NoiseBridge, SF) was kind enough to offer some suggestions. He suggested me to install 9front. So, I went off and downloaded the ISO image.

Host machine setup

I installed plan9 as a guest on a host Debian GNU/Linux system. All I had to install was Qemu.

Booting the ISO

First you need to create a qcow image (virtual hard disk) for qemu to install plan9 into.

  $ qemu-img create -f qcow2 9front.qcow2.img 20G

Now, boot the iso image:

  $ qemu -hda 9front.qcow2.img -cdrom ~/iso/9front.iso -boot d -vga std -m 768

Just follow the instructions in the 9front install wiki page. You start the installation by doing inst/start. Once installation is done, stop the qemu reboot and start with the following switches.

  $ qemu -hda 9front.qcow2.img -boot c -vga std -m 768

Also I configured my screen with 1920x1080x16 which works just fine. I also used ps2intellimouse as my mouse, that gives me nice scrolling.

To take mouse control off Qemu, just press CTRL+ALT.

Mouse

To make good use of the Plan9 graphical console (rio is the graphical shell of plan9), one need a 3-button mouse. acme need a real 3 botton mouse for some of the “chording” operations. One could simulate button-2 (the middle button) with SHIFT+right click. But it is not very pleasant. So, I got a Microsoft Notebook Optical Mouse (from ebay.in for Rs.1000) which has a side button that acts as the third button.

Unix to Plan9

Moving to Plan9 as a regular OS can be daunting (at least for me that was/is the case, but I am slowly making my way in). There is a nice Unix to Plan9 command transition page. Just keep it handy. Plan9 takes Unix philosophy to the extreme and that shows in the commands.

The terminal does not have a separate pager like more or less, infact there is an automatic pager and the command output blocks until one scroll the terminal, though this behaviour of the terminal can be changed using the menu. There is no commandline history. The shell is rc and is very nicely integrated with plan9 in all respects.

Unlike most Unix/GNU programs, plan9 programs need very less customizations. In many ways, GNU programs are antithesis of the Unix philosophy (of doing one thing well). I realized it only after I read and used plan9 a bit.

TODO

  • get an irc client working inside 9front.
  • get email client working with upas.
  • 9fs works like a charm. Play more with it.
  • how to compile C programs?
  • APE layer
  • plumber
  • read all the papers on the bell labs website.
  • ACME, sam, structured regexps, rc.
  • … many more.

Community and Support

There is a small but very passionate community around plan9. 9fans list and the #cat-v irc channel on freenode are great places to hang out with other plan9 enthusiasts.

Compiling programs

I tried to compile a few programs. I could rebuild the plan9 kernel and bootloader just fine. Mercurial seem to be the defacto version control system used by plan9 folks.

I tried to compile the Go compiler but that didn’t succeed. I needed a bunch of patches and even after applying those, it didn’t compile and finally I lost interest. A lot of plan9 folks use the paste service called sprunge for sharing error messages and patches. One could send error messages or recieve patches using the hget/hpost commands. For example, to post a file containing an error message into sprunge, this works:

  term% hpost -u http://sprunge.us -p http://sprunge.us sprunge@errors.txt # hit enter
http://sprunge.us/EUJF

The URL returned by hpost can be shared on the IRC.

Summary

Installing, using and reading the motivations behind Plan9 makes one understand how broken our day-today computing infrastructure is. Plan9 was a nice attempt at fixing Unix and bringing computing to modern ages. In plan9, everything is a file. Even environment is a file. Each process has its own private namespace. This means that one can get rid of the ugly hack called sudo from the system. Venti, the network file storage system, is a content addressible system, which works similar to git.

How ever the strenghts of Plan9 also turned out to be its weakness. The world had already moved well into Unix and making something too different from Unix, is not for someone without enough marketing muscle. Had ANSI Posix Environment (APE) been done and had there been a linux emulation layer, things would have looked quite different. Also Plan9 doesn’t have a C++ compiler. Almost every web browser out there is written in C++ and the lack of C++ compiler means that one cannot use modern web from Plan9.

I am extremely sorry to see plan9 die a silent death. Or dare I say, it is already dead? There are handful of people using it at the moment. But hopefully, Plan9 from Userspace will live on.

Syndicated 2013-10-25 00:00:00 from Ramakrishnan Muthukrishnan

Understanding the GNU/Linux graphics

Sometime ago, after reading some LWN articles (highly recomment an LWN subscription if you are interested in Linux kernel). But I found the going tough. There are lots of scattered information. Even though the software is all Free, it was impossible to comprehend why certain things were done the way it was done. It not only required reading articles (paying close attention to the date on which it was written), it also required digging into the past on how things looked before and how it changed. Most of the time, a long list of APIs are given which can only be comprehended by those working on it for a long time. It was very frustrating. I even wondered how anyone new can contribute to such projects after a few years when the current crop of experts have all lost interest in these projects or have passed away.

If you find yourself also in the same position as me, here are some pointers to some gems I found in my journey that does give a big picture of the GNU/Linux graphics/display sub-system. No, I am not competent enough to explain it myself yet, I would rather leave that to masters who have actually worked on it.

To get an overview of the various terminologies involved (DRM, DRI2, KMS, EGL, X, XRender, Wayland, pixman, cairo and other alphabet soup) start reading this overview article ”The Linux Graphics Stack”. Another great overview is this little PDF file which has short explanations of all the key pieces of the graphics stack from the hardware bits to the application. Once you read it, head straight to Wayland Architecture page which explains how X draws the screen and how Wayland is simplifying the picture. Pay particular attention to the journey of an event and its effect on the screen.

Now you are reading to watch this great LCA 2013 video on X and Wayland by X/Wayland hacker, Daniel Stone and look at the corresponding slides.

Another great video is the Episode 6 of “The luminosity of Free Software”, a Google Hangout series by KDE uberhacker Aaron Seigo. Another great article written in 2005 about the state of GNU/Linux graphics by Job Smirl.

And then we have the great LWN, which is an essential reference to every linux kernel programmer. There is a bunch of links to the relevant LWN articles and other discussions and slides on thie Linaro Memory Management page.

Graphics

Again I am a journeyman into Graphics, trying to make sense of various terminologies. There are two pages, that I found helpful.

Hopefully, these links will give a good “big picture” view of the low level parts of rendering/video/graphics inside a modern GNU/Linux desktop. Also remember to watch the date on which this post was written (because The Internet does not forget anything and you, the reader, may be reading this page many months/years after the day this post was written). The display side of things being the most user visible and sensitive thing, is ever changing. The picture may look entirely different after a few years.

Syndicated 2013-03-08 07:08:00 from Ramakrishnan Muthukrishnan

My recent experiences with online courses

Last year, when the online AI Class was announced by Sebastian Thrun and Peter Norvig, I was thrilled and immediately signed up. Soon two other courses were offered. At work, I do low level software and have not formally studied AI or Databases or Machine Learning, not did I really see a need, in immediate future, to apply them in my job. Neverthless, I was thrilled at the possibility to hear and work with Stanford professors through these courses and enrolled for the AI course.

The AI class started and I think I could keep up my motivation level for the first 3 or 4 units. There were others distractions like family and work. I had to do a bit to extra work to learn some background mathematics and also read up the text to keep up with the lectures. Somehow, at that point of time, it all couldn’t fit together in my scheme of things, so I decided to discontinue. When I think back, I think I could have completed the course with a bit of extra effort, which I was not really putting at that point of time, instead I came up with some excuses! One of my cynical friends had predicted that I and some others at work who enrolled with me would all discontinue the course and I was sad that he was right.

Then the creation of Coursera and Udacity were announced. When I saw the announcement for the Design and analysis of Algorithms - 1 course from Stanford, I was extremely thrilled. I had always wanted to learn about analysis of algorithms but have never taken a formal course. I enrolled for the course and started working on the lectures. Tim Roughgarden, who was the lecturer for the course was going at a bit fast rate than what I could keep up. But somehow I caught up with lectures by working on them late nights and early mornings. I took notes as I went along. Taking notes meant, I had to watch the same lecture two or three times in some cases. It quickly blew up the time required to complete one week worth of lectures and sometime spilled over to the next week. But for me, it was liking playing a game. The problem sets and programming assignments were staggered by a week and so I could submit them on time. I was looking forward to the lectures and what new stuff Tim is going to throw at us, students. I did not find much time to participate in the forums. The programming assignments were mostly easy and was something I was really looking forward to. I used Racket for my programs and turned out that some others taking the course were also using Racket. It was a joy to program in Racket through out the course. During the last week of the course, I was with my parents and didn’t have a working Internet connection. After struggling with the phone company and wasting a lot of time on it, I decided to download the vides from elsewhere and work offline. In the end, I used my phone to connect to the Internet using GPRS and use my laptop via tethering to submit answer to the problem set and programming assignments. Overall, I think I did the tests very well.

Here are somethings I liked/disliked about the course:

  • Teacher is the most important element in a class. If teacher is uninteresting, everything else is. No amount of technology can save the situation. Tim is a great teacher. He talks a bit fast but after a while I started loving his style of talking and teaching. Some other classes (don’t want to point fingers at any specific course) didn’t have as good a teacher as Tim.
  • Free style writing on White/Black board instead of powerpoint was one of the highlights of the course. I think it was crucial for the success of the course. Many other courses which I signed up at Coursera were using powerpoints and the teachers (some of the greatest names in CS) were reading out from the powerpoint slides. I couldn’t sustain interest in such courses, how much ever great those teachers are. The way Tim taught the class is a role model and brought back memories of some of the best classes I had taken in real classroom years ago when I was a fulltime student.
  • Timing and difficulty level of the exercises within the lecture is another extremely important element.
  • A good teacher is far far better than self-learning from a book. I learnt tons of new things in these 5 weeks than I would have ever learnt in 5 weeks of reading.
  • The importance of taking notes cannot be overstated. This was the single best decision I ever took. I carried the notebooks around along with my laptop and used it whenever I got free time (sometime, even at work, when I am waiting for compilation to finish or in the evenings). The notes were handy while doing problem sets and programming assignments for a quick revisit to some particular lecture or to look up specific algorithm etc.
  • I didn’t use any text book though Tim recommended a few. I have CLR with me, but surprisingly I didn’t use it much while doing the course.
  • If I have seen one single use of Technology in recent times that positively affects the human beings, then that is this new experiment of online teaching.

Overall, it was a great experience with this course and I would like to thank Tim and Coursera for offering this great course online. I am looking forward to the part 2 of this course.

I also signed up for some of the new courses offered at Udacity. One of them that I am really excited about is the Web design course by Steve Huffman. I really like the style of presentation at Udacity. It is direct. It is short. The listener is tested at the end of (almost) every video. That makes it extremely interesting. Just like playing a video game!

Syndicated 2012-05-01 07:00:00 from Ramakrishnan Muthukrishnan

Helping the FSF

I like new gadgets and have been tempted many times to acquire some of them (like new Android phones and tablets). Usually these gadgets have a short life though (until it becomes obsolete, but still useful) and then newer gadgets come along. One can go on spending money and chasing these gadgets.

These days, I do a bit more analysis. I really think hard if I really need those gadgets and whether I can live without one. More things in one’s life definitely means less available time for doing other things (like spending time with family or reading books) and certainly more pain maintaining them.

Moreover, most of these gadgets do not respect the user’s freedom. When you buy a stock Android phone, chances are that the bootloader of that phone is locked. What this means is that only binaries of the bootloader signed by the manufacturer can be installed. This is true of most (all?) phones available in the market currently. Clever people have deviced ways to keep the bootloader intact and still load alternate OS images (like the excellent CyanogenMod firmware for Android phones).

When one runs these modern gadgets, the Applications (or apps, as they are called these days) are tied to the users account. The Application distributor (like Google or Amazon) can remotely kill any of those application or the phone itself. This kind of application distribution is very different from the way a desktop computer application is distributed.

These kinds of scenarios are coming to the good old personal computing as well. The UEFI comes with similar restrictions (I have to admit that I haven’t read in-depth about UEFI itself).

The good folks at the FSF have been doing a lot of work on Software Freedom and educating the users on these issues (in addition to supporting a number of Free Software projects and defending the rights of the copyright holders as well). They need to pay the staff, host the machines and support various campaigns (print documents, flyers etc). All these needs money. Projects like Android are successful because they are standing on the shoulders of the great work done for the past few years on various Free Software projects (eventhough Android strives hard to avoid GPL for the userspace projects).

Please consider donating some money to the FSF. I have been a proud associate member of the FSF for many years now. Contributing money is the easiest thing one can do to help the cause. A better way would be to work on Free Software projects itself.

If you are thinking of buying a gadget, think carefully if you really need one and if so, choose one which respects your freedom and don’t become a slave of the manufacturer. Also please think of donating 10% of the cost you plan to spend to organisations like the FSF.

Syndicated 2012-01-18 08:00:00 from Ramakrishnan Muthukrishnan

Using cKanren in Racket

cKanren is a wonderful system created by Clair Alvis and the group at IU for relational programming. The definitive work about cKanren is this paper. cKanren builds on another wonderful system called miniKanren created by William Byrd and Prof. Dan Friedman of IU.

Off late, I started reading “The Little Schemer” series and started reading the awesome ”The Reasoned Schemer”, also by the same team that wrote miniKanren. cKanren is written in R6RS scheme and is developed on Chez, evidently. Since I wanted to use Racket and DrRacket environment, I started looking at changes to be done to make it run on Racket. What follows below are the instructions to setup DrRacket for cKanren programming.

  • Download my fork of cKanren

    $ git clone git://github.com/vu3rdd/cKanren.git

  • Switch to the ‘racketification branch’

    $ cd cKanren $ git checkout -b racketification racketification

  • Now, make cKanren module visible in the Racket ‘collections’.

    $ raco link .

  • Now, fireup DrRacket. In the definitions window, use the following as the language.

    #lang cKanren

  • Hack away in cKanren!

Syndicated 2012-01-09 08:00:00 from Ramakrishnan Muthukrishnan

Sicp Challenge Progress

2011 had been an extremely interesting year. I feel very happy to have made good progress on my Programming Language Theory learning. I am also qute happy with my SICP challenge project, which was my only noteworthy side project. I am somewhere in the initial portions of chapter 4 right now and it had been worth every minute I spent on it.

I also started reading many books connected with SICP and Programming Language theory, like TaPL and EoPL. Discovering the work of Dan Friedman was an eye opener and I hope to spend many many hours in the next few years learning from his books. I also read “The Little Schemer” and am well into “The Seasoned Schemer” and on to “The Reasoned Schemer” as soon as I am done. I will happily recommend these great books for anyone starting with Scheme.

Syndicated 2011-12-23 08:00:00 from Ramakrishnan Muthukrishnan

Object Orientation in Scheme

Guy Steele once said that ”A closure is an object that supports exactly one method: apply.

When I read it a few days ago, I could not get much meaning out of it. While reading the SICP chapter 3, section 3.1.1, a bulb lit in my brain and I finally understood (atleast I think so) what he meant. I dug into other literature on the subject and found some more interesting stuff. Read on.

Let us consider the same example discussed by Abelson and Sussman in section 3.1.1, namely the withdrawal of money from a Bank account. One natural way of representing an account is to have an account object which has a way to represent the current balance. The following code reproduces it verbatim from SICP.

(define (make-account balance)
  (define (withdraw amount)
    (if (>= balance amount)
        (begin (set! balance (- balance amount))
               balance)
        "Insufficient funds"))
  (define (deposit amount)
    (set! balance (+ balance amount))
    balance)
  (define (dispatch m)
    (cond ((eq? m 'withdraw) withdraw)
          ((eq? m 'deposit) deposit)
          (else (error "Unknown request -- MAKE-ACCOUNT"
                       m))))
  dispatch)

Let us analyze what is happening in the above code. The make-account procedure creates an “account” object, so to speak, which is initialized with the balance, as follows:

> (define acc (make-account 100))
> ((acc 'withdraw) 50)
50
> ((acc 'withdraw) 60)
"Insufficient funds"
> ((acc 'deposit) 40)
90
> ((acc 'withdraw) 60)
30

A call to make-account with an initial balance value creates a closure with the variable balance together with the internal routines: withdraw, deposit and dispatch. The value returned by make-account is the procedure dispatch. To call a particular method of the object, we pass it as a message to the closure. The returned procedure is then called with the arguments. This is rather the message passing style of object orientation. Now, how does this relate to the comment made by Guy Steele that “closure is nothing but an object with a single method - apply” ?

The above code can be re-written as follows:

(define (make-account balance)
  (define (withdraw amount)
    (if (>= balance amount)
        (begin (set! balance (- balance amount))
               balance)
        "Insufficient funds"))
  (define (deposit amount)
    (set! balance (+ balance amount))
    balance)
  (define (dispatch m . args)
    (case m
      ((withdraw) (apply withdraw args))
      ((deposit) (apply deposit args))
      (else (error "Unknown request -- MAKE-ACCOUNT" m))))
  dispatch)

All we have done is to use the case special form and use apply. The interactions with this new procedure is shown below.

> (define acc (make-account 100))
> (acc 'withdraw 20)
80
> (acc 'deposit 120)
200
> (acc 'deposit 120)
320
> (acc 'withdraw 40)
280

As we can see, this is a neat and easy way to create objects and explains Guy Steele’s statement regarding closures vs objects. In another blog post, we will see how to implement inheritance and other OO concepts. As you can see, Scheme is really cool and is an excellent platform for language experimentations and prototyping of ideas.

Syndicated 2011-01-07 08:00:00 from Ramakrishnan Muthukrishnan

Not dead yet

I have been silent in the blogosphere for the past few months. Life continues to be very busy. The SICP study group is progressing well. I am having a lot of fun interacting with Tom, Pradip, Martin and others. I am close to finishing chapter 2. Almost all the exercises have been completed and tons of things learnt. I wonder how some people find time to do the problems and blog about them.

I also switched to Scheme from Clojure as my language for doing SICP exersizes for many reasons. One important reason is the fact that the purpose of the whole thing is to do SICP and general principles of Computation. I find Scheme to be an excellent vehicle for that purpose. Thinking back, I think it was emacs + slime which was holding me back from trying other alternatives. :-)

And then it happened. I bought ”The Little Schemer” by Dan Friedman and Matthias Felliesen and simply fell in love with it. In my opinion, this little book is a much more important book in computing than the mighty Knuth and K&R. True, they have their place. But this book conveys some of the most important principles in computation in a simple Q&A style. I had a smooth sail through it until I hit the chapter on Y Combinator (aptly titled ”… and again, and again, and again .. “) which I had to read about 4 times and experiment on the repl to finally get it. Reading this book also motivated me to take a serious look at Scheme. I managed to grok some of the fine papers written by Dybvig, Felliesen and the other fine and friendly folks at the PLT. The PLT community and the mailing lists are one of the finest and helpful group of folks I have seen.

I am currently looking at Guile, the FSF’s own Scheme implementation. There are many factors which makes guile interesting. Guile is small, but at the same time good enough to be very useful to write large systems. It has a good C FFI and has a good module system, something I haven’t seen in the other Scheme implementation and is the closest thing to Common Lisp packages, in my opinion. It has a nice VM and a compiler, which is evolving. I hope I can learn a lot more by working with Guile than any other Scheme. Guile is actively being developed by Andy Wingo and others who can also be interacted with at the #guile irc channel, which is great. I use Emacs and geiser to interact with Guile.

Clojure was fun. I will return back to it when I have a need. I almost finished writing a blog engine with it and had a lot of fun writing it. But for now, Scheme definitely serves my needs for learning programming language fundamentals.

At this point, some people in the Clojure community are busy trying to get all the attention they can (and also sell some books, more in the works, so we will see a proliferation of such posts for the next many months) by posting every blog post they find on clojure to HN, Reddit and also repost the HN url back to twitter! The result of all these is that, a lot of people think Clojure is the first Lisp in this planet! I mean.. grow up, people! I am sure, they will settle down. Can’t resist posting this XKCD strip. But overall, over exposure of Clojure is good for all the Lisps.

I have a bunch of books waiting to be read or partially read:

  • On Lisp (almost finished it, but planning to read again).
  • The Lambda papers by Steele and Sussman.
  • To Mock a mockingbird.
  • PLAI (Shriram Krishnamurthi)
  • EOPL
  • PAIP
  • The Joy of Clojure.
  • ...
Not sure whether a lifetime is enough to read and understand them all and also make something useful for myself and others to use.

Syndicated 2010-10-19 07:00:00 from Ramakrishnan Muthukrishnan

Manual configuration of swank-clojure with the upstream slime

I now have a very nicely working swank-clojure, completely configurable by hand and no ELPA magic. And this plays very well with the upstream slime as well as swank-clojure, albeit some small changes in the emacs lisp of the swank side..

The problem

Upstream swank-clojure supports only ELPA and those who want to configure swank manually are on their own. I, for one, do not like those “conventions over configurations” stuff, atleast for my programming environment. Heck, that’s why I use emacs in the first place.

In the past, I was using an older version of swank-clojure which fully supported manual configuration. I then switched to a newer version of swank-clojure but with a totally different emacs lisp code to make configuration for easy.

Also, I use the clojure and clojure-contrib from the debian packages, which installs into /usr/share/java. The same directory has all the other java jars as well. But upstream swank-clojure supported somewhat different directory structure. If invoked on a project, it picks up dependencies from a subdirectory called “lib” (configurable). lein puts all the dependencies (including clojure.jar) into that directory. It built up a new classpath from these (assuming that the project is self-contained, including dependencies).

This unfortunately does not work in my case. I almost never use a build tool while fooling around doing random with slime. For example, to use Slime with my SICP exercises where I do not have a build mechanism put in, it becomes difficult. Running tests for a namespace from slime is another reason why having the project namespace in the classpath is a very useful thing. For many simple projects that I do, all I need is clojure and clojure-contrib which is already in my classpath. But this made things difficult as adding the project being worked on into the classpath was messy. Becausee of the above setup, swank-clojure-project was unsable for me..

I also don’t like multiple copies of jars lying around. It is not the question of wasting disk space, which is very cheap anyway. But it is just a matter of taste and cleanliness. Multiple jars on each project directory is a convenience, but it is plain ugly.

Today I decided to clean up the whole mess. The end result is a much cleaner swank/slime.

Solution

Turned out the solution was very simple. When swank is started on a project, instead of changing swank-clojure-classpath, I build up another list using a variable called swank-clojure-extra-classpaths. This is then appended to the swank-clojure-classpath before starting up the JVM.

I also disabled the code which checks the presence of clojure.jar files in some predefined location when swank starts up. This can always be called manually, if one wants to.

Code

For those wanting to follow similar approach, here is my github fork of swank-clojure with instructions on setting it up. The emacs repl (via ielm) was invaluable for debugging.

Syndicated 2010-05-02 07:00:00 from Ramakrishnan Muthukrishnan

Embracing maven

After several failed attempt to understand maven and going back and forth between lein and maven, I have finally decided to settle on maven. There are several reasons for this. One of the most important one is that Debian has a very well packaged maven and a local repository system. i.e. Debian java packages installed on a machine is available as a local repo. With that, offline builds become quite easy (provided all the dependencies are available as Debian packages). Maven is also well supported by the Java ecosystem. Though XML turns me off as well, maven takes care of generating much of the boilerplate for us.

I will walk through creating a trivial clojure project using maven. I assume that maven is already installed on your machine.

First, run the following command:

$ mvn archetype:create -DgroupId=in.clj.hello -DartifactId=hello

This gives the following output on my machine: [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'archetype'. [INFO] ------------------------------------------------------------------------ [INFO] Building Maven Default Project [INFO] task-segment: [archetype:create] (aggregator-style) [INFO] ------------------------------------------------------------------------ [INFO] Setting property: classpath.resource.loader.class => 'org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader'. [INFO] Setting property: velocimacro.messages.on => 'false'. [INFO] Setting property: resource.loader => 'classpath'. [INFO] Setting property: resource.manager.logwhenfound => 'false'. [INFO] [archetype:create {execution: default-cli}] [WARNING] This goal is deprecated. Please use mvn archetype:generate instead [INFO] Defaulting package to group ID: in.clj.hello [INFO] ---------------------------------------------------------------------------- [INFO] Using following parameters for creating OldArchetype: maven-archetype-quickstart:RELEASE [INFO] ---------------------------------------------------------------------------- [INFO] Parameter: groupId, Value: in.clj.hello [INFO] Parameter: packageName, Value: in.clj.hello [INFO] Parameter: package, Value: in.clj.hello [INFO] Parameter: artifactId, Value: hello [INFO] Parameter: basedir, Value: /tmp/hello-mvn [INFO] Parameter: version, Value: 1.0-SNAPSHOT [INFO] ********************* End of debug info from resources from generated POM *********************** [INFO] OldArchetype created in dir: /tmp/hello-mvn/hello [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1 second [INFO] Finished at: Wed Apr 21 22:13:22 IST 2010 [INFO] Final Memory: 15M/150M [INFO] ------------------------------------------------------------------------

A directory called hello is created. Let us look at the parameters to archetype:create. groupId is a unique way to identify the module. Think of it as the namespace. artifactId is the name of the project. groupId:artifactId:version uniquely identify an ‘artifact’. By default, maven will create a version number 1.0-SNAPSHOT for the project, if it is omitted from commandline.

The directory tree at this point looks like this:

$ tree
.
|-- pom.xml
`-- src
    |-- main
    |   `-- java
    |       `-- in
    |           `-- clj
    |               `-- hello
    |                   `-- App.java
    `-- test
        `-- java
            `-- in
                `-- clj
                    `-- hello
                        `-- AppTest.java
Let us get rid of the java files first. $ rm -rf src/main/java $ rm -rf src/test Create the following directory structure: $ mkdir -p src/main/clojure/in/clj Note that we have created the structure according to our groupId specification. Create a file called hello.clj at the leaf of this directory and put the following contents inside it:
REXML could not parse this XML/HTML: 
<pre>
(ns in.clj.hello)

(defn greet & args (apply str args)) </pre>

Now, open the pom.xml file. Some changes needs to be done here so that maven knows that we are building a clojure project and the dependencies. The following things are done:

  1. The dependency on junit is removed.
  2. A dependency on clojure is added.
  3. A new plugin clojure-maven-plugin is added and configured.
  4. Repositories from where, dependencies are fetched, are added.
At the end of this process, the pom.xml looks like this:
REXML could not parse this XML/HTML: 
<pre>
<span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">project</span> <span class="nxml-namespace-attribute-xmlns">xmlns</span>=<span class="nxml-namespace-attribute-value-delimiter">"</span><span class="nxml-namespace-attribute-value">http://maven.apache.org/POM/4.0.0</span><span class="nxml-namespace-attribute-value-delimiter">"</span> <span class="nxml-namespace-attribute-xmlns">xmlns</span><span class="nxml-namespace-attribute-colon">:</span><span class="nxml-namespace-attribute-prefix">xsi</span>=<span class="nxml-namespace-attribute-value-delimiter">"</span><span class="nxml-namespace-attribute-value">http://www.w3.org/2001/XMLSchema-instance</span><span class="nxml-namespace-attribute-value-delimiter">"</span>
  <span class="nxml-attribute-prefix">xsi</span><span class="nxml-attribute-colon">:</span><span class="nxml-attribute-local-name">schemaLocation</span>=<span class="nxml-attribute-value-delimiter">"</span><span class="nxml-attribute-value">http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd</span><span class="nxml-attribute-value-delimiter">"</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">modelVersion</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">4.0.0</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">modelVersion</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">groupId</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">in.clj.hello</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">groupId</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">artifactId</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">hello</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">artifactId</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">packaging</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">jar</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">packaging</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">version</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">1.0-SNAPSHOT</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">version</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">name</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">hello</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">name</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">url</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">http://maven.apache.org</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">url</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">description</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">project to demonstrate maven</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">description</span><span class="nxml-tag-delimiter">&gt;</span>
<
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">plugins</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">plugin</span><span class="nxml-tag-delimiter">&gt;</span>
    <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">groupId</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">com.theoryinpractise</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">groupId</span><span class="nxml-tag-delimiter">&gt;</span>
    <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">artifactId</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">clojure-maven-plugin</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">artifactId</span><span class="nxml-tag-delimiter">&gt;</span>
    <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">version</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">1.3.2</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">version</span><span class="nxml-tag-delimiter">&gt;</span>
    <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">executions</span><span class="nxml-tag-delimiter">&gt;</span>
      <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">execution</span><span class="nxml-tag-delimiter">&gt;</span>
        <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">id</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">compile-clojure</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">id</span><span class="nxml-tag-delimiter">&gt;</span>
        <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">phase</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">compile</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">phase</span><span class="nxml-tag-delimiter">&gt;</span>
        <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">goals</span><span class="nxml-tag-delimiter">&gt;</span>
          <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">goal</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">compile</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">goal</span><span class="nxml-tag-delimiter">&gt;</span>
        <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">goals</span><span class="nxml-tag-delimiter">&gt;</span>
      <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">execution</span><span class="nxml-tag-delimiter">&gt;</span>
    <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">executions</span><span class="nxml-tag-delimiter">&gt;</span>
    <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">configuration</span><span class="nxml-tag-delimiter">&gt;</span>
      <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">sourceDirectories</span><span class="nxml-tag-delimiter">&gt;</span>
        <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">sourceDirectory</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">src/main/clojure</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">sourceDirectory</span><span class="nxml-tag-delimiter">&gt;</span>
      <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">sourceDirectories</span><span class="nxml-tag-delimiter">&gt;</span>
    <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">configuration</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">plugin</span><span class="nxml-tag-delimiter">&gt;</span>
<span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">plugins</span><span class="nxml-tag-delimiter">&gt;</span>
<<
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">dependency</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">groupId</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">org.clojure</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">groupId</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">artifactId</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">clojure</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">artifactId</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">version</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">1.1.0</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">version</span><span class="nxml-tag-delimiter">&gt;</span>
<span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">dependency</span><span class="nxml-tag-delimiter">&gt;</span>
<<
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">repository</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">id</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">clojure-snapshots</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">id</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">url</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">http://build.clojure.org/snapshots</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">url</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">releases</span><span class="nxml-tag-delimiter">&gt;</span>
    <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">enabled</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">false</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">enabled</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">releases</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">snapshots</span><span class="nxml-tag-delimiter">&gt;</span>
    <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">enabled</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">true</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">enabled</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">snapshots</span><span class="nxml-tag-delimiter">&gt;</span>
<span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">repository</span><span class="nxml-tag-delimiter">&gt;</span>
<span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">repository</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">id</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">clojure-releases</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">id</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">url</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">http://build.clojure.org/releases</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">url</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">releases</span><span class="nxml-tag-delimiter">&gt;</span>
    <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">enabled</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">true</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">enabled</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">releases</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">snapshots</span><span class="nxml-tag-delimiter">&gt;</span>
    <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-element-local-name">enabled</span><span class="nxml-tag-delimiter">&gt;</span><span class="nxml-text">false</span><span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">enabled</span><span class="nxml-tag-delimiter">&gt;</span>
  <span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">snapshots</span><span class="nxml-tag-delimiter">&gt;</span>
<span class="nxml-tag-delimiter">&lt;</span><span class="nxml-tag-slash">/</span><span class="nxml-element-local-name">repository</span><span class="nxml-tag-delimiter">&gt;</span>
<<
REXML could not parse this XML/HTML: 
</pre>
REXML could not parse this XML/HTML: 
</pre>

Now do: $ mvn package This produces the following output on my machine:

[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building hello
[INFO]    task-segment: [package]
[INFO] ------------------------------------------------------------------------
[INFO] [resources:resources {execution: default-resources}]
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /tmp/hello-mvn/hello/src/main/resources
[INFO] [compiler:compile {execution: default-compile}]
[INFO] No sources to compile
[INFO] [clojure:compile {execution: compile-clojure}]
Compiling in.clj.hello to /tmp/hello-mvn/hello/target/classes
[INFO] [resources:testResources {execution: default-testResources}]
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /tmp/hello-mvn/hello/src/test/resources
[INFO] [compiler:testCompile {execution: default-testCompile}]
[INFO] No sources to compile
[INFO] [surefire:test {execution: default-test}]
[INFO] No tests to run.
[INFO] [jar:jar {execution: default-jar}]
[INFO] Building jar: /tmp/hello-mvn/hello/target/hello-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4 seconds
[INFO] Finished at: Wed Apr 21 22:57:11 IST 2010
[INFO] Final Memory: 23M/121M
[INFO] ------------------------------------------------------------------------
A jar file is created under the target directory. Now, we add the jar into our classpath and invoke the clojure repl: $ java -cp /usr/share/java/clojure.jar:target/hello-1.0-SNAPSHOT.jar clojure.main Clojure 1.1.0 user=> (use 'in.clj.hello) nil user=> (greet "Hello World") "Hello World" user=> You can also invoke the repl from maven: $ mvn clojure:repl That wasn’t really too hard. With emerging tools around maven like the Polyglot Maven which supports Clojure and a S-expression syntax for writing the POM, we don’t even have to do as much as we did now. I have put this example in this repository for anyone to play with.

Syndicated 2010-04-21 07:00:00 from Ramakrishnan Muthukrishnan

251 older entries...

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!