PDFで公開されているMake本をマージする | kanta’s spikeで、公開されているGNU Make 第3版のPDFをマージするシェルスクリプトを作成したことを紹介しました。
折角なので、この『Make本』を読んで学びたいと思います。
そして、勉強の成果として、PDFで公開されているMake本をマージする | kanta’s spikeで作成したシェルスクリプトをmakefile
に置き換えたいと思います。
Makeについてはこれまで、メタプログラミング · the missing semester of your cs educationで学んだり、コピペでツールインストール用に使用してきました。1
この機会に、ちゃんと make
について学びたいと思います。
ターゲットと依存関係の整理
makefile
の基本構成は以下になるようです。
target: prereq1 prereq2
commands
用語の意味は以下になります。
target
: ファイルもしくは何か作り出されるものprereq
: 必須項目(または依存項目)。ターゲットが作成される前に必要なものcommands
: 必須項目からターゲットを作るためのコマンド
以前作成したシェルスクリプトをもとに、『Make本』のマージ版PDFを作成するための、依存関係を整理します。
target | prereq | メモ |
---|---|---|
マージ版目次付きpdf2 | マージ版PDF3 | make_book_pdf/03_add_toc.shから整理 |
目次情報ファイル4 | ||
マージ版PDF3 | ダウンロードした章別PDF | make_book_pdf/02_merge_pdf.shから整理 |
改訂情報PDF5 | ||
ダウンロードした章別PDF | 章別PDFのURL一覧6 | make_book_pdf/01_download_pdf.shから整理 |
PDFダウンロード用ディレクトリ7 | ||
改訂情報PDF5 | 改訂情報PDFの原本8 | cp で作成 |
PDFダウンロード用ディレクトリ7 | mkdir -p で作成 |
|
目次情報ファイル4 | 手動で作成 | |
章別PDFのURL一覧6 | 手動で作成 | |
改訂情報PDFの原本8 | 手動で作成 |
疑問点の整理
前項でシェルスクリプトからターゲットと依存関係を整理しました。 しかし、いくつか疑問があります。
「Make本」を読んで、疑問点と対策案をまとめてみました。
疑問 | 対策案 | 参照 |
---|---|---|
ダウンロードした章別のPDF群 は、どのようにターゲットを定義するのか? |
$(TOUCH) build/downloaded でダミーファイルとして対応する? |
11.1.4 ソーステキストの検証 |
commands としてwhile 文などの数行あるシェルスクリプトを記載できるのか? |
1行のスクリプトを\ で改行することで対応できそう |
5.1.1 長いコマンド |
curl やgit などのコマンドを利用しているが、それらのコマンドの存在チェックは必要か? |
コマンドを変数で定義して、環境に応じて再定義が必要なことをREADMEに記載しておく | 7章 ポータブルなmakefile |
Makefileの作成
これまでの整理を踏まえて作成したMakefile
が以下になります。
BUILD_DIR := ./build
DOWNLOAD_DIR := $(BUILD_DIR)/pdf
OUTLINE_TOOL_DIR := $(BUILD_DIR)/pdfoutline
URL_LIST := ./URL.txt
TOC_FILE := ./toc.txt
ADDITIONAL_PDF := ./additional_info.pdf
COMBINED_PDF := $(BUILD_DIR)/_make.pdf
OUTPUT_PDF := make_merged.pdf
DOWNLOAD_INTERVAL_SEC := 15
# for debug
QUIET = @
# commands
TOUCH = touch
CURL = curl
GS = gs
GIT = git
PYTHON3 = python3
.PHONY: all
all: $(OUTPUT_PDF)
# add toc to combined pdf
$(OUTPUT_PDF): $(TOC_FILE) $(OUTLINE_TOOL_DIR) $(COMBINED_PDF)
$(PYTHON3) $(OUTLINE_TOOL_DIR)/pdfoutline.py $(COMBINED_PDF) $(TOC_FILE) $@
# clone tool
$(OUTLINE_TOOL_DIR):
$(GIT) clone https://github.com/yutayamamoto/pdfoutline.git $@
# combine pdf
$(COMBINED_PDF): $(BUILD_DIR)/downloaded $(ADDITIONAL_PDF)
cp -p $(ADDITIONAL_PDF) $(DOWNLOAD_DIR)/025.pdf
$(GS) -dNOPAUSE -sDEVICE=pdfwrite -sOUTPUTFILE=$@ -dBATCH $(DOWNLOAD_DIR)/*.pdf
# download from URL_LIST
$(BUILD_DIR)/downloaded: $(URL_LIST) $(DOWNLOAD_DIR)
$(QUIET) idx=1; \
while read line || [ -n "$${line}" ]; \
do \
output_path=$(DOWNLOAD_DIR)/`printf "%02d" $$idx`0.pdf; \
echo "download $${line} to $${output_path} ..."; \
$(CURL) $${line} -o $${output_path}; \
idx=$$(($$idx+1)); \
echo "sleep $(DOWNLOAD_INTERVAL_SEC)sec..."; \
sleep $(DOWNLOAD_INTERVAL_SEC); \
done < $<
$(TOUCH) $@
# make download dir
$(DOWNLOAD_DIR):
mkdir -p $(DOWNLOAD_DIR)
# clean
.PHONY: clean
clean:
rm -rf $(DOWNLOAD_DIR)
rm $(COMBINED_PDF)
rm $(BUILD_DIR)/downloaded
rm $(OUTPUT_PDF)
.PHONY: clean-all
clean-all:
rm -rf $(BUILD_DIR)
rm $(OUTPUT_PDF)
まとめ
生成物(ターゲット)が依存するファイルが新しくなったら、make
すると自動的に更新されるので、便利になりました。
作成済の他ツールのMakefileを修正しながら、もっとmake
になれていきたいと思います。
学んだ事
-
シェルスクリプトと組合せる場合、
for文
などは1行で記載し、\
で改行する 9例えば、このような
for
文の場合を考える。for i in 1 2 3 do echo hello echo world done
1行で記載するとこのようになる。
for i in 1 2 3; do echo hello; echo world; done
Makefile
内には、コマンドに1行のシェルスクリプトとして記載できる。$(ターゲット): for i in 1 2 3; do echo hello; echo world; done
1行だと行が長すぎる場合は、
\
を使って改行する。$(ターゲット): for i in 1 2 3; \ do \ echo hello; \ echo world; \ done
-
シェルスクリプト内の変数は、makeの変数と区別するため、
$$変数名
に変更する必要がある10 11MSG := hello x := world $(ターゲット): for i in 1 2 3; \ do \ echo $(MSG) $x $$i; \ done
参考
- O’Reilly Japan - GNU Make 第3版
- メタプログラミング · the missing semester of your cs education
- kantas-spike/make_book_pdf: 『GNU Make 第3版』 各章マージ版PDF
- yutayamamoto/pdfoutline: A command line tool for adding an outline to pdf files
-
コピペでなんとなくMakefileを作成していました。 ↩︎
-
make_merged.pdf ↩︎
-
make_book_pdf/toc.txt at main · kantas-spike/make_book_pdf ↩︎ ↩︎
-
make_book_pdf/URL.txt at main · kantas-spike/make_book_pdf ↩︎ ↩︎
-
make_book_pdf/additional_info.pdf at main · kantas-spike/make_book_pdf ↩︎ ↩︎
-
makeの変数値を取得するには$(変数名)で取得する。変数名が1文字の場合は、括弧を省略して$変数名で取得できる。 ↩︎