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