# -*- mode: Makefile; -*-

######################################################################
## NOTE.  This file is not part of the standard ACL2 books build
## process; it is part of an experimental build system that is not yet
## intended, for example, to be capable of running the whole
## regression.  The ACL2 developers do not maintain this file.
##
## Please contact Jared Davis <jared@cs.utexas.edu> or Sol Swords
## <sswords@cs.utexas.edu> with any questions/comments.
######################################################################

# Copyright 2008 by Sol Swords and Jared Davis.
# Credit to Matt Kaufmann and J Strother Moore for code from Makefile-generic.

# This file can be included in a GNU makefile (with SHELL set to bash)
# to provide a rule for certifying ACL2 books.

SHELL := $(shell which bash)

COMPILE_FLG ?= t :ttags :all :skip-proofs-okp t
COMPILE_FLG_TWOPASS ?= t :ttagsx :all :ttags :all :skip-proofs-okp t :acl2x t
INHIBIT ?= (set-inhibit-output-lst (list (quote prove) (quote proof-tree) (quote warning) (quote observation) (quote event) (quote expansion)))
ACL2_BOOKS_DEBUG ?=

# Avoid loading customization file unless environment variable is already set.
export ACL2_CUSTOMIZATION ?= NONE

# Default ACL2 to whatever is in the path
ACL2 ?= acl2

define make_cert
	@TARGETEXT=$(1) ;\
	PASSES=$(2) ;\
	if [ $$PASSES == 2 ] ;\
	then \
	   FLAGS="$(COMPILE_FLG_TWOPASS)" ;\
	else \
	   FLAGS="$(COMPILE_FLG)" ;\
	fi ;\
	echo "Making $*.$$TARGETEXT on `date`" ;\
	DIR=`dirname $*` ;\
	FILE=`basename $*` ;\
        ACL2=`which $(ACL2) 2> /dev/null` ;\
	cd $$DIR ;\
	if [ -f $$FILE.image ] ; then \
	   IM=`cat $$FILE.image` ;\
	   if [ "$${IM}" != "" ] ; then \
	      ACL2=$${IM} ;\
	   fi ;\
	elif [ -f cert.image ] ; then \
	   IM=`cat cert.image` ;\
	   if [ "$${IM}" != "" ] ; then \
	      ACL2=$${IM} ;\
	   fi ;\
	fi ;\
	rm -f $$FILE.$$TARGETEXT ;\
	WORKXXXFILE=workxxx.$$FILE.$$TARGETEXT.$$RANDOM ;\
	echo '(acl2::value :q)' > $$WORKXXXFILE ;\
	echo '(in-package "ACL2")' >> $$WORKXXXFILE ;\
	echo '(acl2::lp)' >> $$WORKXXXFILE ;\
	if [ $$TARGETEXT == acl2x ] ;\
	  then echo '(set-write-acl2x t state)' >> $$WORKXXXFILE ;\
	fi ;\
	echo '$(INHIBIT)' >> $$WORKXXXFILE ;\
	if [ -f $$FILE.acl2 ] ;\
	then \
	  cat $$FILE.acl2 >> $$WORKXXXFILE ;\
	elif [ -f cert.acl2 ] ;\
	then \
	  cat cert.acl2 >> $$WORKXXXFILE ;\
	  echo "" >> $$WORKXXXFILE ;\
	  echo "(time$$ (certify-book \"$$FILE\" ? $$FLAGS))" \
	        >> $$WORKXXXFILE ;\
	else \
	  echo "" >> $$WORKXXXFILE ;\
	  echo "(time$$ (certify-book \"$$FILE\" ? $$FLAGS))" \
	        >> $$WORKXXXFILE ;\
	fi ;\
	echo "" >> $$WORKXXXFILE ;\
	if [ $$TARGETEXT != acl2x ] ;\
	then \
	    echo "(acl2::ld \"make_cert.lsp\" :dir :system)" >> $$WORKXXXFILE ;\
	    echo "(acl2::horrible-include-book-exit \"$$FILE\" acl2::state)" \
                 >> $$WORKXXXFILE ;\
	fi ;\
	if [ -n "$(ACL2_BOOKS_DEBUG)" ] ;\
	then \
	  echo "[make_cert]: certify book commands for $$FILE.$$TARGETEXT:" ;\
	  echo "" ;\
	  cat $$WORKXXXFILE ;\
	  echo "" ;\
	fi ;\
	if [ $$TARGETEXT == acl2x ] ;\
	then \
	  TIMEFILE=$$FILE.acl2x.time ;\
	  OUTFILE=$$FILE.acl2x.out ;\
	else \
	  TIMEFILE=$$FILE.time ;\
	  OUTFILE=$$FILE.out ;\
	fi ;\
	if [ "$$TIME_CERT" != "" ] ;\
	then \
	  (env time -o $$TIMEFILE $$ACL2 < $$WORKXXXFILE 2>&1) > $$OUTFILE ;\
	else \
	  ($$ACL2 < $$WORKXXXFILE 2>&1) > $$OUTFILE ;\
	fi ;\
        STATUS=$$? ;\
	rm -f $$WORKXXXFILE ;\
	if [[   ( $$TARGETEXT != acl2x && "$$STATUS" == "43" ) \
	     || ( $$TARGETEXT == acl2x && -e $$FILE.$$TARGETEXT ) ]] ; then \
	   ls -al $$FILE.$$TARGETEXT || echo "NFS problem for $$FILE.$$TARGETEXT?" ;\
	else \
	  if [[ $$TARGETEXT == acl2x ]] ;\
	    then TASKNAME="ACL2X GENERATION" ;\
	    else TASKNAME="CERTIFICATION" ;\
	  fi ;\
	  echo "**$$TASKNAME FAILED** for $$DIR/$$FILE.lisp" ;\
	  echo "" ;\
	  echo $$OUTFILE : ;\
          tail -300 $$OUTFILE | sed 's/^/   | /' ;\
	  echo "" ;\
	  echo "" ;\
	  if [ "$$ON_FAILURE_CMD" != "" ] ;\
	  then \
	     $$ON_FAILURE_CMD ;\
	  fi ;\
          echo "**CERTIFICATION FAILED** for $$DIR/$$FILE.lisp" ;\
          exit 1 ;\
        fi
endef

# Precedence: The rule for making %.cert from %.acl2x comes before the
# rule for making %.cert directly from %.lisp because we want it to be
# used when the acl2x file is available.  The double-colon means that
# the rule will only be considered if the %.acl2x prerequisite exists
# or is going to be made anyway.
%.cert :: %.acl2x
	$(call make_cert,cert,2)

%.cert : %.lisp
	$(call make_cert,cert,1)

%.acl2x : %.lisp
	$(call make_cert,acl2x,2)
