cygwin上でnodejsとnpmとCoffeeScriptなどをインストールする

(追記: nodejsのバージョンが0.2時代のやり方です。0.4.8でのやり方はnaveを使ったnode.jsインストールと、最近のnpmの使い方 - ラシウラに書きました)

(まとめ)コマンドラインJavaScript環境nodejsと、そのパッケージマネージャnpmをいれ、npmからスクリプト言語CoffeeScriptを入れる手順です。CoffeeScriptというのは、rubyベースでpython風味を付け足したような文法のJavaScript環境で動く言語です。以下すべてWindow7 Home Premium x64上で行っています。

nodejsのインストールの仕方は、Building node.js on cygwin (windows) · nodejs/node-v0.x-archive Wiki · GitHub にあり、結果的にこの手順で可能です。
注意点は以下:

  • リポジトリのheadはcygwin対応出来ていなかった。最新リリースバージョン(0.2.3)は大丈夫
  • pkg-configパッケージを入れるのを忘れない(openssl等それを使う他パッケージの依存関係では入らない)
  • python.exeでDLLエラーが出る場合は、cygwinを閉じたあと、スタートメニューの検索などからash.exeを開いてそこで"rebaseall"する
  • nodejsからの通信で/etc/resolv.confが必要cygwin上で、/etc/resolv.conf(nameserver 8.8.8.8)を作り、一旦cygwinをログアウトしてからnode.exeを実行する

make installで/usr/localを汚したくないので、以下のような配置にするようにしました

  • ~/.nodejs/bin/node.exe
  • ~/.nodejs/bin/npm
  • ~/.nodejs/share/man/...
  • ~/.node_libraries/...

事前準備

最新版のcygwinで以下のパッケージ(とその依存パッケージ)を入れます

  • gcc-g++
  • make
  • openssl
  • openssl-devel
  • pkg-config
  • zlib-devel
  • python
  • curl

(存在しなければ)/etc/resolv.conf(c:\cygwin\etc\resolv.conf)を作ります(これがないとnpmは動きません)

nameserver 8.8.8.8
nameserver 8.8.4.4

nodejsインストール

curl -O http://nodejs.org/dist/node-v0.2.3.tar.gz
tar zxf node-v0.2.3.tar.gz
cd node-v0.2.3
./configure --prefix=~/.nodejs
make
make install

./configureの結果は、以下の出力になるはずです

$ ./configure --prefix=~/.nodejs
Checking for program g++ or c++          : /usr/bin/g++
Checking for program cpp                 : /usr/bin/cpp
Checking for program ar                  : /usr/bin/ar
Checking for program ranlib              : /usr/bin/ranlib
Checking for g++                         : ok
Checking for program gcc or cc           : /usr/bin/gcc
Checking for program ar                  : /usr/bin/ar
Checking for program ranlib              : /usr/bin/ranlib
Checking for gcc                         : ok
Checking for library dl                  : yes
Checking for openssl                     : yes
Checking for library rt                  : yes
--- libeio ---
Checking for library pthread             : yes
Checking for function pthread_create     : yes
Checking for function pthread_atfork     : yes
Checking for futimes(2)                  : yes
Checking for readahead(2)                : no
Checking for fdatasync(2)                : yes
Checking for pread(2) and pwrite(2)      : yes
Checking for sendfile(2)                 : no
Checking for sync_file_range(2)          : no
--- libev ---
Checking for header sys/inotify.h        : not found
Checking for header sys/epoll.h          : not found
Checking for header port.h               : not found
Checking for header poll.h               : yes
Checking for function poll               : yes
Checking for header sys/event.h          : not found
Checking for header sys/queue.h          : yes
Checking for function kqueue             : not found
Checking for header sys/select.h         : yes
Checking for function select             : yes
Checking for header sys/eventfd.h        : not found
Checking for SYS_clock_gettime           : no
Checking for library rt                  : yes
Checking for function clock_gettime      : yes
Checking for function nanosleep          : yes
Checking for function ceil               : yes
Checking for fdatasync(2) with c++       : yes
'configure' finished successfully (21.674s)

cygwinのpkg-configが入っていなければ、"Checking for openssl"がnoとなるでしょう。
またconfigure実行中に、python.exeで"unable to remap 〜"といったDLLのエラーが出る場合があります。その場合はcygwinを閉じ、rebaseallコマンドをash上から実行すると治ります。

出来上がったnode.exeにPATHを通します。

export PATH=$PATH:~/.nodejs/bin

nodejs.orgのトップにあるexample.jsを実行して確認します。

npmインストール

(npmを入れるためには、nodejsから通信するために/etc/resolv.confが存在する必要があります。)
まず、~/.npmrcを作成します。

root = ~/.node_libraries
binroot = ~/.nodejs/bin
manroot = ~/.nodejs/share/man

rootの~/.node_libraries/は、node.exeがデフォルトでモジュールを読み込むPATHです(0.3では~/.node_modulesも読み込むようになってます)。
それ以外にnpm root置く場合、環境変数NODE_PATHでそこを指定する必要があります。


~/.npmrcをつくったら、以下のコマンドを実行します:

curl http://npmjs.org/install.sh | sh
npm list stable

など実行し、npmコマンドの動作確認します。

CoffeeScriptのインストールとexample実行

npmからCoffeeScriptインストール

npm install coffee-script

coffeeコマンドなどがインストールされます。

以下のコードがnodejsのexample.jsのCoffeeScript版example.coffeeとなります

#!/usr/bin/env coffee
http = require "http"
server = http.createServer (req, res) ->
    res.writeHead 200, {"Content-Type": "text/plain"}
    res.end "Hello World\n"
server.listen 8124, "127.0.0.1"
console.log "Server running at http://127.0.0.1:8124/"

実行は、

coffee example.coffee

jisonインストールと利用

CoffeeScriptで使われてる、パーザーjisonを入れます。

npm install jison

jisonはコマンドラインから文法ファイルをJSに変換するパーザージェネレータですが、JSON形式の文法データを渡してパーザーとなるモジュールとしても使えるようにもなってます。

簡単なLISPインタプリタを、jisonをつかってCoffeeScript(0.9.4)で書いたものが以下です:

#!/usr/bin/env coffee
# for coffee 0.9.4
jison = require "jison"

grammar =
  "lex":
    "rules": [
      ["\\s+",          ""]
      ["\\(",           "return 'LPAREN'"]
      ["\\)",           "return 'RPAREN'"]
      ["\\d+",          "return 'NUMBER'"]
      ["[^\\s\\(\\)]+", "return 'SYMBOL'"]
      ["$",             "return 'EOF'"]
    ]
  "bnf":
    "program": [
      ["exprs EOF", "return $1"]
    ]
    "expr": [
      ["NUMBER", "$$ = parseInt(yytext)"]
      ["SYMBOL", "$$ = yytext"]
      ["LPAREN exprs RPAREN", "$$ = $2"]
    ]
    "exprs": [
      ["expr", "$$ = [$1]"],
      ["expr exprs", "$$ = [$1].concat($2)"]
    ]

lparser = new jison.Parser grammar
lget = (env, name) ->
  return env[name] if name of env
  return lget(env.__parent__, name) if "__parent__" of env
  undefined

leval = (env, expr) ->
  switch typeof expr
    when "number" then expr
    when "string" then lget env, expr
    when "object"
      switch expr[0]
        when "define"
          name = expr[1]
          value = leval env, expr[2]
          env[name] = value
        when "quote" then expr[1]
        when "lambda"
          parent = env
          params = expr[1]
          body = expr[2]
          ->
            frame = {}
            for i in [0...params.length]
              frame[params[i]] = arguments[i]
            frame.__parent__ = parent
            leval frame, body
        else
          [func, args...] = leval(env, e) for e in expr
          func args...

run = (env, code) ->
  trees = lparser.parse code
  #console.log trees
  for tree in trees
    leval env, tree

top =
  "+": (params...) -> params.reduce ((a, b) -> a + b), 0
  "*": (params...) -> params.reduce ((a, b) -> a * b), 1
  "write": console.log

# examples
run top, "(write (+ 10 20))"
run top, "(define sq (lambda (a) (* a a)))"
run top, "(write (sq 5))"

(ubuntu maverickにもnodejsやcoffeescriptパッケージがあるのですが、バージョンが古いのでこのコードは解釈できないでしょう)