#; ACL2 Version 4.0 -- A Computational Logic for Applicative Common Lisp
#; Copyright (C) 2010  University of Texas at Austin

#; This version of ACL2 is a descendent of ACL2 Version 1.9, Copyright
#; (C) 1997 Computational Logic, Inc.  See the documentation topic NOTES-2-0.

#; This program is free software; you can redistribute it and/or modify
#; it under the terms of the GNU General Public License as published by
#; the Free Software Foundation; either version 2 of the License, or
#; (at your option) any later version.

#; This program is distributed in the hope that it will be useful,
#; but WITHOUT ANY WARRANTY; without even the implied warranty of
#; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#; GNU General Public License for more details.

#; You should have received a copy of the GNU General Public License
#; along with this program; if not, write to the Free Software
#; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

#; Written by:  Matt Kaufmann               and J Strother Moore
#; email:       Kaufmann@cs.utexas.edu      and Moore@cs.utexas.edu
#; Department of Computer Sciences
#; University of Texas at Austin
#; Austin, TX 78712-1188 U.S.A.

#; Adapted from makefiles for IHS and data-structures library, which were
#; created by Bishop Brock.

#; NOTE:  Target "all" causes a recursive invocation of make with ACL2 set to
#; its current value.  These recursive invocations of make thus have ACL2 set
#; on the command line, which overrides any values of ACL2 set in those files.
#; This should not cause any problems unless you try to do something fancy; see
#; the comment for example just above target .exercises.cert in
#; books/case-studies/ivy/ivy-v2/ivy-sources/Makefile from the ACL2
#; distribution.

# Success can be determined by checking for the absence of the following string
# in the log;  "**CERTIFICATION FAILED**".

# We could probably arrange for the make process to stop as soon as
# certification fails, if there is a need.  If we do that, we should also
# arrange that the -k (or --keep_going) flag, as specified by the GNU make
# manual, avoids such stopping.

#################### Editable variables ####################

# The default command below prints runtime statistics for the certification.
# We normally inhibit most output during certification to speed up the proofs.
# Edit as necessary.

# Check that this version of MAKE defines MAKEFILE_LIST
ifdef MAKEFILE_LIST

# Determine the location of this Makefile-generic.  NOTE: We have
# tried $(realpath $(dir ...)) and similarly for abspath, but they
# have returned the empty string, presumably an error.
BOOKS_DIR := $(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))

# and use that to determine the default location of ACL2.  To override,
# set the ACL2 variable on the command line or in the environment.
ACL2 ?= $(BOOKS_DIR)../saved_acl2

# Unless otherwise specified, use the books under this directory as
# the system books.  We set the flag ACL2_SYSTEM_BOOKS_DYNAMIC if any
# Makefile-generic sets ACL2_SYSTEM_BOOKS, so that recursive calls of
# make using Makefile-generic will re-set ACL2_SYSTEM_BOOKS.
# (With the more naive approach through Version_3.6.1, we had a
# failure with arithmetic-3 and top-level target
# chk-include-book-worlds (for "make" invoked in the directory above
# books/), apparently because Makefile-generic is invoked recursively
# on the subdirectories and we were using :dir ;system in our
# testing.)
ifndef ACL2_SYSTEM_BOOKS
	export ACL2_SYSTEM_BOOKS_DYNAMIC := true
endif
ifdef ACL2_SYSTEM_BOOKS_DYNAMIC
	export ACL2_SYSTEM_BOOKS := $(BOOKS_DIR)
endif
# Otherwise, specify ACL2= and ACL2_SYSTEM_BOOKS= oneself.

# End the ifdef of MAKEFILE_LIST.
endif

ACL2_BOOKS_MAKEFILE ?= Makefile

# Set the following variable to a non-empty string if you want debug information.
ACL2_BOOKS_DEBUG ?=

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

# Fix problem with sh on some Linux systems:
ifeq ($(OSTYPE),linux)
	SHELL = bash
endif
ifeq ($(OSTYPE),linux-gnu)
	SHELL = bash
endif

# Inhibit all output except the summary (which can be useful for tracking down problems).
# Set this to "" if you do want the output.

INHIBIT := (set-inhibit-output-lst (list (quote prove) (quote proof-tree) (quote warning) (quote observation) (quote event) (quote expansion)))

# Support for make dependencies:  should be a list of book names without
# the .lisp suffix.  Can be overridden on the command line or in a file
# that includes this file.

BOOKS := $(patsubst %.lisp, %, $(wildcard *.lisp))

#################### END of editable variables ####################

# We should really check that following is not empty.  It is the same as
# books, but with .cert suffixes.  This variable should not be overridden;
# it is computed as needed from BOOKS.  Note the use of '=' rather than ':=',
# so that BOOKS can be redefined after including this file in another makefile
# and the variables below will automatically be updated accordingly.

BOOKS_CERT    = $(patsubst %, %.cert,    $(BOOKS))
BOOKS_FASL    = $(patsubst %, %.fasl,    $(BOOKS))
BOOKS_FAS     = $(patsubst %, %.fas,     $(BOOKS))
BOOKS_SPARCF  = $(patsubst %, %.sparcf,  $(BOOKS))
BOOKS_UFSL    = $(patsubst %, %.ufsl,    $(BOOKS))
BOOKS_DFSL    = $(patsubst %, %.dfsl,    $(BOOKS))
BOOKS_D64FSL  = $(patsubst %, %.d64fsl,  $(BOOKS))
BOOKS_DX64FSL = $(patsubst %, %.dx64fsl, $(BOOKS))
BOOKS_LX64FSL = $(patsubst %, %.lx64fsl, $(BOOKS))
BOOKS_X86F    = $(patsubst %, %.x86f,    $(BOOKS))
BOOKS_O       = $(patsubst %, %.o,       $(BOOKS))
BOOKS_LISP    = $(patsubst %, %.lisp,    $(BOOKS))
BOOKS_BKCHK_OUT = $(patsubst %, %.bkchk.out, $(BOOKS))

#  This tells make to expect `suffix rules' for these file suffixes.

.SUFFIXES: .cert .lisp

#  This rule tells how to get <book>.cert from <book>.lisp, either by running
#  ACL2 on the <book>.acl2 file (if it exists) or using the default command
#  to certify at ground zero.  Note that some Lisps execute (LP) upon startup
#  and some do not, and some (e.g., OpenMCL) might not even start in the ACL2
#  package, which can cause a problem if .acl2 files in our regressions suite
#  execute (LP) instead of (ACL2::LP).  We deal with these issues below.

.lisp.cert:
	@echo "Making `pwd`/$*.cert on `date`"
	@rm -f $*.cert
	@echo '(acl2::value :q)' > workxxx.$(*F)
	@echo '(in-package "ACL2")' >> workxxx.$(*F)
	@echo '(acl2::lp)' >> workxxx.$(*F)
	@echo '$(INHIBIT)' >> workxxx.$(*F)
	@if [ -f $*.acl2 ] ; \
	then \
	  cat $*.acl2 >> workxxx.$(*F) ; \
	elif [ -f cert.acl2 ] ; \
	then \
	  cat cert.acl2 >> workxxx.$(*F) ; \
	  echo "" >> workxxx.$(*F) ; \
	  echo '(certify-book "$*" ? $(COMPILE_FLG))' >> workxxx.$(*F) ; \
	else \
	  echo "" >> workxxx.$(*F) ; \
	  echo '(certify-book! "$*" 0 $(COMPILE_FLG))' >> workxxx.$(*F) ; \
	fi
	@echo "" >> workxxx.$(*F)
	@echo '(acl2::value :q)' >> workxxx.$(*F)
	@echo '(acl2::exit-lisp)' >> workxxx.$(*F)
	@if [ -n "$(ACL2_BOOKS_DEBUG)" ] ;\
	then \
	  echo "[Makefile-generic]: certify book commands:" ;\
	  echo "" ;\
	  cat workxxx.$(*F) ;\
	  echo "" ;\
	fi	
	@($(ACL2) < workxxx.$(*F) 2>&1) > $*.out
	@rm -f workxxx.$(*F)
	@((test -f $<) && (ls -al $*.cert)) || \
            (echo "**CERTIFICATION FAILED** for `pwd`/$*.lisp" ;\
	     echo "" ;\
	     tail -300 $*.out | sed 's/^/   | /' ;\
	     echo "" ;\
	     echo "" ;\
	     echo "**CERTIFICATION FAILED** for `pwd`/$*.lisp" ;\
             exit 1)
# The following code can replace the line just above.  However, it is a bit
# complicated by our having seen sh on Sun/Solaris 5.9 fail to recognize -nt,
# which is this code uses csh instead of sh if possible.  At any rate, the test
# on file dates seems unnecessary since we remove the .cert file immediately
# upon entering this target.
#	@if [ `which csh` ] ; then \
#	csh -c "((test -f $< -a ! $< -nt $@ ) && (ls -al $*.cert))" || ($(MAKE) -s --no-print-directory FAILED FAILED_BOOK=`pwd`/$*.lisp) ; \
#	else \
#	((test -f $< -a ! $< -nt $@ ) && (ls -al $*.cert)) || ($(MAKE) -s --no-print-directory FAILED FAILED_BOOK=`pwd`/$*.lisp) ; \
#	fi

#  This rule certifies every book in BOOKS.  If the dependencies are set up
#  correctly then the order of the books in BOOKS won't matter.

.PHONY: all
all:
	@if [ -n "$(ACL2_BOOKS_DEBUG)" ] ;\
	then \
		echo "[Makefile-generic]: Preparing to make 'all'" ;\
	fi
	@echo 'Using ACL2=$(ACL2)'
	$(MAKE) -s -f $(ACL2_BOOKS_MAKEFILE) $(BOOKS_CERT) INHIBIT='$(INHIBIT)' ACL2='$(ACL2)'

# The following rules are useful when books have been certified in one lisp,
# but we would also like their compiled files to exist in the other lisp.

.PHONY: fasl
fasl:
	@echo 'Using ACL2=$(ACL2)'
	$(MAKE) -s -f $(ACL2_BOOKS_MAKEFILE) $(BOOKS_FASL) INHIBIT='$(INHIBIT)' ACL2='$(ACL2)'

%.fasl: %.cert
	@echo "Making $$PWD/$@"
	echo '(acl2::value :q) (acl2::lp) (ld `((include-book "$(patsubst %.fasl,%,$(@))" :load-compiled-file :comp :ttags :all))) (acl2::value :q) (acl2::exit-lisp)' | $(ACL2)

.PHONY: fas
fas:
	@echo 'Using ACL2=$(ACL2)'
	$(MAKE) -s -f $(ACL2_BOOKS_MAKEFILE) $(BOOKS_FAS) INHIBIT='$(INHIBIT)' ACL2='$(ACL2)'

# For CLISP, apparently only the first echoed form is evaluated.  So do not give multiple forms.
%.fas: %.cert
	@echo "Making $$PWD/$@"
	echo '(ld `((include-book "$(patsubst %.fas,%,$(@))" :load-compiled-file :comp :ttags :all)))' | $(ACL2)

.PHONY: sparcf
sparcf:
	@echo 'Using ACL2=$(ACL2)'
	$(MAKE) -s -f $(ACL2_BOOKS_MAKEFILE) $(BOOKS_SPARCF) INHIBIT='$(INHIBIT)' ACL2='$(ACL2)'

%.sparcf: %.cert
	@echo "Making $$PWD/$@"
	echo '(acl2::value :q) (acl2::lp) (ld `((include-book "$(patsubst %.sparcf,%,$(@))" :load-compiled-file :comp :ttags :all))) (acl2::value :q) (acl2::exit-lisp)' | $(ACL2)

.PHONY: ufsl
ufsl:
	@echo 'Using ACL2=$(ACL2)'
	$(MAKE) -s -f $(ACL2_BOOKS_MAKEFILE) $(BOOKS_UFSL) INHIBIT='$(INHIBIT)' ACL2='$(ACL2)'

%.ufsl: %.cert
	@echo "Making $$PWD/$@"
	echo '(acl2::value :q) (acl2::lp) (ld `((include-book "$(patsubst %.ufsl,%,$(@))" :load-compiled-file :comp :ttags :all))) (acl2::value :q) (acl2::exit-lisp)' | $(ACL2)

.PHONY: x86f
x86f:
	@echo 'Using ACL2=$(ACL2)'
	$(MAKE) -s -f $(ACL2_BOOKS_MAKEFILE) $(BOOKS_X86F) INHIBIT='$(INHIBIT)' ACL2='$(ACL2)'

%.x86f: %.cert
	@echo "Making $$PWD/$@"
	echo '(acl2::value :q) (acl2::lp) (ld `((include-book "$(patsubst %.x86f,%,$(@))" :load-compiled-file :comp :ttags :all))) (acl2::value :q) (acl2::exit-lisp)' | $(ACL2)

.PHONY: dfsl
dfsl:
	@echo 'Using ACL2=$(ACL2)'
	$(MAKE) -s -f $(ACL2_BOOKS_MAKEFILE) $(BOOKS_DFSL) INHIBIT='$(INHIBIT)' ACL2='$(ACL2)'

%.dfsl: %.cert
	@echo "Making $$PWD/$@"
	echo '(acl2::value :q) (acl2::lp) (ld `((include-book "$(patsubst %.dfsl,%,$(@))" :load-compiled-file :comp :ttags :all))) (acl2::value :q) (acl2::exit-lisp)' | $(ACL2)

.PHONY: d64fsl
d64fsl:
	@echo 'Using ACL2=$(ACL2)'
	$(MAKE) -s -f $(ACL2_BOOKS_MAKEFILE) $(BOOKS_D64FSL) INHIBIT='$(INHIBIT)' ACL2='$(ACL2)'

%.d64fsl: %.cert
	@echo "Making $$PWD/$@"
	echo '(acl2::value :q) (acl2::lp) (ld `((include-book "$(patsubst %.d64fsl,%,$(@))" :load-compiled-file :comp :ttags :all))) (acl2::value :q) (acl2::exit-lisp)' | $(ACL2)

.PHONY: dx64fsl
dx64fsl:
	@echo 'Using ACL2=$(ACL2)'
	$(MAKE) -s -f $(ACL2_BOOKS_MAKEFILE) $(BOOKS_DX64FSL) INHIBIT='$(INHIBIT)' ACL2='$(ACL2)'

%.dx64fsl: %.cert
	@echo "Making $$PWD/$@"
	echo '(acl2::value :q) (acl2::lp) (ld `((include-book "$(patsubst %.dx64fsl,%,$(@))" :load-compiled-file :comp :ttags :all))) (acl2::value :q) (acl2::exit-lisp)' | $(ACL2)

.PHONY: o
o:
	@echo 'Using ACL2=$(ACL2)'
	$(MAKE) -s -f $(ACL2_BOOKS_MAKEFILE) $(BOOKS_O) INHIBIT='$(INHIBIT)' ACL2='$(ACL2)'

%.o: %.cert
	@echo "Making $$PWD/$@"
	echo '(acl2::value :q) (acl2::lp) (ld `((include-book "$(patsubst %.o,%,$(@))" :load-compiled-file :comp :ttags :all))) (acl2::value :q) (acl2::exit-lisp)' | $(ACL2)

.PHONY: lx64fsl
lx64fsl:
	@echo 'Using ACL2=$(ACL2)'
	$(MAKE) -s -f $(ACL2_BOOKS_MAKEFILE) $(BOOKS_LX64FSL) INHIBIT='$(INHIBIT)' ACL2='$(ACL2)'

%.lx64fsl: %.cert
	@echo "Making $$PWD/$@"
	echo '(acl2::value :q) (acl2::lp) (ld `((include-book "$(patsubst %.lx64fsl,%,$(@))" :load-compiled-file :comp :ttags :all))) (acl2::value :q) (acl2::exit-lisp)' | $(ACL2)

.PHONY: nothing
nothing:
	@echo "There\'s a good reason to do this here."

# The dependencies rule prints make dependency commands to the screen.  The basic
# strategy is to look for include-book commands, and to prefix appropriately
# "$(ACL2_SYSTEM_BOOKS)" when :dir :system is specified.  Thus, if :dir :system is
# specified then a common Makefile header in a books directory could be as
# follows (just strip off the leading "# " on each line).

# ----------------------------------------------------------------------
# # The following variable should represent the ACL2 source directory.
# # It is the only variable in this Makefile that may need to be edited.
# ACL2_SRC = ../../../../../..

# ACL2_SYSTEM_BOOKS = $(ACL2_SRC)/books
# include $(ACL2_SYSTEM_BOOKS)/Makefile-generic
# ACL2 = $(ACL2_SRC)/saved_acl2
# ----------------------------------------------------------------------

# Here are variables that represent egrep commands for finding include-book
# forms, as well as sed commands for modifying those include-book forms to
# generate dependency lines.

# Grep commands to rule out :dir :system:
ACL2_NON_DIR            = egrep -i -v ':dir'

# Grep commands for include-book and ld forms withOUT :dir:
ACL2_EGREP_CMD          = egrep -i '^[^;]*include-book[ 	]*\".*\"' $$book.lisp | $(ACL2_NON_DIR)
ACL2_EGREP_CMD_ACL2     = $(subst book.lisp,book.acl2,$(ACL2_EGREP_CMD))
ACL2_EGREP_CMD_CERT     = $(subst $$book.lisp,cert.acl2,$(ACL2_EGREP_CMD))
ACL2_EGREP_CMD_ACL2_LD  = egrep -i '^[^;]*\(ld[ 	]*\".*\"' $$book.acl2 | $(ACL2_NON_DIR)
ACL2_EGREP_CMD_CERT_LD  = egrep -i '^[^;]*\(ld[ 	]*\".*\"' cert.acl2 | $(ACL2_NON_DIR)

# Grep commands for include-book and ld forms WITH :dir :system (need a file argument):
ACL2_EGREP_CMD_DIR      = egrep -i '^[^;]*include-book[ 	]*\".*\"[ 	]*:dir[ 	]*:system'
ACL2_EGREP_CMD_DIR_LD   = egrep -i '^[^;]*\(ld[ 	]*\".*\"[ 	]*:dir[ 	]*:system'

# Sed commands for transforming above egrep results into a dependency line:
ACL2_SED_CMD            = sed "s/[^\"]*\"/$$book.cert: /" | sed 's/".*/.cert/'
ACL2_SED_CMD_LD         = sed "s/[^\"]*\"/$$book.cert: /" | sed 's/".*//'
ACL2_SED_CMD_DIR        = $(subst book.cert: ,book.cert: $$\(ACL2_SYSTEM_BOOKS)\/,$(ACL2_SED_CMD))
ACL2_SED_CMD_DIR_LD     = $(subst book.cert: ,book.cert: $$\(ACL2_SYSTEM_BOOKS)\/,$(ACL2_SED_CMD_LD))

# To comment out a line:
ACL2_SED_CMD_COMMENT    = sed "s/^/\# /"

# See comments above.
.PHONY: dependencies
dependencies: 
	@for book in $(BOOKS) ; \
	do \
	echo "" ;  echo "$$book.cert: $$book.lisp" ; \
	$(ACL2_EGREP_CMD) | $(ACL2_SED_CMD) ;\
	$(ACL2_EGREP_CMD_DIR) $$book.lisp | $(ACL2_SED_CMD_DIR) | $(ACL2_SED_CMD_COMMENT) ;\
	if [ -f $$book.acl2 ]; then \
	echo "$$book.cert: $$book.acl2" ; \
	$(ACL2_EGREP_CMD_ACL2) | $(ACL2_SED_CMD) ;\
	$(ACL2_EGREP_CMD_ACL2_LD) | $(ACL2_SED_CMD_LD) ;\
	$(ACL2_EGREP_CMD_DIR) $$book.acl2 | $(ACL2_SED_CMD_DIR) | $(ACL2_SED_CMD_COMMENT) ;\
	$(ACL2_EGREP_CMD_DIR_LD) $$book.acl2 | $(ACL2_SED_CMD_DIR_LD) | $(ACL2_SED_CMD_COMMENT) ;\
	elif [ -f cert.acl2 ]; then \
	echo "$$book.cert: cert.acl2" ; \
	$(ACL2_EGREP_CMD_CERT) | $(ACL2_SED_CMD) ;\
	$(ACL2_EGREP_CMD_CERT_LD) | $(ACL2_SED_CMD_LD) ;\
	$(ACL2_EGREP_CMD_DIR) cert.acl2 | $(ACL2_SED_CMD_DIR) | $(ACL2_SED_CMD_COMMENT) ;\
	$(ACL2_EGREP_CMD_DIR_LD) cert.acl2 | $(ACL2_SED_CMD_DIR_LD) | $(ACL2_SED_CMD_COMMENT) ;\
	fi ; \
	done

.PHONY: clean
clean:
	rm -f Makefile-deps
	rm -f *.cert *.cert.temp
	rm -f *.h
	rm -f *.c
	rm -f *.o
	rm -f *.sbin
	rm -f *.lbin
	rm -f *.fasl
	rm -f *.ufsl
	rm -f *.pfsl
	rm -f *.dfsl
	rm -f *.d64fsl
	rm -f *.dx64fsl
	rm -f *.lx64fsl *.lx32fsl
	rm -f *.bin
	rm -f *.sparcf
	rm -f *.axpf
	rm -f *.x86f
	rm -f *.ppcf
	rm -f *.fas
	rm -f *.lib
	rm -f *.out
	rm -f *.date
	rm -f *.log
	rm -f TMP*.*
	rm -f *@expansion.lsp
	rm -f temp-emacs-file.lsp
	rm -f workxxx*

ifdef FAST_DEPS_FOR_CLEAN
# Note that Makefile-deps will be deleted by the clean target
# immediately after the following code creates it.
Makefile-deps: 
	@echo "# Skipping deps" > Makefile-deps
else
# The argument --no-print-directory below avoids lines like:
# make[3]: Leaving directory `/v/filer4b/v11q001/acl2/devel/v3-5-alpha-aug31/books/bdd'
Makefile-deps: $(BOOKS_LISP) $(wildcard *.acl2)
	@echo "Updating dependencies in `pwd`"
	@rm -f Makefile-deps
	@echo "# This file is automatically generated; do not hand edit." > Makefile-deps
	+@make --no-print-directory -s dependencies >> Makefile-deps
endif

# The following targets are primarily for developers to be able to
# check well-formedness of the ACL2 world after including each book.
# Note that the two problematic directories for world-checking,
# hacking/ and workshops/2007/dillinger-et-al/code/ override the
# chk-include-book-worlds target by setting environment variable
# ACL2_SKIP_CHK_INCLUDE_BOOK_WORLDS in order to skip this check.  The
# problem seems likely to be that in many of the books in these two
# directories, the first bad triple is a GLOBAL-VALUE for either the
# unknown property EXTEND-PROGN! or RETRACT-PROGN!, or else is an
# unbinding of the PREDEFINED property for PROGN! (indicating a use of
# :REDEF); presumably these books mess with raw mode.

.PHONY: chk-include-book-worlds
chk-include-book-worlds:
	if [ -z "$(ACL2_SKIP_CHK_INCLUDE_BOOK_WORLDS)" ]; then \
	echo "Using ACL2=$(ACL2)" ; \
	(rm -f *.bkchk.out > /dev/null) ; \
	$(MAKE) -s $(BOOKS_BKCHK_OUT) ACL2='$(ACL2)' ; \
	fi

%.bkchk.out: %.cert
	@echo "Including `pwd`/$* on `date`"
	@echo '(acl2::value :q)' > workxxx.bkchk.$(*F)
	@echo '(in-package "ACL2")' >> workxxx.bkchk.$(*F)
	@echo '(acl2::lp)' >> workxxx.bkchk.$(*F)
	@echo '(acl2::in-package "ACL2")' >> workxxx.bkchk.$(*F)
	@echo '(include-book "$*")' >> workxxx.bkchk.$(*F)
	@echo '(include-book "system/pseudo-good-worldp" :dir :system)' >> workxxx.bkchk.$(*F)
	@echo "Checking world created by including `pwd`/$* on `date`"
	@echo '(chk-pseudo-good-worldp "$*")' >> workxxx.bkchk.$(*F)
	@($(ACL2) < workxxx.bkchk.$(*F) 2>&1) > $*.bkchk.out
	@(fgrep 'Pseudo-good-worldp check for including "$*" passed.' $@) || \
            (echo '** Pseudo-good-worldp check FAILED for including $*;' "see `pwd`/$@" '**' ;\
             exit 1)
	@rm -f workxxx.bkchk.$(*F)
