The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.
PROJECTNAME = logical_expression_parser

VERSION = 0.01

# Installation prefix
PREFIX = /usr

LIBRARY_NAME = logical_expression_parser_library

# Any other files you want to distribute when the tarball is created with
# "make dist"
EXTRA_DIST_FILES = README

# The extensions for C++ code, C code, YACC grammars, and LEX scanners
CCFILEEXT = cc
CFILEEXT = c
FFILEEXT = f
YACCFILEEXT = y
LEXFILEEXT = lex
SCRIPTFILEEXT = sh

# Typical flags for GNU compilers: -g (debugging information), -p (profiling),
# -O2 (optimization), -Idir (extra include directory), -DDEBUG,
# -Wall (all warnings)
CFLAGS		= -Wall -pedantic -O3
FFLAGS		= -g -C

# Linker flags. Use -lg2c if you're calling Fortran from C/C++
LDFLAGS		=

# Appear on the end of the link line
LIB_FLAGS :=

# You should really leave this as GNUmakefile since this makefile uses GNU
# extensions
MAKEFILE_NAME := GNUmakefile

# -----------------------------------------------------------------------------

# Programs
LN          = '/sw/bin/ln'
CP          = '/sw/bin/cp'
RM          = '/bin/rm'
MV          = '/sw/bin/mv'
BASH        = bash
FIND        = '/sw/bin/find'
GREP        = '/usr/bin/grep'
CHMOD	    = '/sw/bin/chmod'
CC          = gcc
CXX         = '/usr/bin/g++'
FC          = g77
LD          = '/usr/bin/g++'
AR          = '/usr/bin/ar'
LEX         = flex
UNIX2DOS    = unix2dos
YACC        = yacc
MKDIR       = '/sw/bin/mkdir'
TAR         = tar
GZIP        = gzip
ZIP         = zip
DIFF        = diff
MKDIRHIER   = $(PERL) $(UTILSDIR)/mkdirhier.pl
DATE        = '/bin/date'
PERL        = '/usr/bin/perl'
MAKEDEPEND  = $(PERL) $(UTILSDIR)/makedependgcc
COLORS      = $(PERL) $(UTILSDIR)/colors
BASEDIR     = $(PERL) $(UTILSDIR)/basedir
DIRNAME     = '/usr/bin/dirname'
EXPR        = '/bin/expr'

# -----------------------------------------------------------------------------

# Set to "true" to disable colors
DISABLE_COLORS = true

# Color preferences
DEFAULT_FOREGROUND = white
DEFAULT_BACKGROUND = black
MAIN_STEP_FOREGROUND = green
MAIN_STEP_BACKGROUND = black
SUB_STEP_FOREGROUND = cyan
SUB_STEP_BACKGROUND = black
WARNING_FOREGROUND = red
WARNING_BACKGROUND = black
ERROR_FOREGROUND = black
ERROR_BACKGROUND = red

# -----------------------------------------------------------------------------

# Set to true to store files in another location and create symbolic links to
# the current directory. This is useful for systems with slow NFS performance,
# or systems with limited user disk space. (i.e. we can store things in /tmp
# as specified by the STORAGE_DIRECTORY variable.)
STORE_FILES_ELSEWHERE = false

# NOTE: This directory will be created if necessary. It will NOT be deleted
# during make clean.
STORAGE_DIRECTORY = /tmp/$(USER)/$(PROJECTNAME)

###############################################################################

default : progs

# Custom dependencies, if any, go here

############################# END OF CONFIGURATION ############################
###############################################################################

# Directories
SRCDIR = src
TESTDIR = tests
PROGDIR = progs
BUILDDIR = build
LIBDIR = lib
ETCDIR = etc
UTILSDIR = util
DOCUMENTDIR = doc

# Add $(BUILDDIR) because there may be generated .h files from yacc.
CFLAGS          := -I$(SRCDIR) -I$(BUILDDIR) $(CFLAGS)
LDFLAGS         := -L$(LIBDIR) $(LDFLAGS)

# -----------------------------------------------------------------------------

PROGRAMS    = $(CP) $(RM) $(MV) $(FIND) $(GREP) $(CXX) $(LD) $(FC) \
              $(AR) $(LEX) $(UNIX2DOS) $(YACC) $(MKDIR) $(TAR) $(GZIP) \
              $(ZIP) $(DIFF) $(MKDIRHIER) $(DATE) $(PERL) $(MAKEDEPEND) \
              $(CHMOD) $(BASH) $(LN) $(DIRNAME) $(BASEDIR) $(EXPR)

# -----------------------------------------------------------------------------

# We use a simple assignment to prevent re-evaluation of the shell command
# (resulting in different PIDs and random numbers)
TEMPDIR := $(shell $(DATE) +tempdir-%H-%M-%S-$$$$-$$RANDOM)
DISTFILE = $(shell $(DATE) +$(PROJECTNAME)-$(VERSION)-%Y-%m-%d)

# -----------------------------------------------------------------------------

# Libraries
LIB_FLAGS := -l$(LIBRARY_NAME) $(LIB_FLAGS)

EMPTY =
SPACE = $(EMPTY) $(EMPTY)
COMMA = ,
make_pattern = \($(subst $(SPACE),\|,$(1))\)

SRC_FILE_EXTS = \
  $(CFILEEXT) $(CCFILEEXT) $(FFILEEXT) $(LEXFILEEXT) $(YACCFILEEXT)

GENERATED_SRC_FILE_EXTS = $(LEXFILEEXT) $(YACCFILEEXT)

# A couple patterns for easier searching commands
SRC_FILE_EXTS_PATTERN = \
  $(call make_pattern,$(SRC_FILE_EXTS))

GENERATED_SRC_FILE_EXTS_PATTERN = \
  $(call make_pattern,$(GENERATED_SRC_FILE_EXTS))

SRC_DIRS_PATTERN = $(call make_pattern,$(call compute_subdirs_with_sources))

# Some subroutines to find source files and compute their corresponding object
# files
find_source_files = \
  $(shell $(FIND)                                                $(SRCDIR) -regex '$(SRCDIR)/$(1)/.*\.$(SRC_FILE_EXTS_PATTERN)')

find_shell_scripts = \
  $(shell $(FIND)                                                $(SRCDIR) -regex '$(SRCDIR)/$(1)/.*\.$(SCRIPTFILEEXT)')

# In case we need this later
#find_nonsource_files = \
#  $(filter-out \
#    $(shell $(FIND)                                                $(SRCDIR) -regex '$(SRCDIR)/$(1)/.*\.$(SRC_FILE_EXTS_PATTERN)'), \
#    $(shell $(FIND)                                                $(SRCDIR) -regex '$(SRCDIR)/$(1)/.*'))

find_gen_source_files = \
  $(shell $(FIND)                                                $(SRCDIR) -regex '$(SRCDIR)/$(1)/.*\.$(GENERATED_SRC_FILE_EXTS_PATTERN)')

compute_subdirs_with_sources = $(filter-out progs tests progs/% tests/%, \
  $(sort $(subst $(SRCDIR)/,, \
  $(patsubst %/,%,$(dir $(call find_source_files,*))))))

compute_ofiles = $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%.o, \
  $(basename $(call find_source_files,$1)))

compute_ofile = $(patsubst $(firstword \
  $(subst /,$(SPACE),$(1)))/%,$(BUILDDIR)/%.o,$(basename $(1)))

# Source files generated from lex or yacc
GENERATED_SRC_FILES = $(patsubst $(SRCDIR)/%, \
  $(BUILDDIR)/%.$(CCFILEEXT), \
  $(basename $(call find_gen_source_files,$(SRC_DIRS_PATTERN))))

# Object files. Just used for dependency analysis
OBJFILES = $(call compute_ofiles,$(SRC_DIRS_PATTERN)) \
  $(call compute_ofiles,tests) $(call compute_ofiles,progs)

# Test cases and test binaries
COMPILED_TESTS = $(patsubst $(SRCDIR)/tests/%,$(TESTDIR)/%, \
  $(basename $(call find_source_files,tests)))

NONCOMPILED_TESTS = $(patsubst $(SRCDIR)/tests/%,$(TESTDIR)/%, \
  $(call find_shell_scripts,tests))

TESTS = $(COMPILED_TESTS) $(NONCOMPILED_TESTS)

# Programs
PROGS = $(patsubst $(SRCDIR)/progs/%,$(PROGDIR)/%, \
  $(basename $(call find_source_files,progs)))

.SUFFIXES : $(patsubst %,.%,$(SRC_FILE_EXTS)) .o .a .t .$(YACCFILEEXT) .$(LEXFILEEXT)

# To prevent gnu make from deleting the intermediate parser-related
# implementation files
.SECONDARY : 

.PHONY: progs lib tests

################################# MAIN TARGETS ################################
###############################################################################

install : install_progs install_lib

install_progs : progs
	install $(PROGS) $(PREFIX)/bin

install_lib: lib
	install $(LIBDIR)/lib$(LIBRARY_NAME).a ${PREFIX}/lib

lib : lib_message $(LIBDIR)/lib$(LIBRARY_NAME).a

# Check build environment
check : check_message check_programs check_colors

# Run tests
test : compiled_tests noncompiled_tests
	@$(call main_step_msg,Tests completed)
	@echo '   Compiled' tests: `cat $(TESTDIR)/COMPILED_TESTS_PASS` passed, `cat $(TESTDIR)/COMPILED_TESTS_FAIL` failed
	@echo Noncompiled tests: `cat $(TESTDIR)/NONCOMPILED_TESTS_PASS` passed, `cat $(TESTDIR)/NONCOMPILED_TESTS_FAIL` failed
	@$(RM) $(TESTDIR)/COMPILED_TESTS_PASS $(TESTDIR)/COMPILED_TESTS_FAIL \
	   $(TESTDIR)/NONCOMPILED_TESTS_PASS $(TESTDIR)/NONCOMPILED_TESTS_FAIL

# Make the libraries and programs
progs : lib progs_message $(PROGS) 

clean : clean_message 
	$(RM) -rf $(BUILDDIR) $(LIBDIR) $(TESTDIR) $(PROGDIR)
	@# The echo is just so the user can see what's happening
	@if test $(STORE_FILES_ELSEWHERE) = 'true'; then \
	  echo $(RM) -rf $(STORAGE_DIRECTORY)/$(BUILDDIR) \
	    $(STORAGE_DIRECTORY)/$(LIBDIR) \
	    $(STORAGE_DIRECTORY)/$(TESTDIR) $(STORAGE_DIRECTORY)/$(PROGDIR); \
	  $(RM) -rf $(STORAGE_DIRECTORY)/$(BUILDDIR) $(STORAGE_DIRECTORY)/$(LIBDIR) \
	    $(STORAGE_DIRECTORY)/$(TESTDIR) $(STORAGE_DIRECTORY)/$(PROGDIR); \
  fi

dist : dist_message distdir
	@$(call sub_step_msg,Making distribution file...)
	$(MV) $(TEMPDIR) $(DISTFILE)
	$(TAR) cf $(DISTFILE).tar $(DISTFILE)
	$(RM) -f $(DISTFILE).tar.gz
	$(GZIP) -9 $(DISTFILE).tar
	$(RM) -rf $(DISTFILE)

windist : windist_message windistdir
	@$(call sub_step_msg,Making distribution file...)
	$(MV) $(TEMPDIR) $(DISTFILE)
	$(ZIP) $(DISTFILE)-win.zip $(DISTFILE)/*
	$(RM) -rf $(DISTFILE)

################################### MESSAGES ##################################
###############################################################################

check_programs_message :
	@$(call sub_step_msg,Checking that programs exist...)

compiled_tests_message :
	@$(call sub_step_msg,Building compiled test cases into tests directory)

noncompiled_tests_message :
	@$(call sub_step_msg,Copying noncompiled test cases to tests directory)

lib_message :
	@$(call main_step_msg,Making library $(LIBRARY_NAME))

check_message :
	@$(call main_step_msg,Checking build environment...)

progs_message :
	@$(call main_step_msg,Making programs)

clean_message :
	@$(call main_step_msg,Making clean)

dist_message :
	@$(call main_step_msg,Making $(DISTFILE).tar.gz)

windist_message :
	@$(call main_step_msg,Making $(DISTFILE).zip)

################################# SUBROUTINES #################################
###############################################################################

# A subroutine to make a directory
make_directory = @ \
	if test ! -d $(1); then \
	  if test $(STORE_FILES_ELSEWHERE) = 'true'; then \
	    echo '--' Creating directory $(STORAGE_DIRECTORY)/$(1)...; \
	    echo $(MKDIRHIER) $(STORAGE_DIRECTORY)/$(1); \
	    $(MKDIRHIER) $(STORAGE_DIRECTORY)/$(1); \
	    if test ! -e `$(BASEDIR) $(1)`; then \
	      echo '--' Making symbolic link from $(STORAGE_DIRECTORY)/`$(BASEDIR) $(1)` to `$(BASEDIR) $(1)`...; \
	      echo $(LN) -s $(STORAGE_DIRECTORY)/`$(BASEDIR) $(1)` `$(BASEDIR) $(1)`; \
	      $(LN) -s $(STORAGE_DIRECTORY)/`$(BASEDIR) $(1)` `$(BASEDIR) $(1)`; \
	    fi; \
	  else \
	    echo '--' Creating directory $(1)...; \
	    echo $(MKDIRHIER) $(1); \
	    $(MKDIRHIER) $(1); \
	  fi; \
	fi

# Subroutines to issue colored alerts
main_step_msg = \
  if test $(DISABLE_COLORS) = 'false'; then \
    $(COLORS) $(MAIN_STEP_FOREGROUND) $(MAIN_STEP_BACKGROUND); \
  fi; \
  echo -n '===> $(1)'; \
  if test $(DISABLE_COLORS) = 'false'; then \
    $(COLORS) $(DEFAULT_FOREGROUND) $(DEFAULT_BACKGROUND); \
  fi; \
  echo

sub_step_msg = \
  if test $(DISABLE_COLORS) = 'false'; then \
    $(COLORS) $(SUB_STEP_FOREGROUND) $(SUB_STEP_BACKGROUND); \
  fi; \
  echo -n '> $(1)'; \
  if test $(DISABLE_COLORS) = 'false'; then \
    $(COLORS) $(DEFAULT_FOREGROUND) $(DEFAULT_BACKGROUND); \
  fi; \
  echo

warning_msg = \
  if test $(DISABLE_COLORS) = 'false'; then \
    $(COLORS) $(WARNING_FOREGROUND) $(WARNING_BACKGROUND); \
  fi; \
  echo -n '> $(1)'; \
  if test $(DISABLE_COLORS) = 'false'; then \
    $(COLORS) $(DEFAULT_FOREGROUND) $(DEFAULT_BACKGROUND); \
  fi; \
  echo

error_msg = \
  if test $(DISABLE_COLORS) = 'false'; then \
    $(COLORS) $(ERROR_FOREGROUND) $(ERROR_BACKGROUND); \
  fi; \
  echo -n '\#\#\#> $(1)'; \
  if test $(DISABLE_COLORS) = 'false'; then \
    $(COLORS) $(DEFAULT_FOREGROUND) $(DEFAULT_BACKGROUND); \
  fi; \
  echo

############################# SUPPORTING TARGETS ##############################
###############################################################################

check_programs : check_programs_message $(patsubst %,%.checkprogram,$(PROGRAMS))

%.checkprogram:
	@if !($* --help 2>&1 | grep -i '\(usage\|option\|invalid\)' > /dev/null); then \
	  $(call warning_msg,Could not find program $*. You may not need it--check the makefile.); \
	fi

# -----------------------------------------------------------------------------

check_colors:
	@echo Now checking colors. You may want to set DISABLE_COLORS to true.
	@$(call main_step_msg,This is a main step message.)
	@$(call sub_step_msg,This is a sub-step message.)
	@$(call warning_msg,This is a warning!)
	@$(call error_msg,This is an error!)

########################### DEPENDENCY GENERATION #############################
###############################################################################

# Cancel the normal implicit rules to make sure we get our own ones
%.c : %.$(YACCFILEEXT)
%.c : %.$(LEXFILEEXT)

# Dependency generation for object files

# Rule to make .o.d files from .$(CCFILEEXT) files
$(BUILDDIR)/%.o.d : $(SRCDIR)/%.$(CCFILEEXT)
	$(call make_directory,$(shell $(DIRNAME) $@))
	@$(call sub_step_msg,Making dependencies file $@)
	@set -e; rm -f $@; \
	 $(MAKEDEPEND) -- $(CXX) -MM $(CFLAGS) $< -o $(call compute_ofile,$<) > $@.$$$$; \
	 sed 's,\($(call compute_ofile,$<)\)[ :]*,\1 $@: ,g' < $@.$$$$ > $@; \
	 rm -f $@.$$$$

# Rule to make .o.d files from .$(CFILEEXT) files
$(BUILDDIR)/%.o.d : $(SRCDIR)/%.$(CFILEEXT)
	$(call make_directory,$(shell $(DIRNAME) $@))
	@$(call sub_step_msg,Making dependencies file $@)
	@set -e; rm -f $@; \
	 $(MAKEDEPEND) -- $(CC) -MM $(CFLAGS) $< -o $(call compute_ofile,$<) > $@.$$$$; \
	 sed 's,\($(call compute_ofile,$<)\)[ :]*,\1 $@: ,g' < $@.$$$$ > $@; \
	 rm -f $@.$$$$

# Rule to make .o.d files from generated .$(CCFILEEXT) files
# This is pretty yucky. We pass -MG to tell the GNU compiler to treat missing
# headers as generated. Then we have to patch up the paths so that the
# dependencies will refer to files in the build directory
$(BUILDDIR)/%.o.d : $(BUILDDIR)/%.$(CCFILEEXT)
	$(call make_directory,$(shell $(DIRNAME) $@))
	@$(call sub_step_msg,Making dependencies file $@)
	@set -e; rm -f $@; \
	 $(MAKEDEPEND) -- $(CXX) -MM -MG $(CFLAGS) $< -o $(call compute_ofile,$<) > $@.$$$$; \
	 sed 's,\($(call compute_ofile,$<)\)[ :]*,\1 $@: ,g' < $@.$$$$ > $@; \
	 rm -f $@.$$$$; \
	 mv $@ $@.$$$$; \
	 sed 's, \($(shell $(DIRNAME) $*)\), $(BUILDDIR)/\1,g' < $@.$$$$ > $@; \
	 rm -f $@.$$$$

# Dependency generation for library files

format_files=$(subst $(SPACE),$(SPACE)\\\\\\n$(SPACE)$(SPACE),$1)

$(BUILDDIR)/$(LIBDIR)/%.a.d :
	$(call make_directory,$(shell $(DIRNAME) $@))
	@$(call sub_step_msg,Making dependencies file $@)
	@set -e; rm -f $@; \
	 echo -e '$(LIBDIR)/$*.a: \\'"\\n  $(call format_files,$(call compute_ofiles,$(patsubst lib%,%,$*)))\\n" > $@

# Dependency generation for generated files

$(BUILDDIR)/%.$(CCFILEEXT).d : $(SRCDIR)/%.$(LEXFILEEXT)
	$(call make_directory,$(shell $(DIRNAME) $@))
	@$(call sub_step_msg,Making dependencies file $@)
	@set -e; rm -f $@; \
	 echo -e '$(BUILDDIR)/$*.$(CCFILEEXT) $@: \\'"\\n  $<\\n" > $@

$(BUILDDIR)/%.$(CCFILEEXT).d : $(SRCDIR)/%.$(YACCFILEEXT)
	$(call make_directory,$(shell $(DIRNAME) $@))
	@$(call sub_step_msg,Making dependencies file $@)
	@set -e; rm -f $@; \
	 echo -e '$(BUILDDIR)/$*.$(CCFILEEXT) $(BUILDDIR)/$*.h $@: \\'"\\n  $<\\n" > $@

# -----------------------------------------------------------------------------

# Include the dependencies (will automatically generate them). We guard this
# so that you can always run "make clean" without having to worry about
# generating dependencies

ifneq ($(MAKECMDGOALS),clean)
-include $(addsuffix .d,$(GENERATED_SRC_FILES)) \
        $(BUILDDIR)/$(LIBDIR)/lib$(LIBRARY_NAME).a.d \
        $(addsuffix .d,$(OBJFILES))
endif

########################### DISTRIBUTION TARGETS ##############################
###############################################################################

distdir:
	@$(call sub_step_msg,Copying files to temporary directory...)
	rm -rf $(TEMPDIR)
	$(MKDIR) $(TEMPDIR)
	$(CP) $(MAKEFILE_NAME) $(EXTRA_DIST_FILES) $(TEMPDIR)
	$(CP) -r $(SRCDIR) $(ETCDIR) $(UTILSDIR) $(DOCUMENTDIR) $(TEMPDIR)

windistdir: $(patsubst $(SRCDIR)/%.$(YACCFILEEXT),$(BUILDDIR)/%.$(CCFILEEXT),$(wildcard $(SRCDIR)/*/*.$(YACCFILEEXT))) \
            $(patsubst $(SRCDIR)/%.$(LEXFILEEXT),$(BUILDDIR)/%.$(CCFILEEXT),$(wildcard $(SRCDIR)/*/*.$(LEXFILEEXT))) \
            $(patsubst $(SRCDIR)/%.$(YACCFILEEXT),$(BUILDDIR)/%.h,$(wildcard $(SRCDIR)/*/*.$(YACCFILEEXT)))
	@$(call sub_step_msg,Copying files to temporary directory...)
	rm -rf $(TEMPDIR)
	$(MKDIR) $(TEMPDIR)
	$(CP) $(MAKEFILE_NAME) $(EXTRA_DIST_FILES) $(TEMPDIR)
	$(CP) -r $(SRCDIR) $(ETCDIR) $(UTILSDIR) $(DOCUMENTDIR) $(TEMPDIR)
	$(MKDIR) $(TEMPDIR)/$(BUILDDIR)
	$(CP) $^ $(TEMPDIR)/$(BUILDDIR)
	@$(call sub_step_msg,Converting files to DOS format...)
	@for file in `$(FIND) $(TEMPDIR) -type f`; do \
	  $(UNIX2DOS) $$file 2>/dev/null; \
	done

############################## TESTING TARGETS ################################
###############################################################################

# -----------------------------------------------------------------------------

compiled_tests : lib compiled_tests_message $(COMPILED_TESTS) 
	@$(call main_step_msg,Running compiled tests)
	@export COMPILED_TESTS_PASS="0"; \
	 export COMPILED_TESTS_FAIL="0"; \
	 for test in $(COMPILED_TESTS); do \
	   echo -n $(BACKGROUND); echo -n $(FOREGROUND); echo -n $(CYAN)'> Running test '"$$test... "$(TEXTCOLOR); \
	   if $$test 1> $$test.stdout 2>$$test.stderr ; then \
	     COMPILED_TESTS_PASS=`$(EXPR) $$COMPILED_TESTS_PASS + 1`; \
	     echo PASS; \
	     $(RM) $$test.stdout $$test.stderr; \
	   else \
	     COMPILED_TESTS_FAIL=`$(EXPR) $$COMPILED_TESTS_FAIL + 1`; \
	     echo "FAIL (See $$test.stdout and $$test.stderr)"; \
	   fi; \
	 done; \
         echo $$COMPILED_TESTS_PASS > $(TESTDIR)/COMPILED_TESTS_PASS; \
         echo $$COMPILED_TESTS_FAIL > $(TESTDIR)/COMPILED_TESTS_FAIL

noncompiled_tests : $(PROGS) noncompiled_tests_message $(NONCOMPILED_TESTS)
	@$(call main_step_msg,Running noncompiled tests)
	@export NONCOMPILED_TESTS_PASS="0"; \
	 export NONCOMPILED_TESTS_FAIL="0"; \
	 for test in $(NONCOMPILED_TESTS); do \
	   echo -n $(BACKGROUND); echo -n $(FOREGROUND); echo -n $(CYAN)'> Running test '"$$test... "$(TEXTCOLOR); \
	   if $$test 1>$$test.stdout 2>$$test.stderr ; then \
	     NONCOMPILED_TESTS_PASS=`$(EXPR) $$NONCOMPILED_TESTS_PASS + 1`; \
	     echo PASS; \
	     $(RM) $$test.stdout $$test.stderr; \
	   else \
	     NONCOMPILED_TESTS_FAIL=`$(EXPR) $$NONCOMPILED_TESTS_FAIL + 1`; \
	     echo "FAIL (See $$test.stdout and $$test.stderr)"; \
	   fi; \
	 done; \
         echo $$NONCOMPILED_TESTS_PASS > $(TESTDIR)/NONCOMPILED_TESTS_PASS; \
         echo $$NONCOMPILED_TESTS_FAIL > $(TESTDIR)/NONCOMPILED_TESTS_FAIL

############################## COMPILE TARGETS ################################
###############################################################################

# Cancel the normal implicit rules to make sure we get our own ones
%.o : %.$(CCFILEEXT)
%.o : %.$(CFILEEXT)
%.o : %.$(FFILEEXT)

# Rules to compile .$(CCFILEEXT) files into .o files.
$(BUILDDIR)/%.o : $(SRCDIR)/%.$(CCFILEEXT)
	$(call make_directory,$(shell $(DIRNAME) $@))
	$(CXX) $(CFLAGS) -c $< -o $@

# In case we have .$(CCFILEXT) files generated by other source. (e.g. from lex
# and yacc)
$(BUILDDIR)/%.o : $(BUILDDIR)/%.$(CCFILEEXT)
	$(call make_directory,$(shell $(DIRNAME) $@))
	$(CXX) $(CFLAGS) -c $< -o $@

# Rules to compile .$(CFILEEXT) files into .o files.
$(BUILDDIR)/%.o : $(SRCDIR)/%.$(CFILEEXT)
	$(call make_directory,$(shell $(DIRNAME) $@))
	$(CC) $(CFLAGS) -c $< -o $@

# In case we have .$(CFILEXT) files generated by other source. (e.g. from lex
# and yacc)
$(BUILDDIR)/%.o : $(BUILDDIR)/%.$(CFILEEXT)
	$(call make_directory,$(shell $(DIRNAME) $@))
	$(CC) $(CFLAGS) -c $< -o $@

# Rule to compile .f files into .o files.
$(BUILDDIR)/%.o : $(SRCDIR)/%.f
	$(call make_directory,$(shell $(DIRNAME) $@))
	$(FC) $(FFLAGS) -c $< -o $@

# Rule to compile .$(LEXFILEEXT) files into .$(CCFILEEXT) files.
$(BUILDDIR)/%.$(CCFILEEXT) : $(SRCDIR)/%.$(LEXFILEEXT)
	$(call make_directory,$(shell $(DIRNAME) $@))
	$(LEX) -o$@ $<

# Rule to compile test binaries
$(TESTDIR)/% : $(LIBDIR)/lib$(LIBRARY_NAME).a $(BUILDDIR)/tests/%.o
	$(call make_directory,$(shell $(DIRNAME) $@))
	@$(call sub_step_msg,Making test case $@)
	$(LD) $(LDFLAGS) $(CFLAGS) $(BUILDDIR)/tests/$*.o $(LIB_FLAGS) -o $@

# Rule to copy tests which are scripts
$(TESTDIR)/%.$(SCRIPTFILEEXT) : $(PROGS) $(SRCDIR)/$(TESTDIR)/%.$(SCRIPTFILEEXT)
	$(call make_directory,$(shell $(DIRNAME) $@))
	@$(call sub_step_msg,Copying test case $@)
	$(CP) $(SRCDIR)/$(TESTDIR)/$*.$(SCRIPTFILEEXT) $@
	@$(CHMOD) a+x $@

# Rule to compile non-test binaries
$(PROGDIR)/% : $(LIBDIR)/lib$(LIBRARY_NAME).a $(BUILDDIR)/progs/%.o
	$(call make_directory,$(shell $(DIRNAME) $@))
	@$(call sub_step_msg,Making program $@)
	$(LD) $(LDFLAGS) $(CFLAGS) $(BUILDDIR)/progs/$*.o $(LIB_FLAGS) -o $@

# Rule to create the library
$(LIBDIR)/lib$(LIBRARY_NAME).a : $(call compute_ofiles,$(SRC_DIRS_PATTERN))
	@$(call sub_step_msg,Making library $@)
	@$(call make_directory,$(shell $(DIRNAME) $@))
	@$(AR) rv $@ $^
	@ranlib $@

# Rule to generate parser .$(CCFILEEXT) files from .$(YACCFILEEXT) files
$(BUILDDIR)/%.$(CCFILEEXT) $(BUILDDIR)/%.h : $(SRCDIR)/%.$(YACCFILEEXT)
	$(call make_directory,$(shell $(DIRNAME) $@))
	$(YACC) -p $(notdir $*)_ -d -o $(basename $@).$(CCFILEEXT) $<
	if test -e $(basename $@).$(CCFILEEXT).h ; then \
	  $(MV) $(basename $@).$(CCFILEEXT).h $(basename $@).h; \
	else if test -e $(basename $@).hpp ; then \
	  $(MV) $(make_pattern = \($(subst $(SPACE),\|,$(1))\)