MicroHs-0.16.0.0: Makefile
# Define these 3 lines to use GMP for Integer.
#MHSGMPCCFLAGS=-DWANT_GMP=1
#MHSGMP=-ilib/gmp
#MCABALGMP=-fgmp
# AND, for MacOS with homebrew (after brew install gmp):
#MHSGMPCCLIBS= -L/opt/homebrew/lib -lgmp -I/opt/homebrew/include
# OR, for Ubuntu Linux (after apt-get install -y libgmp-dev):
#MHSGMPCCLIBS=-lgmp
#
# installation prefix
PREFIX=/usr/local
# Unix-like system, 32/64 bit words
CONF=unix
#
# Using GCC enables global register variables on ARM64, which gives a 5-10% speedup.
#CC=gcc-14
RTS=src/runtime
RTSINC=-I$(RTS) -I$(RTS)/$(CONF)
MAINC= $(RTS)/main.c
#
CCWARNS= -Wall
CCOPTS= -O3
# CCOPTS+= -flto # useful, but generates harmless warning with gcc
# CCOPTS+= -march=native # useful on x86, but breaks on some platforms
CCLIBS= -lm $(MHSGMPCCLIBS)
CCSANITIZE= -fsanitize=undefined -fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract
CCEVAL= $(CC) $(CCWARNS) $(CCOPTS) $(MHSGMPCCFLAGS) $(RTSINC) $(MAINC) $(RTS)/eval.c
#
GHC= ghc
GHCINCS= -ighc -isrc
GHCWARNS= -Wall -Wno-unrecognised-warning-flags -Wno-x-partial -Wno-deprecations
GHCOPTS= -O
GHCEXTS= -XScopedTypeVariables -XTypeSynonymInstances -XMultiParamTypeClasses -XFlexibleInstances
GHCPKGS= -package mtl -package pretty -package haskeline -package process -package time -package ghc-prim -package containers -package deepseq -package directory -package text -package bytestring -package filepath -package array
GHCTOOL= # -F -pgmF Tools/convertX.sh
GHCOUTDIR= ghc-out
GHCOUT= -outputdir $(GHCOUTDIR)
GHCPROF= # -prof -fprof-late #-prof -fprof-auto
GHCFLAGS= $(GHCEXTS) $(GHCINCS) $(GHCWARNS) $(GHCOPTS) $(GHCTOOL) $(GHCPKGS) $(GHCOUT) $(GHCPROF) -main-is MicroHs.Main
#
# Hugs
HUGS= runhugs
FFIHUGS= ffihugs
HUGSINCS= '+Phugs:mhs:src:{Hugs}/packages/*:hugs/obj' -98 +o +w
#
NODE=node
#NODEFLAGS=--stack_size=8192
#
MHSINCNP= -i $(MHSGMP) -imhs -isrc -ilib
MHSINC=$(MHSINCNP)
MAINMODULE=MicroHs.Main
#
.PHONY: clean bootstrap install ghcgen newmhs newmhsz cachelib timecompile exampletest cachetest runtest runtestmhs everytest everytestmhs nfibtest info install minstall installmsg
all: bin/mhs bin/cpphs bin/mcabal
newmhs: ghcgen mhs.conf
$(CCEVAL) generated/mhs.c $(CCLIBS) -o bin/mhs
$(CC) $(CCWARNS) $(MHSGMPCCFLAGS) -g $(RTSINC) $(RTS)/eval.c $(MAINC) generated/mhs.c $(CCLIBS) -o bin/mhsgdb
newmhsz: newmhs
@rm -f generated/mhs.c
$(MAKE) generated/mhs.c
$(CCEVAL) generated/mhs.c $(CCLIBS) -o bin/mhs
sanitizemhs: ghcgen mhs.conf
$(CCEVAL) $(CCSANITIZE) generated/mhs.c $(CCLIBS) -o bin/mhssane
# Compile mhs from distribution, with C compiler
bin/mhs: $(RTS)/*.c $(RTS)/*.h $(RTS)/*/*.h mhs.conf #generated/mhs.c
@mkdir -p bin
$(CCEVAL) generated/mhs.c $(CCLIBS) -o bin/mhs
# Compile cpphs from distribution, with C compiler
bin/cpphs: $(RTS)/*.c $(RTS)/*.h $(RTS)/*/*.h #generated/cpphs.c
@mkdir -p bin
$(CCEVAL) generated/cpphs.c $(CCLIBS) -o bin/cpphs
# Compile mcabal from distribution, with C compiler
bin/mcabal: $(RTS)/*.c $(RTS)/*.h $(RTS)/*/*.h #generated/mcabal.c
@mkdir -p bin
$(CCEVAL) generated/mcabal.c $(CCLIBS) -o bin/mcabal
# Compile cpphs from distribution, with C compiler
bin/install: $(RTS)/*.c $(RTS)/*.h $(RTS)/*/*.h #generated/install.c
@mkdir -p bin
$(CCEVAL) generated/install.c $(CCLIBS) -o bin/install
# Compile combinator evaluator
bin/mhseval: $(RTS)/*.c $(RTS)/*.h $(RTS)/*/*.h
@mkdir -p bin
$(CCEVAL) $(RTS)/comb.c $(CCLIBS) -o bin/mhseval
size bin/mhseval
bin/mhsevalgdb: $(RTS)/*.c $(RTS)/*/*.h
@mkdir -p bin
$(CC) $(CCWARNS) $(MHSGMPCCFLAGS) $(RTSINC) -g $(RTS)/eval.c $(RTS)/comb.c $(MAINC) $(CCLIBS) -o bin/mhsevalgdb
bin/mhsevalsane: $(RTS)/*.c $(RTS)/*/*.h
@mkdir -p bin
$(CCEVAL) $(CCSANITIZE) $(RTSINC) $(RTS)/comb.c $(CCLIBS) -o bin/mhsevalsane
#######################
# mhseval, compiled with emscripten. Use in the browser!
#EMCC=emcc
#EMCCFLAGS=-O3 -sEXPORTED_RUNTIME_METHODS=stringToNewUTF8 -sALLOW_MEMORY_GROWTH -sTOTAL_STACK=5MB -sNODERAWFS -sSINGLE_FILE -DUSE_SYSTEM_RAW -sEXIT_RUNTIME
EMCCOPTS= -O3 -sEXPORTED_FUNCTIONS=_apply_sp,_main -sEXPORTED_RUNTIME_METHODS=stringToNewUTF8 -sALLOW_MEMORY_GROWTH -sTOTAL_STACK=5MB -sSINGLE_FILE -DUSE_SYSTEM_RAW -Wno-address-of-packed-member
EMCCLIBS= -lm
EMCCEVAL= emcc $(EMCCOPTS) $(RTSINC) $(MAINC) $(RTS)/eval.c
generated/mhseval.js: $(RTS)/*.c $(RTS)/*.h $(RTS)/*/*.h
@mkdir -p bin
$(EMCCEVAL) $(RTS)/comb.c $(EMCCLIBS) -o generated/mhseval.js
bin/mhs.js: mhs.js
@mkdir -p bin
echo '#! /usr/bin/env node' > bin/mhs.js
cat mhs.js >> bin/mhs.js
rm mhs.js
chmod +x bin/mhs.js
#######################
# Compile mhs with ghc
bin/gmhs: src/*/*.hs ghc/*.hs ghc/*/*.hs ghc/*/*/*.hs
@mkdir -p bin
$(GHC) $(GHCFLAGS) $(RTSINC) $(MAINMODULE) -o bin/gmhs
# Compile mhs with ghc, with code coverage
bin/cmhs: src/*/*.hs ghc/*.hs ghc/*/*.hs
@mkdir -p bin
$(GHC) $(GHCFLAGS) $(RTSINC) -fhpc $(MAINMODULE) -o bin/cmhs
# Generate distribution C file
generated/mhs.c: bin/mhs src/*/*.hs
@mkdir -p generated
bin/mhs -z $(MHSINC) $(MAINMODULE) -ogenerated/mhs.c
generated/install.c: bin/mhs Tools/Install.hs
@mkdir -p generated
bin/mhs -z $(MHSINC) -iTools Install -ogenerated/install.c
ghcgen: bin/gmhs src/*/*.hs lib/*.hs lib/*/*.hs lib/*/*/*.hs
bin/gmhs $(MHSINC) $(MAINMODULE) -ogenerated/mhs.c
# This doesn't keep MicroCabal updated. I'm not sure how to do it
#generated/mcabal.c: MicroCabal/.git
# bin/mhs -z -iMicroCabal/src -ilib -ogenerated/mcabal.c MicroCabal.Main
#
#MicroCabal/.git:
# git submodule update --init --depth 1 MicroCabal
generated/mcabal.c:
bin/mhs -z -i../MicroCabal/src -ilib -ogenerated/mcabal.c MicroCabal.Main
# Flags to read local file system, generate a single .js file, and to avoid ioctl()
mhs.js: src/*/*.hs $(RTS)/*.h $(RTS)/*/*.h mhs.conf
bin/mhs $(MHSINC) -temscripten $(MAINMODULE) -o mhs.js
# Make sure boottrapping works
bootstrap: bin/mhs-stage2
@echo "*** copy stage2 to bin/mhs"
cp bin/mhs-stage2 bin/mhs
cp generated/mhs-stage2.c generated/mhs.c
# Build stage1 compiler with existing compiler
bin/mhs-stage1: bin/mhs src/*/*.hs
@mkdir -p generated
@echo "*** Build stage1 compiler, using bin/mhs"
bin/mhs -z $(MHSINC) $(MAINMODULE) -ogenerated/mhs-stage1.c
$(CCEVAL) generated/mhs-stage1.c $(CCLIBS) -o bin/mhs-stage1
# Build stage2 compiler with stage1 compiler, and compare
bin/mhs-stage2: bin/mhs-stage1 src/*/*.hs
@mkdir -p generated
@echo "*** Build stage2 compiler, with stage1 compiler"
bin/mhs-stage1 -z $(MHSINC) $(MAINMODULE) -ogenerated/mhs-stage2.c
cmp generated/mhs-stage1.c generated/mhs-stage2.c
@echo "*** stage2 equal to stage1"
$(CCEVAL) generated/mhs-stage2.c $(CCLIBS) -o bin/mhs-stage2
# Fetch cpphs submodule
cpphssrc/malcolm-wallace-universe/.git:
git submodule update --init --depth 1 cpphssrc/malcolm-wallace-universe
# Use this cpphs for bootstrapping
USECPPHS=bin/cpphs
bootstrapcpphs: bin/mhs cpphssrc/malcolm-wallace-universe/.git
MHSCPPHS=$(USECPPHS) bin/mhs -z -XCPP '-DMIN_VERSION_base(x,y,z)=((x)<4||(x)==4&&(y)<19||(x)==4&&(y)==19&&(z)<=1)' -icpphscompat -icpphssrc/malcolm-wallace-universe/polyparse-1.12/src -icpphssrc/malcolm-wallace-universe/cpphs-1.20.9 cpphssrc/malcolm-wallace-universe/cpphs-1.20.9/cpphs.hs -ogenerated/cpphs.c
mhs.conf: mhs.conf.in
sed -e "s,%GMPFLAGS,$(MHSGMPCCFLAGS)," -e "s,%GMPLIBS,$(MHSGMPCCLIBS)," mhs.conf.in > mhs.conf
# Run test examples with ghc-compiled compiler
runtest: bin/mhseval bin/gmhs tests/*.hs
cd tests; $(MAKE) alltest
# Run test examples with mhs-compiled compiler
runtestmhs: bin/mhseval bin/mhs
cd tests; $(MAKE) MHS=../bin/mhs cache; $(MAKE) MHS="../bin/mhs +RTS -H4M -RTS -CR" alltest interactivetest
runitestmhs: bin/mhseval bin/mhs
cd tests; $(MAKE) MHS=../bin/mhs cache; $(MAKE) MHS="../bin/mhs +RTS -H4M -RTS -CR" interactivetest
# Run test examples with sanitized mhs-compiled compiler
runtestsan: bin/mhsevalsane sanitizemhs
cd tests; $(MAKE) MHS="../bin/mhssane +RTS -H4M -RTS -CW" cache
cd tests; $(MAKE) MHS="../bin/mhssane +RTS -H4M -RTS -CR" EVAL="../bin/mhsevalsane +RTS -H1M -RTS" info test errtest
runtestgsan: bin/mhsevalsane bin/gmhs
cd tests; $(MAKE) EVAL="../bin/mhsevalsane +RTS -H1M -RTS" info test errtest
# Run test examples going via JavaScript
runtestemscripten: bin/mhseval bin/mhs bin/cpphs
cd tests; $(MAKE) MHS=../bin/mhs cache; MHSDIR=.. $(MAKE) MHSTARGET="-temscripten" MHS="../bin/mhs -CR -oout.js" EVAL="$(NODE) $(NODEFLAGS) out.js" info test errtest testpipenonblockioem
runtestinstemscripten:
cd tests; $(MAKE) MHSTARGET="-temscripten" MHS="mhs.js -oout.js" EVAL="$(NODE) $(NODEFLAGS) out.js" test
# Run test examples going with tcc
runtesttcc: bin/mhseval bin/mhs bin/cpphs
cd tests; MHSDIR=.. $(MAKE) MHSTARGET="-ttcc" MHSOUTPUT="-oa.out" EVAL="./a.out" info test errtest
# Compress the binary (broken on MacOS)
bin/umhs: bin/mhs
rm -f bin/umhs
upx -q -q -obin/umhs bin/mhs
#
timecompile: bin/mhs
@date
@git rev-parse HEAD
time bin/mhs +RTS -v -RTS $(MHSINC) $(MAINMODULE)
#
timecachecompile: bin/mhs
@-rm -f .mhscache
time bin/mhs +RTS -v -RTS -CW AllOfLib
time bin/mhs +RTS -v -RTS -CR -s $(MHSINC) $(MAINMODULE)
#
timemhscompile:
@date
@git rev-parse HEAD
time mhs +RTS -v -RTS -z -imhs -isrc $(MAINMODULE)
timegmhscompile:
@date
@git rev-parse HEAD
time bin/gmhs -imhs -isrc $(MAINMODULE)
timeghccompile:
@date
@git rev-parse HEAD
time $(GHC) -fforce-recomp $(GHCFLAGS) -O0 $(MAINMODULE) -o bin/gmhs
#
cachelib:
@-rm -f .mhscache
bin/mhs -CW AllOfLib
#
clean:
rm -rf src/*/*.hi src/*/*.o *.comb *.js *.tmp *~ bin/* a.out $(GHCOUTDIR) Tools/*.o Tools/*.hi dist-newstyle generated/*-stage* .mhscache .mhscache dist-mcabal Interactive.hs .mhsi lib/*.pkg lib/dist-mcabal mhs.conf
cd tests; $(MAKE) clean
-cabal clean
-git submodule deinit cpphssrc/malcolm-wallace-universe
-git submodule deinit MicroCabal
oldinstall:
mkdir -p $(PREFIX)/bin
cp bin/mhs $(PREFIX)/bin
-cp bin/cpphs $(PREFIX)/bin
mkdir -p $(PREFIX)/lib/mhs/$(RTS)
cp -r lib $(PREFIX)/lib/mhs
cp -r $(RTS)/* $(PREFIX)/lib/mhs/$(RTS)
cp mhs.conf $(PREFIX)/lib/mhs/mhs.conf
@echo "***"
@echo "*** Installation complete"
@echo "*** Set environment variable MHSDIR to $(PREFIX)/lib/mhs"
@echo "***"
everytest: newmhs bin/cpphs exampletest info runtest cachetest bootcombtest nfibtest
everytestmhs: bin/mhs bin/cpphs bin/mhseval exampletest info cachetest bootstrap runtestmhs nfibtest
bootcombtest: bin/gmhs bin/mhseval
bin/gmhs $(MHSINC) -ogmhs.comb $(MAINMODULE)
bin/mhseval +RTS -v -rgmhs.comb -RTS $(MHSINC) -omhs.comb $(MAINMODULE)
cmp gmhs.comb mhs.comb
exampletest: bin/mhs bin/mhseval Example.hs
bin/mhs -r Example
bin/mhs Example && bin/mhseval
bin/mhs Example -oEx && ./Ex && rm Ex
examplejs: bin/mhs Example.hs
bin/mhs -temscripten Example -oEx.js
$(NODE) $(NODEFLAGS) Ex.js
rm Ex.js
info: bin/mhs
bin/mhs -r -itests Info
cachetest: bin/mhs bin/cpphs bin/mhseval Example.hs
rm -f .mhscache
bin/mhs -CW AllOfLib
bin/mhs -CR Example && bin/mhseval
bin/mhs +RTS -v -RTS $(MHSINC) -CR $(MAINMODULE)
rm -f .mhscache
nfibtest: bin/mhs bin/mhseval
bin/mhs -itests Nfib && bin/mhseval
######
VERSION=0.16.0.0
HVERSION=0,16,0,0
MCABAL=$(HOME)/.mcabal
MCABALMHS=$(MCABAL)/mhs-$(VERSION)
MDATA=$(MCABALMHS)/packages/mhs-$(VERSION)/data
MRUNTIME=$(MDATA)/$(RTS)
MCABALBIN=$(MCABAL)/bin
BASE=base-$(VERSION)
$(MCABALBIN)/mhs: bin/mhs $(RTS)/*.[ch] mhs.conf machdep
@mkdir -p $(MCABALBIN)
bin/mhs -z $(MHSINCNP) $(MAINMODULE) -o$(MCABALBIN)/mhs
$(MCABALBIN)/cpphs: bin/cpphs
@mkdir -p $(MCABALBIN)
cp bin/cpphs $(MCABALBIN)
$(MCABALBIN)/mcabal: bin/mcabal
@mkdir -p $(MCABALBIN)
cp bin/mcabal $(MCABALBIN)
preparedist: newmhsz bootstrapcpphs
rm -f generated/mcabal.c generated/mhseval.js generated/base.pkg
$(MAKE) generated/mcabal.c
$(MAKE) generated/install.c
$(MAKE) generated/mhseval.js
$(MAKE) generated/base.pkg
generated/base.pkg: bin/mhs bin/mcabal
cd lib; PATH=../bin:"$$PATH" mcabal $(MCABALGMP) build
cp lib/dist-mcabal/base-$(VERSION).pkg generated/base.pkg
install: installmsg minstall
installmsg:
@echo '***************************************************'
@echo "* Installing MicroHs $(VERSION)"
@echo "* Binaries (in $(MCABALBIN)):"
@echo '* mhs - MicroHs compiler'
@echo '* cpphs - C preprocessor'
@echo '* mcabal - cabal for MicroHs'
@echo '* Libraries:'
@echo '* base (bytestring, deepseq, directory, hashable, text, stm)'
@echo '***************************************************'
@echo ''
minstall: bin/install
bin/install -i$(MCABAL) GMPFLAGS=$(MHSGMPCCFLAGS) GMPLIBS=$(MHSGMPCCLIBS)
oldminstall: bin/mhs bin/cpphs bin/mcabal machdep
@mkdir -p $(MCABALBIN)
@mkdir -p $(MRUNTIME)
cp bin/mhs bin/cpphs bin/mcabal $(MCABALBIN)
cp mhs.conf $(MDATA)
cp -r $(RTS)/* $(MRUNTIME)
@mkdir -p $(MCABALMHS)
bin/mhs -Q generated/base.pkg $(MCABALMHS)
@echo $$PATH | tr ':' '\012' | grep -q $(MCABALBIN) || echo '***' Add $(MCABALBIN) to the PATH
machdep:
$(CC) Tools/machdep.c -o machdep.exe && ./machdep.exe > $(RTS)/MachDeps.h && rm machdep.exe
# Install with recompiling
slowinstall: bin/cpphs bin/mcabal bin/mhs machdep
@mkdir -p $(MCABALBIN)
@mkdir -p $(MRUNTIME)
cp bin/cpphs bin/mcabal $(MCABALBIN)
cp mhs.conf $(MDATA)
cp -r $(RTS)/* $(MRUNTIME)
bin/mhs -z $(MHSINCNP) $(MAINMODULE) -o$(MCABALBIN)/mhs
cd lib; PATH=$(MCABALBIN):"$$PATH" mcabal $(MCABALGMP) install
@echo $$PATH | tr ':' '\012' | grep -q $(MCABALBIN) || echo '***' Add $(MCABALBIN) to the PATH
#####
# Profile Guided Optimization for LLVM on MacOS
# This gives about a 5% speedup on my M4 MacMini
llvmpgo:
rm -f *.profraw
$(CCEVAL) -fprofile-generate generated/mhs.c $(CCLIBS) -o $(MCABABIN)/mhs_gen
mhs_gen -imhs -isrc MicroHs.Main
xcrun llvm-profdata merge -output=code.profdata *.profraw
$(CCEVAL) -fprofile-use=code.profdata generated/mhs.c $(CCLIBS) -o $(MCABABIN)/mhs
#####
# Hugs
HUGS= runhugs
HUGSINCS= '+Phugs:src:{Hugs}/packages/*:hugs/obj' -98 +o +w -h100m
generated/hmhs.c:
@mkdir -p generated
$(HUGS) $(HUGSINCS) hugs/Main.hs $(MHSINC) $(MAINMODULE) -ogenerated/hmhs.c
bin/hmhs: generated/hmhs.c
@mkdir -p bin
$(CCEVAL) generated/hmhs.c $(CCLIBS) -o bin/hmhs