# ;-*-Mode: makefile-*-
#=============================================================================
#
# This is M.pixie, a makefile tail for running pixie and prof on jobs with
# dynamically-loaded objects.  It expects the following to be defined
#
# EXE       Name of executable to profile (uses standard suez as default)
# MAKEFILE  Name of calling makefile (if not standard 'Makefile')
#
# SHLIBS         List of shared libraries that should be instrumented
# SHLIBS_IGNORE  List of shared libraries that will be loaded, but need not
#                be instrumented
#
# SHLIBDIR  Directory where the instrumented objects will be put (default: pwd)
#           (NB: If you're instrumenting many objects, you should probably
#                use the /tem, /stm, or /mtm disk)
#
# DEBUG       must be "y" or "Y" if you want to instrument debug versions
# LINES       must be "y" or "Y" if you want a line-usage profile
# PROCEDURES  must be "y" or "Y" if you want a procedures-usage profile
# ZERO        must be "y" or "Y" if you want prof to report unused procedures
#
# TOOL  Tool for atom (uses pixie as default)
#
# USER_PIXFLAGS   any additional flags you want to pass to atom
# USER_PROFFLAGS  any additional flags you want to pass to prof
#
#
# There are two targets currently supported by this makefile:
#
# pixie  Instrument the files as specified in $(MAKEFILE) (default)
# prof   Profile $(EXE)
#
#
#***************************************************************************
#* Remember to run $(EXE).pixie, loading in the appropriately-instrumented *
#* objects, before profiling!                                              *
#***************************************************************************
#
#=============================================================================

MAKE	:=	gmake
MAKEFILE:=	Makefile

ATOM	:=	/bin/atom
PROF	:=	/bin/prof

ifeq "$(EXE)" ""
  ifneq "$(findstring zfiles,$(shell /bin/echo $(SHLIBS) $(SHLIBS_IGNORE)|/bin/sed 'y/[A-Z]/[a-z]/'))" ""
    EXE := $(C3_BIN)/$(CXX)/suez_zfiles.exe$(USER_G)
  else
    EXE := $(C3_BIN)/$(CXX)/suez.exe$(USER_G)
  endif
endif

ifneq (,$(findstring $(DEBUG),yY))
  USER_G := _g
endif

ifneq (,$(findstring $(LINES),yY))
  PROF_HEAVY := -heavy
  USER_G := _g
endif

ifneq (,$(findstring $(PROCEDURES),yY))
  PROF_PROCEDURES := -procedures
endif

ifneq (,$(findstring $(ZERO),yY))
  PROF_ZERO := -zero
endif

# This appends to whatever the user has set.
LIBDIRS += $(subst :, ,$(C3_SHLIB))
LIBDIRS	+= $(HOME)/lib/$(CXX)
LIBDIRS += $(HOME)/lib/$(shell uname)/$(CXX)
LIBDIRS += $(C3_LIB)/lib/$(shell uname)/$(CXX)

FILES = $(foreach libdir,$(LIBDIRS),$(wildcard $(libdir)/$(SHAR)$(USER_G).so))
SHARFILES := $(foreach SHAR,$(SHLIBS),$(firstword $(FILES)))
SHARFILES_IGNORE := $(foreach SHAR,$(SHLIBS_IGNORE),$(firstword $(FILES)))

OBJLIST		:=	$(patsubst %,-incobj %,$(SHARFILES))
OBJLIST_IGNORE	:=	$(patsubst %,-dynobj %,$(SHARFILES_IGNORE))

DUMP_COMMAND      := odump -Dl -p

# Search for dynamic objects in the instrumented and non-instrumented
# shared objects, as well as the executable.
BURIED_LIBS := $(foreach \
                    lib, \
                    $(SHARFILES) $(SHARFILES_IGNORE) $(EXE), \
                    $(foreach \
                         burlib, \
                         $(filter \
                              lib%, \
                              $(notdir $(shell $(DUMP_COMMAND) $(lib))) \
                          ), \
                         $(burlib) \
                     ) \
                )

BURIED_LIBS_SORT := $(sort $(BURIED_LIBS))
BLIB_SEARCH_PATH += $(C3_LIB)/lib/$(shell uname)/$(CXX) \
                    /usr/shlib \
                    /usr/local/lib
BURIED_LIBS_WITH_PATH := $(foreach \
                              BLIB, \
                              $(BURIED_LIBS_SORT), \
                              $(firstword \
                                   $(foreach \
                                        libdir, \
                                        $(BLIB_SEARCH_PATH), \
                                        $(wildcard $(libdir)/$(BLIB)) \
                                    ) \
                               ) \
                          )

BURIED_PREFIX := -dynobj
ifneq (,$(findstring $(INSTRUMENT_BURIED),yY))
   BURIED_PREFIX := -incobj
endif

BURIED_LIST := $(patsubst %,$(BURIED_PREFIX) %,$(BURIED_LIBS_WITH_PATH))

ifeq "$(SHLIBDIR)" ""
SHLIBDIR := $(shell pwd)
endif

ifeq "$(TOOL)" ""
  TOOL := pixie
endif

ifneq "$(TOOL)" "pixie"
  SPECIAL_COMMAND := /usr/bin/echo "\n********************\n* Do not run prof! *\n********************"
endif

EXE_REAL := $(notdir $(EXE)).$(TOOL)
EXE_IS_SUEZ := $(findstring suez,$(EXE_REAL))
EXE_MAYBE :=
ifneq "$(EXE_IS_SUEZ)" ""
   EXE_MAYBE := $(C3_BIN)/$(CXX)/suez
endif

ifneq "$(NICE_LEVEL)" ""
   NICE := nice -n $(NICE_LEVEL)
endif

# This is a debugging tool.  Every command that does something has
# $(ECHO) in front of it.  "gmake <target> TEST=y" will cause make
# to echo the command rather than running it.  This is different from
# "gmake -n" in very minor, though potentially useful, ways.

ECHO :=
ifneq (,$(findstring $(TEST),yY))
   ECHO := echo
endif

default : pixie

pixie : $(SHARFILES) $(SUEZ_EXE)
	@echo "Putting instrumented shared objects in $(SHLIBDIR)"
	$(ECHO) $(ATOM) -tool $(TOOL) -shlibdir $(SHLIBDIR) $(EXE) $(OBJLIST) \
	$(BURIED_LIST) $(OBJLIST_IGNORE) $(USER_PIXFLAGS)
	@for a in $(SHLIBDIR)/*.so.*.$(TOOL); do \
	$(ECHO) ln -fs $$a $$a.so; done
	@$(SPECIAL_COMMAND)
	@echo "Run instrumented files with:\nenv LD_LIBRARY_PATH=$(SHLIBDIR) $(EXE_MAYBE) $(EXE_REAL)"

run :
	$(ECHO) env LD_LIBRARY_PATH=$(SHLIBDIR) $(NICE) $(EXE_MAYBE) \
	$(EXE_REAL)

prof :
	$(ECHO) $(PROF) -pixie $(PROF_HEAVY) $(PROF_PROCEDURES) $(PROF_ZERO) \
	$(OBJLIST) $(USER_PROFFLAGS) $(EXE)

clean :
	@$(ECHO) rm -f $(SHLIBDIR)/*.so.*.$(TOOL)
	@$(ECHO) rm -f $(SHLIBDIR)/*.so.*.$(TOOL).so
	@$(ECHO) rm -f $(EXE_REAL)
