4 # bsd.destdir.mk - Support for chrooted installation
6 # Created by: Gabor Kovesdan <gabor@FreeBSD.org>
10 # Please make sure all changes to this file are passed through the maintainer.
12 DESTDIR_Include_MAINTAINER= portmgr@FreeBSD.org
15 # The target order is always: pre-chroot do-chroot post-chroot
18 # - You can use this for special preparation work, that
19 # want to do before chrooting into the destination
20 # environment and doing the real build. At default
21 # this target is empty.
24 # - This is the main target for doing the chrooted
25 # operations. It mounts the ports tree and devfs into
26 # the destination environment and starts make(1)
27 # by calling chroot(1).
30 # - This target runs chrooted just after chroot(1) was
31 # called. You can use this for special preparation
32 # work for the chrooted build if necessary. At
33 # default, this target is empty.
36 # - Contains names of the variables in host environ(7),
37 # which should be imported into the chrooted environ
38 # along with their values.
42 # - Contains the directories to mount into the
43 # destination. This is to make PORTSDIR, DISTDIR, etc.
44 # available in the destination environment. Three
45 # forms of entries are allowed:
47 # - Mounts the path contained by VAR into
48 # a temporary directory and sets VAR to that
49 # directory in the destination environ(7).
51 # - Mounts HOST_PATH to a a temporary directory
52 # and sets VAR to that directory in the
53 # destination environ(7).
54 # VAR:HOST_PATH:DEST_PATH
55 # - Mounts HOST_PATH to DEST_PATH and sets VAR
56 # to DEST_PATH in the destination environ(7).
57 # Default: PORTSDIR DISTDIR
59 # You can use something like this in host /etc/make.conf to
60 # customize per-chroot environment:
61 # .if ${DESTDIR}=/foo/bar
64 # DESTDIR_ENV_LIST=PREFIX CFLAGS
68 .if !defined(_DESTDIRMKINCLUDED)
70 _DESTDIRMKINCLUDED= yes
72 .if defined(WITH_DESTDIR_DEBUG)
73 DEBUG_MSG= ${ECHO_MSG} "DEBUG:"
79 DESTDIR_ENV= CHROOTED=yes PATH=${PATH} TERM=${TERM}
80 .for _var in ${DESTDIR_ENV_LIST:NDESTDIR:NCHROOTED:NPORTSDIR}
81 DESTDIR_ENV+= ${_var}="${${_var}}"
84 # Processing DESTDIR_MOUNT_LIST into something more machine-readable
85 # VAR:HOST_PATH:DEST_PATH
86 # VAR -> VAR:${VAR}:TMP
87 # VAR:HOST_PATH -> VAR:HOST_PATH:TMP
88 DESTDIR_MOUNT_LIST?= PORTSDIR DISTDIR
90 .for _entry in ${DESTDIR_MOUNT_LIST}
92 .if ${__entry:M*\:*\:*}
93 _DESTDIR_MOUNT_LIST+= ${_entry}
94 .elif ${__entry:M*\:*}
95 _DESTDIR_MOUNT_LIST+= ${_entry}:___temp___
97 .if defined(${_entry}) && !empty(${_entry})
98 _DESTDIR_MOUNT_LIST+= ${_entry}:${${_entry}}:___temp___
104 .for _target in ${.TARGETS}
105 ${_target}: pre-chroot do-chroot
109 .if !target(pre-chroot)
114 .if !target(do-chroot)
116 @if [ ! -d ${DESTDIR} ]; then \
117 ${ECHO_MSG} "===> Directory ${DESTDIR} does not exist"; \
118 ${ECHO_MSG} "===> Please set DESTDIR to a valid jail environment."; \
121 _destdir=`${REALPATH} ${DESTDIR}`; \
122 _mounted_entries_list=""; \
123 _created_mountpoints_list=""; \
125 ${ECHO_MSG} "===> Creating some important subdirectories"; \
126 for _dir in tmp dev; do \
127 [ -d $${_destdir}/$${_dir} ] || \
128 if ${MKDIR} $${_destdir}/$${_dir}; then \
129 ${ECHO_MSG} "===> /$${_dir} subdirectory has been successfully created"; \
130 _created_mountpoints_list="$${_destdir}/$${_dir} $${_created_mountpoints_list}"; \
132 ${ECHO_MSG} "===> /$${_dir} subdirectory could not be created"; \
136 ${DEBUG_MSG} "_DESTDIR_MOUNT_LIST=${_DESTDIR_MOUNT_LIST}"; \
137 for _entry in ${_DESTDIR_MOUNT_LIST}; do \
138 ${DEBUG_MSG} "Processing $${_entry}"; \
139 _mount_var=$${_entry%%:*}; \
141 _host_path=`${REALPATH} $${_tp%:*}`; \
142 _dest_path=$${_entry##*:}; \
143 _full_dest_path=`${REALPATH} -q $${_destdir}/$${_dest_path} || :`; \
144 _entry_was_created=0; \
145 _entry_should_mount=0; \
146 ${DEBUG_MSG} "$${_mount_var}:$${_host_path}:$${_full_dest_path}"; \
147 if [ "$${_dest_path}" = "___temp___" ]; then \
148 ${DEBUG_MSG} "Creating temporary mount point"; \
149 if _full_dest_path=`${MKTEMP} -d $${_destdir}/tmp/mountpoint.XXXXXX`; then \
150 ${DEBUG_MSG} "Temporary mount point $${_full_dest_path} created successfully"; \
151 _entry_was_created=1; \
152 _entry_should_mount=1; \
153 _dest_path=$${_full_dest_path#$${_destdir}}; \
154 _created_mountpoints_list="$${_full_dest_path} $${_created_mountpoints_list}"; \
156 ${ECHO_MSG} "===> Failed to create temporary mount point"; \
160 ${DEBUG_MSG} "Checking if already mounted"; \
161 if ${MOUNT}|${GREP} -qs "^$${_host_path} on $${_full_dest_path} ("; then \
162 ${DEBUG_MSG} "$${_host_path} is already mounted on $${_full_dest_path}"; \
163 _var_path_list="$${_var_path_list} $${_mount_var}=$${_dest_path}"; \
165 ${DEBUG_MSG} "$${_host_path} is not mounted on $${_full_dest_path}"; \
166 _entry_should_mount=1; \
169 [ -d $${_full_dest_path} ] || \
170 if ${MKDIR} $${_full_dest_path}; then \
171 ${DEBUG_MSG} "Mount point $${_full_dest_path} created"; \
172 _entry_was_created=1; \
173 _created_mountpoints_list="$${_created_mountpoints_list} ${_full_dest_path}"; \
175 ${ECHO_MSG} "===> Mount point $${_full_dest_path} could not be created"; \
178 [ "$${_entry_should_mount}" = "0" ] || \
179 if ${MOUNT_NULLFS} $${_host_path} $${_full_dest_path}; then \
180 ${DEBUG_MSG} "Directory $${_host_path} mounted"; \
181 _mounted_entries_list="$${_full_dest_path} $${_mounted_entries_list}"; \
182 _var_path_list="$${_var_path_list} $${_mount_var}=$${_dest_path}"; \
184 ${ECHO_MSG} "===> Dir $${_host_path} could not be mounted"; \
185 [ "$${_entry_was_created}" = "0" ] || \
186 ${RMDIR} $${_full_dest_path} || ${TRUE}; \
190 ${DEBUG_MSG} "Handling devfs separately"; \
191 _full_dest_path=$${_destdir}/dev; \
192 ${MOUNT}|${GREP} -qs "^devfs on $${_full_dest_path} (" || \
193 if ${MOUNT_DEVFS} $${_full_dest_path}; then \
194 ${DEBUG_MSG} "devfs mounted"; \
195 _mounted_entries_list="$${_full_dest_path} $${_mounted_entries_list}"; \
197 ${ECHO_MSG} "===> devfs could not be mounted"; \
198 [ -n "$${_created_mountpoints_list%%* $${_destdir}/dev *}" ] || \
199 ${RMDIR} $${_destdir}/dev || ${TRUE}; \
202 _var_path_list="$${_var_path_list} DEVFS=/dev"; \
203 ${DEBUG_MSG} "Things we mounted: $${_mounted_entries_list}"; \
204 ${DEBUG_MSG} "Things we created: $${_created_mountpoints_list}"; \
205 ${DEBUG_MSG} "_var_path_list: $${_var_path_list}"; \
206 ${ECHO_MSG} "===> Starting chrooted make in ${DESTDIR}..."; \
207 export $${_var_path_list}; \
208 ${CHROOT} $${_destdir} ${SH} -c "\
209 cd $${PORTSDIR}${.CURDIR:S|^${PORTSDIR}||}; \
210 ${SETENV} -i ${DESTDIR_ENV} $${_var_path_list} ${MAKE} ${.TARGETS}" && \
211 { status=$$?; ${ECHO_MSG} "===> Chrooted make in ${DESTDIR} succeeded"; } || \
212 { status=$$?; ${ECHO_MSG} "===> Chrooted make in ${DESTDIR} failed"; }; \
213 ${ECHO_MSG} "===> Cleaning up..."; \
214 for _entry in $${_mounted_entries_list}; do \
215 ${UMOUNT} -f $${_entry} || ${TRUE}; \
217 for _entry in $${_created_mountpoints_list}; do \
218 ${RMDIR} $${_entry} || ${TRUE}; \
221 .endif # !target(do-chroot)
222 .endif # !defined(_DESTDIRMKINCLUDED)