1*bb75b0d5SLexi Winter# SPDX-License-Identifier: ISC 2*bb75b0d5SLexi Winter# 3*bb75b0d5SLexi Winter# Copyright (c) 2026 Lexi Winter <ivy@FreeBSD.org> 4*bb75b0d5SLexi Winter# 5*bb75b0d5SLexi Winter# Permission to use, copy, modify, and distribute this software for any 6*bb75b0d5SLexi Winter# purpose with or without fee is hereby granted, provided that the above 7*bb75b0d5SLexi Winter# copyright notice and this permission notice appear in all copies. 8*bb75b0d5SLexi Winter# 9*bb75b0d5SLexi Winter# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10*bb75b0d5SLexi Winter# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11*bb75b0d5SLexi Winter# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12*bb75b0d5SLexi Winter# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13*bb75b0d5SLexi Winter# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14*bb75b0d5SLexi Winter# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15*bb75b0d5SLexi Winter# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16*bb75b0d5SLexi Winter 17*bb75b0d5SLexi Winter# bsd.pkg.mk: Create a package based on an existing plist and the template 18*bb75b0d5SLexi Winter# UCL files. This is intended for use by packages/* during the build, and 19*bb75b0d5SLexi Winter# cannot be used to generate standalone packages. 20*bb75b0d5SLexi Winter 21*bb75b0d5SLexi Winter.if !defined(REPODIR) 22*bb75b0d5SLexi Winter. error REPODIR must be set 23*bb75b0d5SLexi Winter.endif 24*bb75b0d5SLexi Winter 25*bb75b0d5SLexi Winter.if !defined(PKG_VERSION) 26*bb75b0d5SLexi Winter. error PKG_VERSION must be set 27*bb75b0d5SLexi Winter.endif 28*bb75b0d5SLexi Winter 29*bb75b0d5SLexi Winter_PKG_NEED_ABI= 30*bb75b0d5SLexi Winter.include <bsd.pkg.pre.mk> 31*bb75b0d5SLexi Winter.include <bsd.compat.pre.mk> 32*bb75b0d5SLexi Winter.include <src.opts.mk> 33*bb75b0d5SLexi Winter 34*bb75b0d5SLexi Winter# Allow flua to be overridden; the world build does this to use the 35*bb75b0d5SLexi Winter# bootstrap version. 36*bb75b0d5SLexi WinterFLUA?= /usr/libexec/flua 37*bb75b0d5SLexi Winter 38*bb75b0d5SLexi Winter# The directory that files to be packaged have been staged into. 39*bb75b0d5SLexi Winter# If ${WSTAGEDIR} is set from Makefile.inc1, use that, otherwise 40*bb75b0d5SLexi Winter# use the default location. 41*bb75b0d5SLexi Winter.if defined(WSTAGEDIR) 42*bb75b0d5SLexi Winter_PKG_WORLDSTAGE= ${WSTAGEDIR} 43*bb75b0d5SLexi Winter.else 44*bb75b0d5SLexi Winter_PKG_WORLDSTAGE= ${OBJTOP}/worldstage 45*bb75b0d5SLexi Winter.endif 46*bb75b0d5SLexi Winter 47*bb75b0d5SLexi Winter_PKGDIR= ${SRCTOP}/packages 48*bb75b0d5SLexi Winter_STAGEDIR= ${REPODIR}/${PKG_ABI}/${PKG_VERSION} 49*bb75b0d5SLexi Winter 50*bb75b0d5SLexi Winter# These are the default UCL variables we pass to generate-ucl.lua. 51*bb75b0d5SLexi Winter# Allow the caller to add additional variables via PKG_UCLVARS. 52*bb75b0d5SLexi Winter_UCLVARS= \ 53*bb75b0d5SLexi Winter VERSION "${PKG_VERSION}" \ 54*bb75b0d5SLexi Winter PKG_NAME_PREFIX "${PKG_NAME_PREFIX}" \ 55*bb75b0d5SLexi Winter PKG_WWW "${PKG_WWW}" \ 56*bb75b0d5SLexi Winter PKG_MAINTAINER "${PKG_MAINTAINER}" \ 57*bb75b0d5SLexi Winter ${PKG_UCLVARS} 58*bb75b0d5SLexi Winter 59*bb75b0d5SLexi Winter# Global pkg(8) arguments. 60*bb75b0d5SLexi Winter_PKG_ARGS= \ 61*bb75b0d5SLexi Winter -o ABI=${PKG_ABI} \ 62*bb75b0d5SLexi Winter -o OSVERSION=${PKG_OSVERSION} \ 63*bb75b0d5SLexi Winter -o ALLOW_BASE_SHLIBS=yes \ 64*bb75b0d5SLexi Winter -o SHLIB_PROVIDE_PATHS_NATIVE=/lib,/usr/lib \ 65*bb75b0d5SLexi Winter ${_ALL_LIBCOMPATS:range:@i@-o SHLIB_PROVIDE_PATHS_COMPAT_${_ALL_LIBCOMPATS:[$i]}=/usr/lib${_ALL_libcompats:[$i]}@} \ 66*bb75b0d5SLexi Winter 67*bb75b0d5SLexi Winter# Arguments to pkg-create(8). 68*bb75b0d5SLexi Winter_PKG_CREATE_ARGS= \ 69*bb75b0d5SLexi Winter -f ${PKG_FORMAT} \ 70*bb75b0d5SLexi Winter ${PKG_CLEVEL} \ 71*bb75b0d5SLexi Winter -T ${PKG_CTHREADS} \ 72*bb75b0d5SLexi Winter -r ${_PKG_WORLDSTAGE} \ 73*bb75b0d5SLexi Winter -o ${.OBJDIR} 74*bb75b0d5SLexi Winter 75*bb75b0d5SLexi Winter_PKG_CREATE= ${PKG_CMD} ${_PKG_ARGS} create ${_PKG_CREATE_ARGS} 76*bb75b0d5SLexi Winter 77*bb75b0d5SLexi Winter# If WORLDPACKAGE is set, we're building a world package. 78*bb75b0d5SLexi Winter.if defined(WORLDPACKAGE) 79*bb75b0d5SLexi Winter 80*bb75b0d5SLexi Winter# Default to using the same UCL file for all subpackages, since the vast 81*bb75b0d5SLexi Winter# majority of packages are built this way. 82*bb75b0d5SLexi WinterUCLSRC?= ${WORLDPACKAGE}.ucl 83*bb75b0d5SLexi Winter 84*bb75b0d5SLexi Winter# Nearly all packages have a dbg and man subpackage, so enable that by default. 85*bb75b0d5SLexi WinterSUBPACKAGES?= dbg man 86*bb75b0d5SLexi Winter 87*bb75b0d5SLexi Winter# This lets the caller use constructs like SUBPACKAGES.${MK_FOO}+= foo 88*bb75b0d5SLexi Winter_SUBPACKAGES= ${SUBPACKAGES} ${SUBPACKAGES.yes} ${SUBPACKAGES.yes.yes} 89*bb75b0d5SLexi Winter 90*bb75b0d5SLexi Winter# Remove the dbg subpackage if debug files are disabled. 91*bb75b0d5SLexi Winter.if ${MK_DEBUG_FILES} == "no" 92*bb75b0d5SLexi Winter_SUBPACKAGES:= ${_SUBPACKAGES:Ndbg} 93*bb75b0d5SLexi Winter. if defined(COMPAT_PKGS) 94*bb75b0d5SLexi WinterCOMPAT_PKGS:= ${COMPAT_PKGS:Ndbg} 95*bb75b0d5SLexi Winter. endif # defined(COMPAT_PKGS) 96*bb75b0d5SLexi Winter.endif # ${MK_DEBUG_FILES} == "no" 97*bb75b0d5SLexi Winter 98*bb75b0d5SLexi Winter# Remove the man subpackage if split man packages are disabled. 99*bb75b0d5SLexi Winter.if ${MK_MANSPLITPKG} == "no" 100*bb75b0d5SLexi Winter_SUBPACKAGES:= ${_SUBPACKAGES:Nman} 101*bb75b0d5SLexi Winter.endif # ${MK_MANSPLITPKG} == "no" 102*bb75b0d5SLexi Winter 103*bb75b0d5SLexi Winter# Add the base package, unless there isn't one, which can happen with 104*bb75b0d5SLexi Winter# static library packages. 105*bb75b0d5SLexi Winter.if !defined(PKG_NO_BASE) 106*bb75b0d5SLexi Winter_ALLPACKAGES= ${WORLDPACKAGE} 107*bb75b0d5SLexi Winter.endif 108*bb75b0d5SLexi Winter 109*bb75b0d5SLexi Winter# Add basic subpackages. 110*bb75b0d5SLexi Winter.for _subpackage in ${_SUBPACKAGES} 111*bb75b0d5SLexi Winter_ALLPACKAGES+= ${_subpackage:S/^/${WORLDPACKAGE}-/} 112*bb75b0d5SLexi Winter.endfor # _subpackage in ${_SUBPACKAGES} 113*bb75b0d5SLexi Winter 114*bb75b0d5SLexi Winter# Add libcompat subpackages. 115*bb75b0d5SLexi Winter.for LIBCOMPAT libcompat in ${_ALL_LIBCOMPATS_libcompats} 116*bb75b0d5SLexi Winter. if ${MK_LIB${LIBCOMPAT}} != "no" 117*bb75b0d5SLexi Winter 118*bb75b0d5SLexi Winter# For the base package... 119*bb75b0d5SLexi Winter. if ${COMPAT_PKG:Uno} != "no" 120*bb75b0d5SLexi Winter_ALLPACKAGES+= ${WORLDPACKAGE}-lib${libcompat} 121*bb75b0d5SLexi Winter. endif 122*bb75b0d5SLexi Winter 123*bb75b0d5SLexi Winter# And for subpackages. 124*bb75b0d5SLexi Winter. for _pkg in ${COMPAT_PKGS} 125*bb75b0d5SLexi Winter# lib is special, because it gets -lib32, not -lib-lib32. 126*bb75b0d5SLexi Winter. if ${_pkg} == "lib" 127*bb75b0d5SLexi Winter_ALLPACKAGES+= ${WORLDPACKAGE}-lib${libcompat} 128*bb75b0d5SLexi Winter. else 129*bb75b0d5SLexi Winter_ALLPACKAGES+= ${WORLDPACKAGE}-${_pkg}-lib${libcompat} 130*bb75b0d5SLexi Winter. endif 131*bb75b0d5SLexi Winter. endfor 132*bb75b0d5SLexi Winter 133*bb75b0d5SLexi Winter. endif # ${MK_LIB${LIBCOMPAT}} != "no" 134*bb75b0d5SLexi Winter.endfor 135*bb75b0d5SLexi Winter 136*bb75b0d5SLexi WinterCLEANFILES+= *.pkgucl *.ucl.in *.plist *.pkg 137*bb75b0d5SLexi Winter 138*bb75b0d5SLexi Winterall: .PHONY 139*bb75b0d5SLexi Winter 140*bb75b0d5SLexi Winter. for _pkg in ${_ALLPACKAGES} 141*bb75b0d5SLexi Winter_pkgfullname:= ${PKG_NAME_PREFIX}-${_pkg} 142*bb75b0d5SLexi Winter_pkgfilename:= ${_pkgfullname}-${PKG_VERSION}.pkg 143*bb75b0d5SLexi Winter 144*bb75b0d5SLexi Winterall: ${_pkgfilename} 145*bb75b0d5SLexi Winter 146*bb75b0d5SLexi Winter${_pkgfilename}: ${_pkgfullname}.pkgucl ${_pkg}.plist 147*bb75b0d5SLexi Winter # We should never create an empty package; this means we intended to 148*bb75b0d5SLexi Winter # build the package, but we didn't build the things which are supposed 149*bb75b0d5SLexi Winter # to be in the package, which means something went wrong somewhere. 150*bb75b0d5SLexi Winter # If you hit this check when building, it probably means a package is 151*bb75b0d5SLexi Winter # not properly excluded in packages/Makefile based on src.conf options. 152*bb75b0d5SLexi Winter @if [ "$$(grep -vc '^@dir' "${.ALLSRC:M*.plist}")" -eq 0 ]; \ 153*bb75b0d5SLexi Winter then \ 154*bb75b0d5SLexi Winter printf >&2 'ERROR: Refusing to build empty package %s from %s\n' \ 155*bb75b0d5SLexi Winter "${.TARGET}" "${.ALLSRC:M*.plist}"; \ 156*bb75b0d5SLexi Winter exit 1; \ 157*bb75b0d5SLexi Winter fi 158*bb75b0d5SLexi Winter ${_PKG_CREATE} -M ${.ALLSRC:M*.pkgucl} -p ${.ALLSRC:M*.plist} 159*bb75b0d5SLexi Winter 160*bb75b0d5SLexi Winter${_pkgfullname}.ucl.in: ${UCLSRC.${_pkg}:U${UCLSRC:U${_pkg}.ucl}} 161*bb75b0d5SLexi Winter @echo 'Generating ${.TARGET} from ${.ALLSRC}' 162*bb75b0d5SLexi Winter @cp ${.ALLSRC} ${.TARGET} 163*bb75b0d5SLexi Winter @echo >>${.TARGET} 'name = "${PKG_NAME_PREFIX}-${_pkg}"' 164*bb75b0d5SLexi Winter @echo >>${.TARGET} 'origin = "base/${PKG_NAME_PREFIX}-${_pkg}"' 165*bb75b0d5SLexi Winter @echo >>${.TARGET} 'categories [ "base" ]' 166*bb75b0d5SLexi Winter @echo >>${.TARGET} 'prefix = "/"' 167*bb75b0d5SLexi Winter @echo >>${.TARGET} 'version = "${PKG_VERSION}"' 168*bb75b0d5SLexi Winter @echo >>${.TARGET} 'maintainer = "${PKG_MAINTAINER}"' 169*bb75b0d5SLexi Winter @echo >>${.TARGET} 'www = "${PKG_WWW}"' 170*bb75b0d5SLexi Winter.if defined(PKG_VITAL.${_pkg}) 171*bb75b0d5SLexi Winter @echo >>${.TARGET} 'vital = true' 172*bb75b0d5SLexi Winter.endif 173*bb75b0d5SLexi Winter @echo >>${.TARGET} 'licenselogic = "${PKG_LICENSELOGIC}"' 174*bb75b0d5SLexi Winter @echo >>${.TARGET} 'licenses [' 175*bb75b0d5SLexi Winter.for _license in ${PKG_LICENSES} 176*bb75b0d5SLexi Winter # When a value contains spaces and is quoted (e.g., "X WITH Y"), 177*bb75b0d5SLexi Winter # make preserves the quotes in the value, so we need to strip them. 178*bb75b0d5SLexi Winter @echo >>${.TARGET} ' "${_license:S/"//g}",' 179*bb75b0d5SLexi Winter.endfor 180*bb75b0d5SLexi Winter @echo >>${.TARGET} ']' 181*bb75b0d5SLexi Winter @echo >>${.TARGET} 'annotations {' 182*bb75b0d5SLexi Winter.for _annotation in ${PKG_ANNOTATIONS} 183*bb75b0d5SLexi Winter @echo >>${.TARGET} ' ${_annotation} = "${PKG_ANNOTATIONS.${_annotation}}"' 184*bb75b0d5SLexi Winter.endfor 185*bb75b0d5SLexi Winter @echo >>${.TARGET} '}' 186*bb75b0d5SLexi Winter.if defined(PKG_DEPS.${_pkg}) 187*bb75b0d5SLexi Winter @echo >>${.TARGET} 'deps {' 188*bb75b0d5SLexi Winter. for _dep in ${PKG_DEPS.${_pkg}} 189*bb75b0d5SLexi Winter @echo >>${.TARGET} ' "${_dep}" {' 190*bb75b0d5SLexi Winter @echo >>${.TARGET} ' "origin" = "base/${PKG_NAME_PREFIX}-${_dep}"' 191*bb75b0d5SLexi Winter @echo >>${.TARGET} ' "version" = "${PKG_VERSION}"' 192*bb75b0d5SLexi Winter @echo >>${.TARGET} ' },' 193*bb75b0d5SLexi Winter. endfor 194*bb75b0d5SLexi Winter @echo >>${.TARGET} '}' 195*bb75b0d5SLexi Winter.endif 196*bb75b0d5SLexi Winter 197*bb75b0d5SLexi Winter${_pkgfullname}.pkgucl: ${_pkgfullname}.ucl.in 198*bb75b0d5SLexi Winter ${FLUA} ${SRCTOP}/release/packages/generate-ucl.lua \ 199*bb75b0d5SLexi Winter ${_UCLVARS} \ 200*bb75b0d5SLexi Winter PKGNAME "${_pkg}" \ 201*bb75b0d5SLexi Winter PKGGENNAME "${WORLDPACKAGE}" \ 202*bb75b0d5SLexi Winter SRCDIR "${.CURDIR}" \ 203*bb75b0d5SLexi Winter "${.ALLSRC:M*.ucl.in}" ${.TARGET} 204*bb75b0d5SLexi Winter 205*bb75b0d5SLexi Winter. endfor # _pkg in ${_ALLPACKAGES} 206*bb75b0d5SLexi Winter.endif # defined(WORLDPACKAGE) 207*bb75b0d5SLexi Winter 208*bb75b0d5SLexi Winter# Stage the packages from objdir into repodir. 209*bb75b0d5SLexi Winter 210*bb75b0d5SLexi Winterstagepackages: .PHONY 211*bb75b0d5SLexi Winter mkdir -p ${_STAGEDIR} 212*bb75b0d5SLexi Winter cp ${_ALLPACKAGES:S/^/${PKG_NAME_PREFIX}-/:S/$/-${PKG_VERSION}.pkg/} \ 213*bb75b0d5SLexi Winter ${_STAGEDIR} 214*bb75b0d5SLexi Winter 215*bb75b0d5SLexi Winter.SUFFIXES: .plist .ucl .pkg 216*bb75b0d5SLexi Winter.PATH: ${_PKG_WORLDSTAGE} 217*bb75b0d5SLexi Winter 218*bb75b0d5SLexi Winter.include <bsd.obj.mk> 219