Registering installation

port をインストールするとき、「Registering installation...」と「Checking if xxx already installed」にやたら時間がかかるのが不思議だったので、調べたメモ。

BSD make の基礎知識

=       変数に値を代入する。
+=      現在の変数の値に、右辺の値を追加する。
?=	変数が未定義の場合のみ代入する。
:=	右辺を展開した値を代入。通常、値の展開は代入時でなく、変数参照時に行われる。
!=      右辺を展開した値をシェルに実行させ、実行結果を左辺の変数に代入する。
${COMMENT:Q}      変数 COMMENT 中のシェルメタ文字をクォートする。
$${HOGE}              シェルの変数 HOGE

Registering ...

	@if [ ! -d ${PKG_DBDIR}/${PKGNAME} ]; then \
		if [ -z "${DESTDIR}" ] ; then \
			${ECHO_MSG} "===>   Registering installation for ${PKGNAME}"; \
		else \
			${ECHO_MSG} "===>   Registering installation for ${PKGNAME} in ${DESTDIR}"; \
		fi; \

		# 「FreeBSD port 作成者のためのハンドブック」には pkg-comment というファイルに一行コメントを
		# 書くとあるけど、今は各 port の Makefile 内に書くようだ。

		# パッケージ xfce4-desktop-4.4.1 をインストールする場合:
		# mkdir -p /var/db/pkg/xfce4-desktop-4.4.1
		${MKDIR} ${PKG_DBDIR}/${PKGNAME}; \
		# pkg_create -v -c -${COMMENT:Q} -d ${DESCR} -f ${TMPPLIST} -p ${PREFIX} -P "`cd ${.CURDIR} && ${MAKE} package-depends | ${GREP} -v -E ${PKG_IGNORE_DEPENDS} | ${SORT} -u`" ${EXTRA_PKG_ARGS} $${_LATE_PKG_ARGS}
		# 	-v verbose
		#	-c 一行説明ファイルを指定
		#	-d 説明ファイルを指定
		#	-f パッケージ内のファイルリストを指定
		#	-p インストール先ディレクトリプレフィックス
		#	-P 依存するパッケージのリスト。
		#	   .CURDIR は make が暗黙に設定する内部変数。make が起動されたディレクトリを表す。
		#	   make package-depends をすると、以下のような形式で依存するパッケージ一覧が出力される。これがけっこう遅い。
		#	   	hicolor-icon-theme-0.5:misc/hicolor-icon-theme
		#	   	xfce4-panel-4.4.1:x11-wm/xfce4-panel
		#	   	startup-notification-0.7:x11/startup-notification
		#
		${PKG_CMD} ${PKG_ARGS} -O ${PKGFILE} > ${PKG_DBDIR}/${PKGNAME}/+CONTENTS; \
		# pkg-descr を /var/db/pkg/xfce4-desktop-4/+DESC にコピー
		${CP} ${DESCR} ${PKG_DBDIR}/${PKGNAME}/+DESC; \
		# 一行コメントを +COMMENT に保存
		${ECHO_CMD} ${COMMENT:Q} > ${PKG_DBDIR}/${PKGNAME}/+COMMENT; \
		# インストール時に実行するスクリプトをコピー
		if [ -f ${PKGINSTALL} ]; then \
			${CP} ${PKGINSTALL} ${PKG_DBDIR}/${PKGNAME}/+INSTALL; \
		fi; \
		# アンインストール時に実行するスクリプトをコピー
		if [ -f ${PKGDEINSTALL} ]; then \
			${CP} ${PKGDEINSTALL} ${PKG_DBDIR}/${PKGNAME}/+DEINSTALL; \
		fi; \
		# +REQUIRE スクリプトをコピー
		if [ -f ${PKGREQ} ]; then \
			${CP} ${PKGREQ} ${PKG_DBDIR}/${PKGNAME}/+REQUIRE; \
		fi; \
		# インストール後に表示するメッセージファイルをコピー
		if [ -f ${PKGMESSAGE} ]; then \
			${CP} ${PKGMESSAGE} ${PKG_DBDIR}/${PKGNAME}/+DISPLAY; \
		fi; \
		# pkginfo で依存するパッケージを探す。これも遅い。
		# 	-q 静かに
		# 	-f パッケージの packing list instructions を表示。以下のような形式。
		# 	@pkgdep libiconv-1.9.2_2
		# 	@comment DEPORIGIN:converters/libiconv
		for dep in `${PKG_INFO} -qf ${PKGNAME} | ${AWK} '/^@pkgdep / {print $$2}' | ${SORT} -u`; do \
			# 依存するパッケージが既にインストールされていて、それが無視すべきものでないなら
			if [ -d ${PKG_DBDIR}/$$dep -a -z `${ECHO_CMD} $$dep | ${GREP} -E ${PKG_IGNORE_DEPENDS}` ]; then \
				# +REQUIRED_BY にこのパッケージが入っていないなら
				if ! ${GREP} ^${PKGNAME}$$ ${PKG_DBDIR}/$$dep/+REQUIRED_BY \
					>/dev/null 2>&1; then \
					# +REQUIRED_BY に追加する。
					${ECHO_CMD} ${PKGNAME} >> ${PKG_DBDIR}/$$dep/+REQUIRED_BY; \
				fi; \
			fi; \
		done; \

Checking if

.if !defined(DESTDIR)
		@${ECHO_MSG} "===>  Checking if ${PKGORIGIN} already installed"
.else
		@${ECHO_MSG} "===>  Checking if ${PKGORIGIN} already installed in ${DESTDIR}"
.endif
		# mkdir -p /var/db/pkg
		@${MKDIR} ${PKG_DBDIR}; \
		# -O origin   origin を起源としてもつ全パッケージを表示する。
		#  	起源とは要するに ports ツリーでのディレクトリ位置のこと。
		#  	実行例:
		#  	# pkg_info -q -O x11-wm/xfce4-desktop
		#	xfce4-desktop-4.4.1
		already_installed=`${PKG_INFO} -q -O ${PKGORIGIN}`; \
		if [ -n "$${already_installed}" ]; then \
				for p in $${already_installed}; do \
						# pkg_info -q -p     インストール用プレフィックスを表示
						# 実行例:
						## pkg_info -q -p xfce4-desktop-4.4.1
						# @cwd /usr/local
						prfx=`${PKG_INFO} -q -p $${p} 2> /dev/null | ${SED} -ne '1s|^@cwd ||p'`; \
						# 今インストールしようとしているプレフィックスと既にインストールされているもののプレフィックスとが同じなら
						if [ "x${PREFIX}" = "x$${prfx}" ]; then \
								# 既にインストールしたパッケージのファイル一覧と、今インストールしようとしているファイル一覧の comm をとる
								df=`${PKG_INFO} -q -f $${p} 2> /dev/null | ${GREP} -v "^@" | ${COMM} -12 - ${TMPPLIST}`; \
								# 1行でも共通部分があったら found
								if [ -n "$${df}" ]; then \
										found_package=$${p}; \
										break; \
								fi; \
						fi; \
				done; \
		fi ; \
		# /var/db/pkg に同名のパッケージが見つかった、または found_package があったら
		if [ -d ${PKG_DBDIR}/${PKGNAME} -o -n "$${found_package}" ]; then \
                                # ディレクトリ名が一致ならインストールしようとしているのと同バージョン
				if [ -d ${PKG_DBDIR}/${PKGNAME} ]; then \
					if [ -z "${DESTDIR}" ] ; then \
						${ECHO_MSG} "===>   ${PKGNAME} is already installed"; \
					else \
						${ECHO_MSG} "===>   ${PKGNAME} is already installed in ${DESTDIR}"; \
					fi; \
                                # そうでないなら旧バージョンがインストールされている。
				else \
					if [ -z "${DESTDIR}" ] ; then \
						${ECHO_MSG} "===>   An older version of ${PKGORIGIN} is already installed ($${found_package})"; \
					else \
						${ECHO_MSG} "===>   An older version of ${PKGORIGIN} is already installed in ${DESTDIR} ($${found_package})"; \
					fi; \
				fi; \
				${ECHO_MSG} "      You may wish to \`\`make deinstall'' and install this port again"; \
				${ECHO_MSG} "      by \`\`make reinstall'' to upgrade it properly."; \
				${ECHO_MSG} "      If you really wish to overwrite the old port of ${PKGORIGIN}"; \
				${ECHO_MSG} "      without deleting it first, set the variable \"FORCE_PKG_REGISTER\""; \
				${ECHO_MSG} "      in your environment or the \"make install\" command line."; \
				exit 1; \
		fi
.else

bsd.port.mk 合計 6031 行。/var/db/pkg にファイルシステムだけを使って構築されたパッケージのデータベース。これでこそ Unix …というべきなのだろうか?