シェルのコマンドが異なるので、両方に対応するのは意外とめんどくさい。 今回はシンボリックリンクを作成するコマンドを例にして説明する。

WindowsのmakeはMinGWのものを想定している。

Linux専用

install:
    ln -s ~/dotfiles/.vimrc ~/.vimrc;

シンボリックリンクを作るコマンドをそのまま書いただけ。

Windows専用

install:
    cmd.exe /C mklink $(HOME)\.vimrc $(HOME)\dotfiles\.vimrc

Windowsのコマンドを使う場合は、cmd.exe /Cを接頭語のように付ける。 これで、mklinkコマンドが使えるようになる。

Linux用と比べて以下の点が異なっている

  • sourceとtargetの順番が逆
  • パスのディレクトリ区切りがバックスラッシュ
  • ホームディレクトリの指定がチルダではなく$(HOME)
    • 環境変数HOMEをあらかじめ指定する必要があるかも

両対応版

愚直に書くと以下のようになる。 ifeq ($(OS),Windows_NT)でWindowsかどうかを分岐させている。

install:
ifeq ($(OS),Windows_NT)
    ln -s ~/dotfiles/.vimrc ~/.vimrc;
else
    cmd.exe /C mklink $(HOME)\.vimrc $(HOME)\dotfiles\.vimrc
endif

この書き方だと、シンボリックリンクを張るファイルが増えると、Linux用とWindows用のそれぞれに追記する必要がある。 以下のように書くとスマート。

install:
	make link SOURCE:=$(HOME)/dotfiles/.vimrc TARGET:=$(HOME)/.vimrc

link:
ifeq ($(OS),Windows_NT)
    cmd.exe /C mklink $(subst /,\,$(TARGET)) $(subst /,\,$(SOURCE))
else
    ln -s $(SOURCE) $(TARGET)
endif

linkというターゲットを用意して、関数のように使っている。 linkの中でOSを分岐させることで、それを呼び出す側を統一できるというわけ。

substというのはmakeの文字列置換関数。スラッシュをバックスラッシュに置き換えるために使っている。

おまけ

ここまででほぼ完成。

最後に鬱陶しい出力を抑えるために、--no-print-directoryしたり、シンボリックリンクが既に存在している場合にはコマンドをスキップする仕組みを入れたものを載せる (解説は割愛)。

MAKEFLAGS += --no-print-directory

install:
	make link SOURCE:=$(HOME)/dotfiles/.vimrc TARGET:=$(HOME)/.vimrc

link:
ifeq ($(OS),Windows_NT)
	@cmd.exe /C if not exist $(subst /,\,$(TARGET)) \
		cmd.exe /C mklink $(subst /,\,$(TARGET)) $(subst /,\,$(SOURCE))
else
	@if [ ! -e $(TARGET) ]; then\
		ln -s $(SOURCE) $(TARGET);\
	fi
endif