JVMベースの言語処理系用にシンボリックリンクを張りなおすMakefile

Javaプラットフォームで動作する言語処理系を幾つかUbuntuに入れている。$HOME/langs以下に各処理系のアーカイブを伸張・展開しておき、付属の実行スクリプトへのシンボリックリンクを$HOME/binに作成して使用している。

アーカイブを展開した後のディレクトリ名にバージョン番号が含まれたままになっているので、処理系を更新する度にシンボリックリンクを張りなおす必要がある。バージョン番号を取り除く運用にすれば張りなおさなくて済みそうなものを、なぜかそのままにしている。

手作業で張りなおすのもいい加減面倒になってきたので自動化用のスクリプトを書くことにした。自動化しておけばOSの入れ替えやHDDの交換の際にも使えるはずだ。

どの言語で書こうか考えてみて、シェルスクリプトよりもmakeが向いている気がしたのでMakefileを書くことにした。とりあえずGNU Make前提で、こんな感じ。

LANGSDIR   := ../langs
COMMAND    := groovy irb jython processing scala

# $(call shell-script-list,dir-name)
shell-script-list   = $(shell \
  file $(wildcard $(LANGSDIR)/$1/*) | \
  awk ' \
  /shell script text executable/ { \
      sub(/:$$/, "", $$1); \
      print $$1 \
  }')

GROOVYCMD  := $(call shell-script-list,groovy-2.0.5/bin)
SCALACMD   := $(call shell-script-list,scala-2.9.2/bin)

LN     := ln -s

.PHONY: usage
usage:
	@echo 'create symlinks'
	@echo 'usage: make $(patsubst %,[%],$(COMMAND))'

.PHONY: all
all: $(COMMAND)

irb:
	$(LN) /usr/bin/irb1.8 $@

.PHONY: jython processing
jython:     CMDDIR := jython-2.5.3/bin
processing: CMDDIR := processing-1.5.1
jython processing:
	$(RM) $@
	$(LN) $(LANGSDIR)/$(CMDDIR)/$@ $@

.PHONY: groovy scala
groovy: $(GROOVYCMD)
scala: $(SCALACMD)

.PHONY: $(GROOVYCMD) $(SCALACMD)
$(GROOVYCMD) $(SCALACMD):
	$(RM) $(@F)
	$(LN) $@ $(@F)

シンボリックリンクの更新時刻はリンク先ファイルの更新時刻そのものだ。なのでシンボリックそのものを操作したい場合、makeによるファイル更新時刻のチェックとは相性が悪い。面倒なのでここでは基本的に擬似ターゲットとして扱い、強制的にリンクを張りなおすようにしている。

その影響もあってgroovyとscalaシンボリックリンク張りなおしの部分は少々変態的な書き方になっている。ターゲット名がシンボリックリンクではなくリンク対象のファイルなのだ。あべこべだ。

このMakefileの欠点は、リンク対象のスクリプトの減少や名前の変更に弱い点だろう。新しいバージョンの処理系にて削除されたスクリプトへのリンクが削除されずに残ってしまうので、手作業で削除しなくてはならない。