bsd.destdir.mk 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. #-*- tab-width: 4; -*-
  2. # ex:ts=4
  3. #
  4. # bsd.destdir.mk - Support for chrooted installation
  5. #
  6. #
  7. # Please make sure all changes to this file are passed through the maintainer.
  8. DESTDIR_Include_MAINTAINER= portmgr@FreeBSD.org
  9. #
  10. # The target order is always: pre-chroot do-chroot post-chroot
  11. #
  12. # pre-chroot
  13. # - You can use this for special preparation work, that
  14. # want to do before chrooting into the destination
  15. # environment and doing the real build. At default
  16. # this target is empty.
  17. #
  18. # do-chroot
  19. # - This is the main target for doing the chrooted
  20. # operations. It mounts the ports tree and devfs into
  21. # the destination environment and starts make(1)
  22. # by calling chroot(1).
  23. #
  24. # post-chroot
  25. # - This target runs chrooted just after chroot(1) was
  26. # called. You can use this for special preparation
  27. # work for the chrooted build if necessary. At
  28. # default, this target is empty.
  29. #
  30. # DESTDIR_ENV_LIST
  31. # - Contains names of the variables in host environ(7),
  32. # which should be imported into the chrooted environ
  33. # along with their values.
  34. # Default: empty.
  35. #
  36. # DESTDIR_MOUNT_LIST
  37. # - Contains the directories to mount into the
  38. # destination. This is to make PORTSDIR, DISTDIR, etc.
  39. # available in the destination environment. Three
  40. # forms of entries are allowed:
  41. # VAR
  42. # - Mounts the path contained by VAR into
  43. # a temporary directory and sets VAR to that
  44. # directory in the destination environ(7).
  45. # VAR:HOST_PATH
  46. # - Mounts HOST_PATH to a a temporary directory
  47. # and sets VAR to that directory in the
  48. # destination environ(7).
  49. # VAR:HOST_PATH:DEST_PATH
  50. # - Mounts HOST_PATH to DEST_PATH and sets VAR
  51. # to DEST_PATH in the destination environ(7).
  52. # Default: PORTSDIR DISTDIR
  53. #
  54. # You can use something like this in host /etc/make.conf to
  55. # customize per-chroot environment:
  56. # .if ${DESTDIR}=/foo/bar
  57. # PREFIX=/opt
  58. # CFLAGS=-O3 -pipe
  59. # DESTDIR_ENV_LIST=PREFIX CFLAGS
  60. # .endif
  61. #
  62. .if !defined(_DESTDIRMKINCLUDED)
  63. _DESTDIRMKINCLUDED= yes
  64. . if defined(WITH_DESTDIR_DEBUG)
  65. DEBUG_MSG= ${ECHO_MSG} "DEBUG:"
  66. . else
  67. DEBUG_MSG= ${TRUE}
  68. . endif
  69. DESTDIR_ENV_LIST?=
  70. DESTDIR_ENV= CHROOTED=yes PATH=${PATH} TERM=${TERM}
  71. . for _var in ${DESTDIR_ENV_LIST:NDESTDIR:NCHROOTED:NPORTSDIR}
  72. DESTDIR_ENV+= ${_var}="${${_var}}"
  73. . endfor
  74. # Processing DESTDIR_MOUNT_LIST into something more machine-readable
  75. # VAR:HOST_PATH:DEST_PATH
  76. # VAR -> VAR:${VAR}:TMP
  77. # VAR:HOST_PATH -> VAR:HOST_PATH:TMP
  78. DESTDIR_MOUNT_LIST?= PORTSDIR DISTDIR
  79. _DESTDIR_MOUNT_LIST=
  80. . for _entry in ${DESTDIR_MOUNT_LIST}
  81. __entry=${_entry}
  82. . if ${__entry:M*\:*\:*}
  83. _DESTDIR_MOUNT_LIST+= ${_entry}
  84. . elif ${__entry:M*\:*}
  85. _DESTDIR_MOUNT_LIST+= ${_entry}:___temp___
  86. . else
  87. . if defined(${_entry}) && !empty(${_entry})
  88. _DESTDIR_MOUNT_LIST+= ${_entry}:${${_entry}}:___temp___
  89. . endif
  90. . endif
  91. . endfor
  92. .MAIN: all
  93. . for _target in ${.TARGETS}
  94. ${_target}: pre-chroot do-chroot
  95. @${TRUE}
  96. . endfor
  97. . if !target(pre-chroot)
  98. pre-chroot:
  99. @${TRUE}
  100. . endif
  101. . if !target(do-chroot)
  102. do-chroot:
  103. @if [ ! -d ${DESTDIR} ]; then \
  104. ${ECHO_MSG} "===> Directory ${DESTDIR} does not exist"; \
  105. ${ECHO_MSG} "===> Please set DESTDIR to a valid jail environment."; \
  106. exit 1; \
  107. fi; \
  108. _destdir=`${REALPATH} ${DESTDIR}`; \
  109. _mounted_entries_list=""; \
  110. _created_mountpoints_list=""; \
  111. _var_path_list=""; \
  112. ${ECHO_MSG} "===> Creating some important subdirectories"; \
  113. for _dir in tmp dev; do \
  114. [ -d $${_destdir}/$${_dir} ] || \
  115. if ${MKDIR} $${_destdir}/$${_dir}; then \
  116. ${ECHO_MSG} "===> /$${_dir} subdirectory has been successfully created"; \
  117. _created_mountpoints_list="$${_destdir}/$${_dir} $${_created_mountpoints_list}"; \
  118. else \
  119. ${ECHO_MSG} "===> /$${_dir} subdirectory could not be created"; \
  120. exit 2; \
  121. fi; \
  122. done; \
  123. ${DEBUG_MSG} "_DESTDIR_MOUNT_LIST=${_DESTDIR_MOUNT_LIST}"; \
  124. for _entry in ${_DESTDIR_MOUNT_LIST}; do \
  125. ${DEBUG_MSG} "Processing $${_entry}"; \
  126. _mount_var=$${_entry%%:*}; \
  127. _tp=$${_entry#*:}; \
  128. _host_path=`${REALPATH} $${_tp%:*}`; \
  129. _dest_path=$${_entry##*:}; \
  130. _full_dest_path=`${REALPATH} -q $${_destdir}/$${_dest_path} || :`; \
  131. _entry_was_created=0; \
  132. _entry_should_mount=0; \
  133. ${DEBUG_MSG} "$${_mount_var}:$${_host_path}:$${_full_dest_path}"; \
  134. if [ "$${_dest_path}" = "___temp___" ]; then \
  135. ${DEBUG_MSG} "Creating temporary mount point"; \
  136. if _full_dest_path=`${MKTEMP} -d $${_destdir}/tmp/mountpoint.XXXXXX`; then \
  137. ${DEBUG_MSG} "Temporary mount point $${_full_dest_path} created successfully"; \
  138. _entry_was_created=1; \
  139. _entry_should_mount=1; \
  140. _dest_path=$${_full_dest_path#$${_destdir}}; \
  141. _created_mountpoints_list="$${_full_dest_path} $${_created_mountpoints_list}"; \
  142. else \
  143. ${ECHO_MSG} "===> Failed to create temporary mount point"; \
  144. exit 9; \
  145. fi; \
  146. else \
  147. ${DEBUG_MSG} "Checking if already mounted"; \
  148. if ${MOUNT}|${GREP} -qs "^$${_host_path} on $${_full_dest_path} ("; then \
  149. ${DEBUG_MSG} "$${_host_path} is already mounted on $${_full_dest_path}"; \
  150. _var_path_list="$${_var_path_list} $${_mount_var}=$${_dest_path}"; \
  151. else \
  152. ${DEBUG_MSG} "$${_host_path} is not mounted on $${_full_dest_path}"; \
  153. _entry_should_mount=1; \
  154. fi; \
  155. fi; \
  156. [ -d $${_full_dest_path} ] || \
  157. if ${MKDIR} $${_full_dest_path}; then \
  158. ${DEBUG_MSG} "Mount point $${_full_dest_path} created"; \
  159. _entry_was_created=1; \
  160. _created_mountpoints_list="$${_created_mountpoints_list} ${_full_dest_path}"; \
  161. else \
  162. ${ECHO_MSG} "===> Mount point $${_full_dest_path} could not be created"; \
  163. exit 7; \
  164. fi; \
  165. [ "$${_entry_should_mount}" = "0" ] || \
  166. if ${MOUNT_NULLFS} $${_host_path} $${_full_dest_path}; then \
  167. ${DEBUG_MSG} "Directory $${_host_path} mounted"; \
  168. _mounted_entries_list="$${_full_dest_path} $${_mounted_entries_list}"; \
  169. _var_path_list="$${_var_path_list} $${_mount_var}=$${_dest_path}"; \
  170. else \
  171. ${ECHO_MSG} "===> Dir $${_host_path} could not be mounted"; \
  172. [ "$${_entry_was_created}" = "0" ] || \
  173. ${RMDIR} $${_full_dest_path} || ${TRUE}; \
  174. exit 8; \
  175. fi; \
  176. done; \
  177. ${DEBUG_MSG} "Handling devfs separately"; \
  178. _full_dest_path=$${_destdir}/dev; \
  179. ${MOUNT}|${GREP} -qs "^devfs on $${_full_dest_path} (" || \
  180. if ${MOUNT_DEVFS} $${_full_dest_path}; then \
  181. ${DEBUG_MSG} "devfs mounted"; \
  182. _mounted_entries_list="$${_full_dest_path} $${_mounted_entries_list}"; \
  183. else \
  184. ${ECHO_MSG} "===> devfs could not be mounted"; \
  185. [ -n "$${_created_mountpoints_list%%* $${_destdir}/dev *}" ] || \
  186. ${RMDIR} $${_destdir}/dev || ${TRUE}; \
  187. exit 9; \
  188. fi; \
  189. _var_path_list="$${_var_path_list} DEVFS=/dev"; \
  190. ${DEBUG_MSG} "Things we mounted: $${_mounted_entries_list}"; \
  191. ${DEBUG_MSG} "Things we created: $${_created_mountpoints_list}"; \
  192. ${DEBUG_MSG} "_var_path_list: $${_var_path_list}"; \
  193. ${ECHO_MSG} "===> Starting chrooted make in ${DESTDIR}..."; \
  194. export $${_var_path_list}; \
  195. ${CHROOT} $${_destdir} ${SH} -c "\
  196. cd $${PORTSDIR}${.CURDIR:S|^${PORTSDIR}||}; \
  197. ${SETENV} -i ${DESTDIR_ENV} $${_var_path_list} ${MAKE} ${.TARGETS}" && \
  198. { status=$$?; ${ECHO_MSG} "===> Chrooted make in ${DESTDIR} succeeded"; } || \
  199. { status=$$?; ${ECHO_MSG} "===> Chrooted make in ${DESTDIR} failed"; }; \
  200. ${ECHO_MSG} "===> Cleaning up..."; \
  201. for _entry in $${_mounted_entries_list}; do \
  202. ${UMOUNT} -f $${_entry} || ${TRUE}; \
  203. done; \
  204. for _entry in $${_created_mountpoints_list}; do \
  205. ${RMDIR} $${_entry} || ${TRUE}; \
  206. done; \
  207. exit $$status
  208. . endif # !target(do-chroot)
  209. .endif # !defined(_DESTDIRMKINCLUDED)