1PORTNAME=	ghc
2PORTVERSION=	${GHC_VERSION}
3PORTREVISION?=	0
4CATEGORIES=	lang haskell
5MASTER_SITES=	https://www.haskell.org/ghc/dist/${PORTVERSION}/:source \
6		FREEBSD_LOCAL/arrowd/:boot
7DISTFILES=	ghc-${PORTVERSION}-src${EXTRACT_SUFX}:source
8
9MAINTAINER=	ports@MidnightBSD.org
10COMMENT=	Compiler for the functional language Haskell
11WWW=		https://www.haskell.org/ghc/
12
13LICENSE=	bsd3
14LICENSE_FILE=	${WRKSRC}/LICENSE
15
16BROKEN_MidnightBSD_3.2=	Requires 4.0 or higher
17BROKEN_MidnightBSD_3.2.1=	Requires 4.0 or higher
18BROKEN_MidnightBSD_3.2.2=	Requires 4.0 or higher
19BROKEN_MidnightBSD_3.2.3=	Requires 4.0 or higher
20
21ONLY_FOR_ARCHS=		aarch64 amd64 i386
22
23BUILD_DEPENDS=		${LOCALBASE}/lib/libgmp.so:math/gmp
24
25USES=			autoreconf compiler:c11 gmake \
26			ncurses perl5 python:build shebangfix \
27			tar:xz
28
29GHC_ARCH=		${ARCH:S/amd64/x86_64/:C/armv.*/arm/}
30GNU_CONFIGURE=		yes
31CONFIGURE_ARGS+=	--docdir=${DOCSDIR}
32CONFIGURE_ENV=		ALEX=/usr/bin/true HAPPY=/usr/bin/true
33CONFIGURE_TARGET=	${GHC_ARCH}-portbld-freebsd
34INSTALL_TARGET=		install-strip
35USE_LOCALE=		en_US.UTF-8
36USE_PERL5=		build
37NO_CCACHE=		yes
38OPTIONS_SUB=		yes
39SHEBANG_FILES=		${BOOT_SCRIPT}
40
41OPTIONS_DEFINE?=	DYNAMIC GMP PROFILE DOCS PDFDOCS
42OPTIONS_DEFAULT=	DYNAMIC PROFILE GMP
43
44OPTIONS_GROUP=		BOOTSTRAP
45BOOTSTRAP_DESC=		Bootsrap using installed ghc
46OPTIONS_GROUP_BOOTSTRAP=BOOT
47
48BOOT_DESC=		Use installed GHC for bootstrapping
49DOCS_DESC=		Build and install HTML documentation
50PDFDOCS_DESC=		Build and install PDF documentation
51DYNAMIC_DESC=		Add support for dynamic linking
52GMP_DESC=		Use GNU Multi-precision Library from Ports
53PROFILE_DESC=		Add support for performance profiling
54
55BOOT_CONFIGURE_ENV=	GHC=${LOCALBASE}/bin/ghc
56BOOT_CONFIGURE_ENV_OFF=	GHC=${BOOT_GHC} LLC=llc${BOOT_LLVM_VERSION} OPT=opt${BOOT_LLVM_VERSION}
57
58DOCS_BUILD_DEPENDS=	sphinx-build:textproc/py-sphinx
59DOCS_VARS=		enable_docs=YES hadrian_docs_arg=--docs=no-sphinx-pdfs
60DOCS_VARS_OFF=		enable_docs=NO hadrian_docs_arg=--docs=none
61
62PDFDOCS_IMPLIES=	DOCS
63PDFDOCS_BUILD_DEPENDS=	xelatex:print/tex-xetex \
64			${LOCALBASE}/share/fonts/dejavu/DejaVuSans.ttf:x11-fonts/dejavu
65PDFDOCS_VARS=		hadrian_docs_arg=
66
67DYNAMIC_CONFIGURE_WITH=	system-libffi \
68			ffi-includes=${LOCALBASE}/include \
69			ffi-libraries=${LOCALBASE}/lib
70DYNAMIC_LIB_DEPENDS=	libffi.so:devel/libffi
71DYNAMIC_VARS=		enable_dynamic=YES hadrian_setting_dynamic=True
72DYNAMIC_VARS_OFF=	enable_dynamic=NO hadrian_setting_dynamic=False
73
74# do not replace this with GMP_CONFIGURE_WITH
75# it adds "--without-gmp-*" when the option is OFF, which results in "no" value
76# to be used as directory name
77GMP_CONFIGURE_ON=	--with-gmp-includes=${LOCALBASE}/include \
78			--with-gmp-libraries=${LOCALBASE}/lib
79GMP_LIB_DEPENDS=	libgmp.so:math/gmp
80GMP_VARS_OFF=		hadrian_gmp_arg=--bignum=native
81
82PROFILE_VARS=		enable_profile=YES hadrian_setting_profile=True
83PROFILE_VARS_OFF=	enable_profile=NO hadrian_setting_profile=False
84
85GHC_VERSION?=		9.8.4
86LLVM_VERSION?=		15
87BOOT_GHC_VERSION?=	9.6.7
88# LLVM version that bootstrap compiler uses
89BOOT_LLVM_VERSION?=	12
90
91BASE_PACKAGES?=		Cabal-3.10.3.0 array-0.5.8.0 base-4.19.2.0 binary-0.8.9.1 \
92			bytestring-0.12.1.0 containers-0.6.8 deepseq-1.5.1.0 \
93			directory-1.3.8.5 exceptions-0.10.7 filepath-1.4.301.0 \
94			ghc-${GHC_VERSION} ghc-bignum-1.3 ghc-compact-0.1.0.0 \
95			ghc-prim-0.11.0 haskeline-0.8.2.1 hpc-0.7.0.0 \
96			integer-gmp-1.1 mtl-2.3.1 parsec-3.1.17.0 pretty-1.1.3.6 \
97			process-1.6.25.0 stm-2.5.3.1 semaphore-compat-1.0.0 \
98			template-haskell-2.21.0.0 terminfo-0.4.1.6 text-2.1.1 \
99			time-1.12.2 transformers-0.6.1.0 unix-2.8.6.0 \
100			xhtml-3000.2.2.1
101
102.for pkg in ${BASE_PACKAGES}
103PLIST_SUB+=	${pkg:C/-([0-9.])+//:tu}_VERSION=${pkg:C/^([^\.]*-)+//}
104.endfor
105
106BUILD_MK=		DYNAMIC_GHC_PROGRAMS=${ENABLE_DYNAMIC} \
107			BUILD_PROF_LIBS=${ENABLE_PROFILE} \
108			HADDOCK_DOCS=YES \
109			BUILD_SPHINX_HTML=${ENABLE_DOCS} \
110			BUILD_SPHINX_PDF=NO \
111			SRC_HC_OPTS+="-I${NCURSESINC} -L${NCURSESLIB} -I${LOCALBASE}/include -L${LOCALBASE}/lib" \
112			SRC_CC_OPTS+="${CFLAGS}" \
113			EXTRA_HSC2HS_OPTS+="-I${LOCALBASE}/include --lflag=-L${LOCALBASE}/lib" \
114			EXTRA_LD_OPTS+="-L${LOCALBASE}/lib" \
115			libraries/terminfo_CONFIGURE_OPTS+="--configure-option=--with-curses-libraries=${NCURSESLIB}" \
116			${SLAVE_BUILD_MK} \
117			V=0
118
119.include <bsd.port.pre.mk>
120
121.if ${GHC_VERSION:C/\..*//g} >= 9 && ${ARCH} != i386
122# hadrian build on i386 fails due to https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=269570
123# relocation R_386_TLS_LE cannot be used with -shared
124USE_HADRIAN=		yes
125.endif
126
127.if ${GHC_VERSION:C/\..*//g} >= 9 && ${GHC_VERSION:C/[^\.]*\.//:C/\..*//g} >= 4
128BOOT_SCRIPT=	./boot.source
129IGNORE_i386=	requires Hadrian build which doesn't work on i386
130.else
131BOOT_SCRIPT=	./boot
132.endif
133
134.if ${SLAVE_PORT} != "yes"
135PORTDOCS=		*
136HADRIAN_PLAN=		${PATCHDIR}/plan-bootstrap-${BOOT_GHC_VERSION:C/\./_/g}.json
137.else
138HADRIAN_DOCS_ARG=	--docs=none
139HADRIAN_PLAN=		${MASTERDIR}/files/plan-bootstrap-${BOOT_GHC_VERSION:C/\./_/g}.json
140PLIST_SUB+=		GMP=
141.endif
142
143.ifdef USE_HADRIAN
144LIB_DEPENDS+=		libffi.so:devel/libffi
145.undef DYNAMIC_CONFIGURE_WITH
146CONFIGURE_ARGS+=	--with-system-libffi --with-ffi-includes=${LOCALBASE}/include --with-ffi-libraries=${LOCALBASE}/lib
147CONFIGURE_ENV+=		CC=${CC} CXX=${CXX}
148SHEBANG_FILES+=		hadrian/bootstrap/bootstrap.py
149HADRIAN_CMD=		${WRKSRC}/hadrian/bootstrap/_build/bin/hadrian ${HADRIAN_DOCS_ARG} ${HADRIAN_GMP_ARG}
150DO_MAKE_BUILD=		${SETENVI} ${WRK_ENV} ${HADRIAN_CMD} ${_MAKE_JOBS} --flavour=ports
151ALL_TARGET=		binary-dist-dir
152INSTALL_WRKSRC=		${WRKSRC}/_build/bindist/ghc-${GHC_VERSION}-${CONFIGURE_TARGET}
153INSTALL_TARGET=		install
154PLIST?=			${.CURDIR}/pkg-plist.hadrian
155
156.  if (empty(PORT_OPTIONS:MDYNAMIC) || empty(PORT_OPTIONS:MPROFILE))
157IGNORE=			Building with Hadrian requires both DYNAMIC and PROFILE for now
158.  endif
159.endif
160
161CONFIGURE_TARGET=	${GHC_ARCH}-portbld-freebsd
162BOOT_DIR=		${WRKDIR}/ghc-${BOOT_GHC_VERSION}-boot
163BOOT_INSTALL_DIR=	${WRKDIR}/ghc-boot-install
164BOOT_GHC=		${BOOT_INSTALL_DIR}/bin/ghc-${BOOT_GHC_VERSION}
165
166PLIST_SUB+=		GHC_ARCH=${GHC_ARCH}
167
168.if ${BOOT_GHC_VERSION:C/\..*//g} >= 9
169BOOT_DIR=		${WRKDIR}/ghc-${BOOT_GHC_VERSION}-${CONFIGURE_TARGET}
170.endif
171
172# this is hacky but 92 is special as it is compiled with autotools on i386 and with Hadrian elsewhere
173.if ${SLAVE_PORT} == "yes" && ${PKGNAMESUFFIX} == "92"
174.  ifdef USE_HADRIAN
175PLIST=			${.CURDIR}/../ghc92/pkg-plist.hadrian
176.  else
177PLIST=			${.CURDIR}/../ghc92/pkg-plist
178.  endif
179.endif
180
181.if empty(PORT_OPTIONS:MBOOT)
182DISTFILES+=		ghc-${BOOT_GHC_VERSION}-boot-${ARCH}-freebsd${EXTRACT_SUFX}:boot
183.endif # MBOOT
184
185.if !defined(IGNORE_MISSING_HADRIAN) && defined(USE_HADRIAN)
186DISTFILES+=		hadrian-${GHC_VERSION}-boot.tar.gz:boot
187.endif
188
189.if ${ARCH} == aarch64 || ${ARCH:Marmv*}
190# ghc-8.10.x on arm requires devel/llvm10
191# CONFIGURE_TARGET must to be the same as the llvm triple
192CONFIGURE_TARGET=	${ARCH}-unknown-freebsd${"${ARCH:Maarch64}" != "":?:-gnueabihf}
193CONFIGURE_ARGS+=	--host=${CONFIGURE_TARGET}
194BUILD_DEPENDS+=		llc${LLVM_VERSION}:devel/llvm${LLVM_VERSION}
195RUN_DEPENDS+=		llc${LLVM_VERSION}:devel/llvm${LLVM_VERSION}
196
197# When GHC being compiled and GHC used for bootstrapping support different
198# LLVM versions, we have to pull in both. Luckily, this is relatively rare.
199.  if ${BOOT_LLVM_VERSION} != ${LLVM_VERSION}
200BUILD_DEPENDS+=		llc${BOOT_LLVM_VERSION}:devel/llvm${BOOT_LLVM_VERSION}
201.  endif
202.endif
203
204post-patch:
205#	Generate the build.mk file
206	${RM} -f ${WRKSRC}/mk/build.mk
207.for line in ${BUILD_MK}
208	${ECHO_CMD} ${line} >> ${WRKSRC}/mk/build.mk
209.endfor
210.ifdef USE_HADRIAN
211	${SED} -e 's|%%DYNAMIC%%|${HADRIAN_SETTING_DYNAMIC}|' \
212		-e 's|%%PROFILE%%|${HADRIAN_SETTING_PROFILE}|' \
213		${PATCHDIR}/UserSettings.hs > ${WRKSRC}/hadrian/src/UserSettings.hs
214.endif
215
216pre-configure:
217	# Call the bootstrap script
218	cd ${WRKSRC}/ && ${BOOT_SCRIPT}
219# If we are using bootstrap compiler, configure and install it into ${BOOT_DIR}
220.if empty(PORT_OPTIONS:MBOOT)
221	cd ${BOOT_DIR} && ${CONFIGURE_ENV} ${CONFIGURE_ENV_BOOTSTRAP} ${CONFIGURE_CMD} --prefix=${BOOT_INSTALL_DIR} --build=${CONFIGURE_TARGET} --host=${CONFIGURE_TARGET} --target=${CONFIGURE_TARGET}
222	cd ${BOOT_DIR} && PACKAGES='' ${MAKE_CMD} install
223.endif
224.ifdef USE_HADRIAN
225# Compile Hadrian
226	cd ${WRKSRC}/hadrian/bootstrap && \
227		./bootstrap.py -w ${BOOT_GHC} -s ${DISTDIR}/hadrian-${GHC_VERSION}-boot.tar.gz
228.endif
229
230.ifdef USE_HADRIAN
231pre-install:
232	cd ${INSTALL_WRKSRC} && ${CONFIGURE_CMD} ${CONFIGURE_ENV} --prefix=${PREFIX}
233.endif
234
235post-install:
236.ifdef USE_HADRIAN
237# Hadrian doesn't have --docdir
238	${MV} ${DOCSDIR}-${GHC_VERSION} ${DOCSDIR}
239# These includes are duplicated in lib/ghc-X.Y.Z/lib/<triple>/rts-X.Y.Z/include
240	${RM} -r ${PREFIX}/include/*
241.endif
242	${FIND} ${DOCSDIR} -name .buildinfo -delete
243# For some reason, INSTALL_TARGET=install-strip doesn't cause libraries to be stripped
244# Run strip on them manually
245	${FIND} ${PREFIX}/lib/ghc-${GHC_VERSION} -type f -perm +111 -exec ${STRIP_CMD} {} +
246	${FIND} ${PREFIX}/lib/ghc-${GHC_VERSION} -name '*.so' -exec ${STRIP_CMD} {} +
247	${RM} ${PREFIX}/bin/haddock
248.if ${SLAVE_PORT} == "yes"
249.  ifndef USE_HADRIAN
250	${MV} ${PREFIX}/bin/hsc2hs ${PREFIX}/bin/hsc2hs-ghc-${GHC_VERSION}
251.  endif
252	${FIND} ${PREFIX}/bin -not -type d -not -regex '.*-${GHC_VERSION}' -delete
253	${RM} -r ${PREFIX}/lib/ghc-${GHC_VERSION}/html
254	${RM} -r ${PREFIX}/lib/ghc-${GHC_VERSION}/latex
255.endif
256
257post-install-DOCS-off:
258# Docs for Haskell libraries are generated by Haddock, not sphinx, so we have
259# to pass WITH_HADDOCK=no to the build.mk to skip their generation.
260# However, we don't want to do that because this would cause Haddock itself not
261# to be built.
262	${RM} -r ${DOCSDIR}/html
263
264.if exists(${BOOT_INSTALL_DIR}/bin/runhaskell)
265RUNHASKELL?=	${BOOT_INSTALL_DIR}/bin/runhaskell
266.else
267RUNHASKELL?=	${LOCALBASE}/bin/runhaskell
268.endif
269
270# Create a bootstrap compiler tar ball: run this in an interactive poudriere jail
271# Set all OPTIONS to OFF when generating bootstraps
272.PHONY: create-bootstrap
273create-bootstrap:
274.ifndef USE_HADRIAN
275	cd ${WRKSRC} \
276		&& ${ECHO_CMD} "BIN_DIST_NAME=ghc-${GHC_VERSION}-boot" >> mk/build.mk \
277		&& ${ECHO_CMD} "BIN_DIST_TAR=ghc-${GHC_VERSION}-boot.tar" >> mk/build.mk \
278		&& ${ECHO_CMD} "HADDOCK_DOCS=NO" >> mk/build.mk \
279		&& ${SETENVI} ${WRK_ENV} ${GMAKE} binary-dist TAR_COMP=xz \
280		&& ${MV} ${WRKSRC}/ghc-${GHC_VERSION}-boot-${GHC_ARCH}-portbld-freebsd.tar.xz /tmp/ghc-${GHC_VERSION}-boot-${ARCH}-freebsd.tar.xz
281.else
282	cd ${WRKSRC} \
283		&& ${HADRIAN_CMD} binary-dist-xz \
284		&& ${MV} ${WRKSRC}/_build/bindist/ghc-${GHC_VERSION}-${CONFIGURE_TARGET}.tar.xz /tmp/ghc-${GHC_VERSION}-boot-${ARCH}-freebsd.tar.xz
285.endif
286
287	@cd /tmp \
288		&& sha256 ghc-${GHC_VERSION}-boot-${ARCH}-freebsd.tar.xz \
289		&& ${ECHO_CMD} -n "SIZE (ghc-${GHC_VERSION}-boot-${ARCH}-freebsd.tar.xz) = " \
290		&& ${STAT} -f %z ghc-${GHC_VERSION}-boot-${ARCH}-freebsd.tar.xz
291
292# Much like create-bootstrap, just different naming and output format
293# Set DYNAMIC, GMP and PROFILE to ON, and DOCS to OFF when generating Stack bindist
294.PHONY: create-stack-bindist
295create-stack-bindist:
296.ifndef USE_HADRIAN
297	cd ${WRKSRC} \
298		&& ${SETENVI} ${WRK_ENV} ${GMAKE} binary-dist TAR_COMP=xz \
299		&& ${MV} ${WRKSRC}/ghc-${GHC_VERSION}-${GHC_ARCH}-portbld-freebsd.tar.xz /tmp/
300.else
301	cd ${WRKSRC} \
302		&& ${HADRIAN_CMD} binary-dist-xz \
303		&& ${MV} ${WRKSRC}/_build/bindist/ghc-${GHC_VERSION}-${GHC_ARCH}-portbld-freebsd.tar.xz /tmp/
304.endif
305
306	cd /tmp \
307		&& ${ECHO_CMD} "${GHC_VERSION}:" \
308		&& ${ECHO_CMD} "url: \"http://distcache.FreeBSD.org/local-distfiles/arrowd/stack-bindists/ghc-${GHC_VERSION}-${GHC_ARCH}-portbld-freebsd.tar.xz\"" \
309		&& ${ECHO_CMD} -n "content-length: " \
310		&& ${STAT} -f %z ghc-${GHC_VERSION}-${GHC_ARCH}-portbld-freebsd.tar.xz \
311		&& ${ECHO_CMD} -n "sha1: " \
312		&& sha1 -q ghc-${GHC_VERSION}-${GHC_ARCH}-portbld-freebsd.tar.xz \
313		&& ${ECHO_CMD} -n "sha256: " \
314		&& sha256 -q ghc-${GHC_VERSION}-${GHC_ARCH}-portbld-freebsd.tar.xz
315
316.PHONY: create-hadrian-bootstrap
317create-hadrian-bootstrap:
318.if !empty(PORT_OPTIONS:MBOOT)
319	@${ECHO_CMD} "Generating Hadrian bootstrap without bootstrap GHC isn't supported"
320	${FALSE}
321.endif
322	${MAKE} -C ${.CURDIR} patch build-depends USE_PACKAGE_DEPENDS_ONLY=yes IGNORE_MISSING_HADRIAN=yes
323# We always would need to create our own plan.json file and put it into PATCHDIR:
324# Predefined plans use integer-gmp, while we build bootstraps with integer-simple
325# Predefined plans aren't pretty-printed, so we can't easily patch them
326	cd ${WRKSRC}/hadrian/bootstrap && \
327		./bootstrap.py -w ${BOOT_GHC} --deps ${HADRIAN_PLAN} fetch -o /tmp/hadrian-${GHC_VERSION}-boot
328
329	@cd /tmp \
330		&& sha256 hadrian-${GHC_VERSION}-boot.tar.gz \
331		&& ${ECHO_CMD} -n "SIZE (hadrian-${GHC_VERSION}-boot.tar.gz) = " \
332		&& ${STAT} -f %z hadrian-${GHC_VERSION}-boot.tar.gz
333	@${ECHO_CMD}
334	@${ECHO_CMD} "Remember to check that hadrian bootstrap builds fine by running \"make check-hadrian-bootstrap\""
335
336.PHONY: check-hadrian-bootstrap
337check-hadrian-bootstrap:
338.if !empty(PORT_OPTIONS:MBOOT)
339	@${ECHO_CMD} "Generating Hadrian bootstrap without bootstrap GHC isn't supported"
340	${FALSE}
341.endif
342# Compile Hadrian
343	cd ${WRKSRC}/hadrian/bootstrap && \
344		./bootstrap.py -w ${BOOT_GHC} -s /tmp/hadrian-${GHC_VERSION}-boot.tar.gz
345
346.include <bsd.port.post.mk>
347