◆ 御注意 ◆
この記事で紹介したスクリプトは、タイトルどおりの受け狙いパフォーマンスです。
おおむねは期待したとおりに動作しますが、少し詳しく検証するとポロポロと穴が見つかります。
重要なビルドシステムに組み込んだりすることは、間違ってもお勧めしません。
◆ 御注意 ◆
一身上の都合により GNU Make の Makefile で、とあるふたつのディレクトリ A から B への相対パスを動的に生成しなければならなくなりました。
Make のスクリプトはチューリング完全なプログラミング言語だと噂に聞いたことはありましたが、これはさすがに難しいでしょう。
……と思っていたら、できてしまいました。
Makefile
comma := ,
empty :=
space := $(empty) $(empty)
# exsample path
FROM_PATH := ../a/../b/c/d/c
#FROM_PATH := ../b/x/y
TO_PATH := ../b/x/y
#TO_PATH := ../a/../b/c/d/c
# function relpath_from
relpath_from = $(subst $(space),/,$(strip \
$(foreach dir,$(basename $(foreach dir,$(join $(subst /,$(space),$(abspath $(1))),$(addprefix .,$(subst /,$(space),$(abspath $(2))))),$(filter-out $(basename $(dir)).$(basename $(dir)),$(dir)))),$(patsubst %,..,$(dir))) \
$(foreach dir,$(suffix $(foreach dir,$(join $(subst /,$(space),$(abspath $(1))),$(addprefix .,$(subst /,$(space),$(abspath $(2))))),$(filter-out $(basename $(dir)).$(basename $(dir)),$(dir)))),$(subst .,$(empty),$(dir)))))
# step trace
F_ABS := $(abspath $(FROM_PATH))
T_ABS := $(abspath $(TO_PATH))
F_WORD := $(subst /,$(space),$(F_ABS))
T_WORD := $(subst /,$(space),$(T_ABS))
PAIRING := $(join $(F_WORD),$(addprefix .,$(T_WORD)))
CROSSOFF := $(foreach dir,$(PAIRING),$(filter-out $(basename $(dir)).$(basename $(dir)),$(dir)))
UPPER := $(foreach dir,$(basename $(CROSSOFF)),$(patsubst %,..,$(dir)))
DOWNER := $(foreach dir,$(suffix $(CROSSOFF)),$(subst .,$(empty),$(dir)))
CONCAT := $(subst $(space),/,$(strip $(UPPER) $(DOWNER)))
all:
@echo from_path: $(FROM_PATH)
@echo to_path: $(TO_PATH)
@echo $(call relpath_from,$(FROM_PATH),$(TO_PATH))
@echo ===== step trace =====
@echo from_path: $(FROM_PATH)
@echo to_path: $(TO_PATH)
@echo -----
@echo from_abs_path: $(F_ABS)
@echo to_abs_path: $(T_ABS)
@echo -----
@echo from_words: $(F_WORD)
@echo to_words: $(T_WORD)
@echo -----
@echo pairing: $(PAIRING)
@echo cross-off: $(CROSSOFF)
@echo -----
@echo upper: $(UPPER)
@echo downer: $(DOWNER)
@echo $(CONCAT)
あ、ディレクトリ名自体に .(ピリオド) を含んでいるケースは想定していないです、面倒くさいので。
パスは違うけれどたまたま同じ階層に同じ名前のディレクトリがあったりすると、動作がおかしくなります。
それから、たぶん独自拡張の関数を使っているので GNU Make 以外では動かないんじゃないでしょうか。
$ make
from_path: ../a/../b/c/d/c
to_path: ../b/x/y
../../../x/y
===== step trace =====
from_path: ../a/../b/c/d/c
to_path: ../b/x/y
-----
from_abs_path: /Users/b/c/d/c
to_abs_path: /Users/b/x/y
-----
from_words: Users b c d c
to_words: Users b x y
-----
pairing: Users.Users b.b c.x d.y c
cross-off: c.x d.y c
-----
upper: .. .. ..
downer: x y
../../../x/y