
# /*@@
#   @file    make.config.rules.in
#   @date    Sun Jan 17 22:31:16 1999
#   @author  Tom Goodale
#   @desc
#            Rules to generate object files from source files in another
#            directory.
#
#            Note that, due to the (IMHO) rather bizarre way in which Make
#            deals with directories in the target names, this will
#            not work if the target is in a subdirectory.
#
#            In order to accomodate Fortran 90 modules, the working directory
#            for each compilation is set to a scratch directory, so that
#            all module files end up there.
#   @enddesc
#   @version $Header$
# @@*/

# Dividers to make the screen output slightly nicer
DIVEL   =  __________________
DIVIDER =  $(DIVEL)$(DIVEL)$(DIVEL)$(DIVEL)

#####################################################################
# Shortcuts.

INCLUDE_LINE   = $(patsubst %,-I"%",$(call TRANSFORM_DIRS,$(INC_DIRS)))
INCLUDE_LINE_F = $(patsubst %,-I"%",$(call TRANSFORM_DIRS,$(INC_DIRS_F)))
PRINTTIME      = perl -e 'eval { require("Time/HiRes.pm"); print(&Time::HiRes::gettimeofday()+0," "); }; if($$@) { print time(); }'

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

ifeq ($(shell echo $(VERBOSE) | tr '[:upper:]' '[:lower:]'),yes)
define NOTIFY_PREPROCESSING
	@$(PRINTTIME)
	@echo Preprocessing $<
endef
define NOTIFY_COPYING
	@$(PRINTTIME)
	@echo Copying $<
endef
define NOTIFY_COMPILING
	@$(PRINTTIME)
	@echo Compiling $<
endef
define NOTIFY_POSTPROCESSING
	@$(PRINTTIME)
	@echo Postprocessing $<
endef
define NOTIFY_DIVIDER
	@echo $(DIVIDER)
endef
else
define NOTIFY_PREPROCESSING
endef
define NOTIFY_COPYING
endef
define NOTIFY_COMPILING
	@echo COMPILING $(subst $(CCTK_HOME)/,,$(subst $(CCTK_HOME)/src/,Cactus/,$(subst $(CCTK_HOME)/arrangements/,,$<)))
endef
define NOTIFY_POSTPROCESSING
endef
define NOTIFY_DIVIDER
endef
endif

# Define how to do dependencies.
# Correct the dependency target (i.e. the item on the LHS of a make
# rule). The name of the object file is wrong, and the dependency file
# (.d file) is missing. To simplify things, we don't try to match the
# object file name -- we assume that any file ending in .o is the
# object file.
ifeq ($(strip $(PERL_BACKUP_NECESSARY)),)
define DEPENDENCY_FIXER
	$(PERL) -pi -e 's{^\s*\Q$(basename $(basename $@)).o\E\s*:}{$(basename $@).o $(basename $@).d:};\
                        s{\s+\S*[/\\]($(DEP_EXCLUDE_FILES))\b}{}g' $@
endef
else
define DEPENDENCY_FIXER
	$(PERL) -pi.bak -e 's{^\Q$(basename $(basename $@)).o:\E}{$(basename $@).o $(basename $@).d:}\
                            s{\s+\S*[/\\]($(DEP_EXCLUDE_FILES))\b}{}g' $@
	rm $@.bak
endef
endif

define C_DEPENDENCIES
	$(C_DEPEND) $< $(INCLUDE_LINE) $(EXTRA_DEFINES:%=-D%) -DCCODE $(C_DEPEND_OUT)
	$(DEPENDENCY_FIXER)
endef

define CXX_DEPENDENCIES
	$(CXX_DEPEND) $< $(INCLUDE_LINE) $(EXTRA_DEFINES:%=-D%) -DCCODE $(CXX_DEPEND_OUT)
	$(DEPENDENCY_FIXER)
endef

define CUCC_DEPENDENCIES
        $(CUCC_DEPEND) $< $(INCLUDE_LINE) $(EXTRA_DEFINES:%=-D%) -DCCODE $(CUCC_DEPEND_OUT)
        $(DEPENDENCY_FIXER)
endef

define CL_DEPENDENCIES
# An OpenCL source file has no external dependencies
	$(CL_DEPEND) $< $(CL_DEPEND_OUT)
	$(DEPENDENCY_FIXER)
endef

define F77_DEPENDENCIES
	$(F77_DEPEND) $(INCLUDE_LINE_F) $(EXTRA_DEFINES:%=-D%) -DFCODE -DF90CODE $< $(F77_DEPEND_OUT)
	$(DEPENDENCY_FIXER)
endef

define F_DEPENDENCIES
	$(F_DEPEND) $(INCLUDE_LINE_F) $(EXTRA_DEFINES:%=-D%) -DFCODE -DF90CODE $< $(F_DEPEND_OUT)
	$(DEPENDENCY_FIXER)
	current_wd=`$(GET_WD)` ; { if test $(F_LINE_DIRECTIVES) = 'yes'; then echo '#line 1 "'$<'"'; fi; cat $<; } | $(PERL) -p -e 's.//.CCTK_AUTOMATICALLY_GENERATED_CONCATENATION_PROTECTION.g' | $(FPP) $(FPPFLAGS) $(INCLUDE_LINE_F) $(EXTRA_DEFINES:%=-D%) -DFCODE -DF90CODE | $(PERL) -p -e 's.CCTK_AUTOMATICALLY_GENERATED_CONCATENATION_PROTECTION.//.g' | $(PERL) $(F_DEPEND_MODULES) $< $(basename $(notdir $<)).F.o $(SRCDIR) $(USESTHORNS:%=$$current_wd/../%) $(F_DEPEND_MODULES_OUT) || { rm $@; exit 1; }
endef

define F90_DEPENDENCIES
	$(F_DEPEND) $(INCLUDE_LINE_F) $(EXTRA_DEFINES:%=-D%) -DFCODE -DF90CODE $< $(F_DEPEND_OUT)
	$(DEPENDENCY_FIXER)
	current_wd=`$(GET_WD)` ; { if test $(F_LINE_DIRECTIVES) = 'yes'; then echo '#line 1 "'$<'"'; fi; cat $<; } | $(PERL) -p -e 's.//.CCTK_AUTOMATICALLY_GENERATED_CONCATENATION_PROTECTION.g' | $(FPP) $(FPPFLAGS) $(INCLUDE_LINE_F) $(EXTRA_DEFINES:%=-D%) -DFCODE -DF90CODE | $(PERL) -p -e 's.CCTK_AUTOMATICALLY_GENERATED_CONCATENATION_PROTECTION.//.g' | $(PERL) $(F_DEPEND_MODULES) $< $(basename $(notdir $<)).F90.o $(SRCDIR) $(USESTHORNS:%=$$current_wd/../%) $(F_DEPEND_MODULES_OUT) || { rm $@; exit 1; }
endef

# No preprocessing, just create empty dependency file
# Some file systems only update the file modifcation date if something is
# actually written, so "true >$@" won't work.
define f77_DEPENDENCIES
	echo "" > $@
	current_wd=`$(GET_WD)` ; cat $< | $(PERL) $(F_DEPEND_MODULES) $< $(basename $(notdir $<)).f77.o $(SRCDIR) $(USESTHORNS:%=$$current_wd/../%) $(F_DEPEND_MODULES_OUT) || { rm $@; exit 1; }
endef

define f_DEPENDENCIES
	echo "" > $@
	current_wd=`$(GET_WD)` ; cat $< | $(PERL) $(F_DEPEND_MODULES) $< $(basename $(notdir $<)).f.o $(SRCDIR) $(USESTHORNS:%=$$current_wd/../%) $(F_DEPEND_MODULES_OUT) || { rm $@; exit 1; }
endef

define f90_DEPENDENCIES
	echo "" > $@
	current_wd=`$(GET_WD)` ; cat $< | $(PERL) $(F_DEPEND_MODULES) $< $(basename $(notdir $<)).f90.o $(SRCDIR) $(USESTHORNS:%=$$current_wd/../%) $(F_DEPEND_MODULES_OUT) || { rm $@; exit 1; }
endef



# Define how to do a C compilation
define PREPROCESS_C
{ if test $(C_LINE_DIRECTIVES) = 'yes'; then echo '#line 1 "'$<'"'; fi; cat $<; } | $(PERL) -s $(C_FILE_PROCESSOR) -line_directives=$(C_LINE_DIRECTIVES) -source_file_name=$< $(CONFIG) > $(notdir $<)
endef

define COMPILE_C
current_wd=`$(GET_WD)` ; cd $(SCRATCH_BUILD) ; $(CC) $(CPPFLAGS) $(CFLAGS) $(CCOMPILEONLY)$(OPTIONSEP)$$current_wd$(DIRSEP)$@ $$current_wd$(DIRSEP)$(notdir $<) $(INCLUDE_LINE) $(EXTRA_DEFINES:%=-D%) -DCCODE
endef

define POSTPROCESS_C
$(C_POSTPROCESSING)
endef

# Define how to do a C++ compilation
define PREPROCESS_CXX
{ if test $(C_LINE_DIRECTIVES) = 'yes'; then echo '#line 1 "'$<'"'; fi; cat $<; } | $(PERL) -s $(C_FILE_PROCESSOR) -line_directives=$(C_LINE_DIRECTIVES) -source_file_name=$< $(CONFIG) > $(CXX_WORKING_NAME)
endef

define COMPILE_CXX
current_wd=`$(GET_WD)` ; cd $(SCRATCH_BUILD) ; $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(CCOMPILEONLY)$(OPTIONSEP)$$current_wd$(DIRSEP)$@ $$current_wd$(DIRSEP)$(CXX_WORKING_NAME) $(INCLUDE_LINE) $(EXTRA_DEFINES:%=-D%) -DCCODE
endef

define POSTPROCESS_CXX
$(CXX_POSTPROCESSING)
endef

# Define how to do an OpenCL compilation
define PREPROCESS_CL
# Wrap the OpenCL source code into a string, using the thorn name and
# file name to create a variable name, and create a C file
{								\
    echo 'char const *const OpenCL_source_$(THORN)_$* =';	\
    sed -e 's/\\/\\\\/g;s/"/\\"/g;s/\(.*\)/"\1\\n"/g';		\
    echo ';';							\
} < $^ > $(notdir $<).c
endef

define COMPILE_CL
# Basically a C compile, but with a different source file name
current_wd=`$(GET_WD)` ; cd $(SCRATCH_BUILD) ; $(CC) $(CPPFLAGS) $(CFLAGS) $(CCOMPILEONLY)$(OPTIONSEP)$$current_wd$(DIRSEP)$@ $$current_wd$(DIRSEP)$(notdir $<).c $(INCLUDE_LINE) $(EXTRA_DEFINES:%=-D%) -DCCODE
endef

define POSTPROCESS_CL
$(CL_POSTPROCESSING)
endef

# Define how to do a CUDA compilation
define PREPROCESS_CU
{ if test $(C_LINE_DIRECTIVES) = 'yes'; then echo '#line 1 "'$<'"'; fi; cat $<; } | $(PERL) -s $(C_FILE_PROCESSOR) -line_directives=$(C_LINE_DIRECTIVES) -source_file_name=$< $(CONFIG) > $(notdir $<)
endef

define COMPILE_CU
current_wd=`$(GET_WD)` ; cd $(SCRATCH_BUILD) ; $(CUCC) $(CUCCFLAGS) $(CCOMPILEONLY)$(OPTIONSEP)$$current_wd$(DIRSEP)$@ $$current_wd$(DIRSEP)$(notdir $<) $(INCLUDE_LINE) $(EXTRA_DEFINES:%=-D%) -DCCODE 
endef

define POSTPROCESS_CU
$(CUCC_POSTPROCESSING)
endef

# Define how to do a F77 compilation
# Note: We compile this file as Fortran 90
define PREPROCESS_F77
{ if test $(F_LINE_DIRECTIVES) = 'yes'; then echo '#line 1 "'$<'"'; fi; cat $<; } | $(PERL) -p -e 's.//.CCTK_AUTOMATICALLY_GENERATED_CONCATENATION_PROTECTION.g' | $(FPP) $(FPPFLAGS) $(INCLUDE_LINE_F) $(EXTRA_DEFINES:%=-D%) -DFCODE -DF90CODE | $(PERL) -p -e 's.CCTK_AUTOMATICALLY_GENERATED_CONCATENATION_PROTECTION.//.g' | $(PERL) -p -e 's/__FORTRANFILE__/\"$(basename $(notdir $<)).F77\"/g' | $(PERL) -s $(F_FILE_PROCESSOR) -line_directives=$(F_LINE_DIRECTIVES) -source_file_name=$< > $(basename $(notdir $<)).f
endef

define COMPILE_F77
current_wd=`$(GET_WD)` ; cd $(SCRATCH_BUILD) ; $(F77) $(F77FLAGS) $(FCOMPILEONLY)$(OPTIONSEP)$$current_wd$(DIRSEP)$@ $$current_wd$(DIRSEP)$(basename $(notdir $<)).f
endef

define POSTPROCESS_F77
$(F77_POSTPROCESSING)
endef

# Define how to do a fixed-format F90 compilation
define PREPROCESS_F
{ if test $(F_LINE_DIRECTIVES) = 'yes'; then echo '#line 1 "'$<'"'; fi; cat $<; } | $(PERL) -p -e 's.//.CCTK_AUTOMATICALLY_GENERATED_CONCATENATION_PROTECTION.g' | $(FPP) $(FPPFLAGS) $(INCLUDE_LINE_F) $(EXTRA_DEFINES:%=-D%) -DFCODE -DF90CODE | $(PERL) -p -e 's.CCTK_AUTOMATICALLY_GENERATED_CONCATENATION_PROTECTION.//.g' | $(PERL) -p -e 's/__FORTRANFILE__/\"$(basename $(notdir $<)).F\"/g' | $(PERL) -s $(F_FILE_PROCESSOR) -line_directives=$(F_LINE_DIRECTIVES) -source_file_name=$< > $(basename $(notdir $<)).f
endef

define COMPILE_F
current_wd=`$(GET_WD)` ; cd $(SCRATCH_BUILD) ; $(F90) $(F90FLAGS) $(INCLUDE_LINE_F) $(FCOMPILEONLY)$(OPTIONSEP)$$current_wd$(DIRSEP)$@ $$current_wd$(DIRSEP)$(basename $(notdir $<)).f
endef

define POSTPROCESS_F
$(F_POSTPROCESSING)
endef

# Define how to do a free-format F90 compilation
define PREPROCESS_F90
{ if test $(F_LINE_DIRECTIVES) = 'yes'; then echo '#line 1 "'$<'"'; fi; cat $<; } | $(PERL) -p -e 's.//.CCTK_AUTOMATICALLY_GENERATED_CONCATENATION_PROTECTION.g' | $(FPP) $(FPPFLAGS) $(INCLUDE_LINE_F) $(EXTRA_DEFINES:%=-D%) -DFCODE -DF90CODE | $(PERL) -p -e 's.CCTK_AUTOMATICALLY_GENERATED_CONCATENATION_PROTECTION.//.g' | $(PERL) -p -e 's/__FORTRANFILE__/\"$(basename $(notdir $<)).F90\"/g' | $(PERL) -s $(F_FILE_PROCESSOR) -free_format -line_directives=$(F_LINE_DIRECTIVES) -source_file_name=$< > $(basename $(notdir $<)).$(F90_SUFFIX)
endef

define COMPILE_F90
current_wd=`$(GET_WD)` ; cd $(SCRATCH_BUILD) ; $(F90) $(F90FLAGS) $(INCLUDE_LINE_F) $(FCOMPILEONLY)$(OPTIONSEP)$$current_wd$(DIRSEP)$@ $$current_wd$(DIRSEP)$(basename $(notdir $<)).$(F90_SUFFIX)
endef

define POSTPROCESS_F90
$(F90_POSTPROCESSING)
endef

# Define how to do a f77 compilation
define PREPROCESS_f77
cat $< > $(basename $(notdir $<)).f
endef

# Define how to do a f compilation
define PREPROCESS_f
cat $< > $(basename $(notdir $<)).f
endef

# Define how to do a f90 compilation
define PREPROCESS_f90
cat $< > $(basename $(notdir $<)).$(F90_SUFFIX)
endef



# Build rules for C

%.c.o: $(SRCDIR)/%.c
	$(NOTIFY_PREPROCESSING)
	$(PREPROCESS_C)
	$(NOTIFY_COMPILING)
	$(COMPILE_C)
	$(NOTIFY_POSTPROCESSING)
	$(POSTPROCESS_C)
	$(NOTIFY_DIVIDER)

%.c.d: $(SRCDIR)/%.c
	$(C_DEPENDENCIES)

# Build rules for C++

%.cc.o: $(SRCDIR)/%.cc
	$(NOTIFY_PREPROCESSING)
	$(PREPROCESS_CXX)
	$(NOTIFY_COMPILING)
	$(COMPILE_CXX)
	$(NOTIFY_POSTPROCESSING)
	$(POSTPROCESS_CXX)
	$(NOTIFY_DIVIDER)

%.cc.d: $(SRCDIR)/%.cc
	$(CXX_DEPENDENCIES)

%.C.o: $(SRCDIR)/%.C
	$(NOTIFY_PREPROCESSING)
	$(PREPROCESS_CXX)
	$(NOTIFY_COMPILING)
	$(COMPILE_CXX)
	$(NOTIFY_POSTPROCESSING)
	$(POSTPROCESS_CXX)
	$(NOTIFY_DIVIDER)

%.C.d: $(SRCDIR)/%.C
	$(CXX_DEPENDENCIES)

%.cpp.o: $(SRCDIR)/%.cpp
	$(NOTIFY_PREPROCESSING)
	$(PREPROCESS_CXX)
	$(NOTIFY_COMPILING)
	$(COMPILE_CXX)
	$(NOTIFY_POSTPROCESSING)
	$(POSTPROCESS_CXX)
	$(NOTIFY_DIVIDER)


%.cpp.d: $(SRCDIR)/%.cpp
	$(CXX_DEPENDENCIES)

%.cxx.o: $(SRCDIR)/%.cxx
	$(NOTIFY_PREPROCESSING)
	$(PREPROCESS_CXX)
	$(NOTIFY_COMPILING)
	$(COMPILE_CXX)
	$(NOTIFY_POSTPROCESSING)
	$(POSTPROCESS_CXX)
	$(NOTIFY_DIVIDER)

%.cxx.d: $(SRCDIR)/%.cxx
	$(CXX_DEPENDENCIES)

# Build rules for OpenCL

%.cl.o: $(SRCDIR)/%.cl
	$(NOTIFY_PREPROCESSING)
	$(PREPROCESS_CL)
	$(NOTIFY_COMPILING)
	$(COMPILE_CL)
	$(NOTIFY_POSTPROCESSING)
	$(POSTPROCESS_CL)
	$(NOTIFY_DIVIDER)

%.cl.d: $(SRCDIR)/%.cl
	$(CL_DEPENDENCIES)

# Build rules for CUDA

%.cu.o: $(SRCDIR)/%.cu
	$(NOTIFY_PREPROCESSING)
	$(PREPROCESS_CU)
	$(NOTIFY_COMPILING)
	$(COMPILE_CU)
	$(NOTIFY_POSTPROCESSING)
	$(POSTPROCESS_CU)
	$(NOTIFY_DIVIDER)

%.cu.d: $(SRCDIR)/%.cu
	$(CUCC_DEPENDENCIES)

# Build rules for F77

%.F77.o: $(SRCDIR)/%.F77
	$(NOTIFY_PREPROCESSING)
	$(PREPROCESS_F77)
	$(NOTIFY_COMPILING)
	$(COMPILE_F77)
	$(NOTIFY_POSTPROCESSING)
	$(POSTPROCESS_F77)
	$(NOTIFY_DIVIDER)

%.f77.o: $(SRCDIR)/%.f77
	$(NOTIFY_COPYING)
	$(PREPROCESS_f77)
	$(NOTIFY_COMPILING)
	$(COMPILE_F77)
	$(NOTIFY_POSTPROCESSING)
	$(POSTPROCESS_F77)
	$(NOTIFY_DIVIDER)

%.F77.d: $(SRCDIR)/%.F77
	$(F77_DEPENDENCIES)

%.f77.d: $(SRCDIR)/%.f77
	$(f77_DEPENDENCIES)

# Build rules for F90

%.F.o: $(SRCDIR)/%.F
	$(NOTIFY_PREPROCESSING)
	$(PREPROCESS_F)
	$(NOTIFY_COMPILING)
	$(COMPILE_F)
	$(NOTIFY_POSTPROCESSING)
	$(POSTPROCESS_F)
	$(NOTIFY_DIVIDER)

%.f.o: $(SRCDIR)/%.f
	$(NOTIFY_COPYING)
	$(PREPROCESS_f)
	$(NOTIFY_COMPILING)
	$(COMPILE_F)
	$(NOTIFY_POSTPROCESSING)
	$(POSTPROCESS_F)
	$(NOTIFY_DIVIDER)

%.F.d: $(SRCDIR)/%.F
	$(F_DEPENDENCIES)

%.f.d: $(SRCDIR)/%.f
	$(f_DEPENDENCIES)

# Build rules for free-format F90

%.F90.o: $(SRCDIR)/%.F90
	$(NOTIFY_PREPROCESSING)
	$(PREPROCESS_F90)
	$(NOTIFY_COMPILING)
	$(COMPILE_F90)
	$(NOTIFY_POSTPROCESSING)
	$(POSTPROCESS_F90)
	$(NOTIFY_DIVIDER)

%.f90.o: $(SRCDIR)/%.f90
	$(NOTIFY_COPYING)
	$(PREPROCESS_f90)
	$(NOTIFY_COMPILING)
	$(COMPILE_F90)
	$(NOTIFY_POSTPROCESSING)
	$(POSTPROCESS_F90)
	$(NOTIFY_DIVIDER)

%.F90.d: $(SRCDIR)/%.F90
	$(F90_DEPENDENCIES)

%.f90.d: $(SRCDIR)/%.f90
	$(f90_DEPENDENCIES)
