# -*- makefile -*-

ifndef CONTIKI
  ${error CONTIKI not defined! You must specify where Contiki resides}
endif

ifeq ($(TARGET),)
  -include Makefile.target
  ifeq ($(TARGET),)
    ${info TARGET not defined, using target 'native'}
    TARGET=native
  else
    ${info using saved target '$(TARGET)'}
  endif
endif

ifeq ($(DEFINES),)
  -include Makefile.$(TARGET).defines
  ifneq ($(DEFINES),)
    ${info using saved defines '$(DEFINES)'}
  endif
endif

ifndef HOST_OS
  ifeq ($(OS),Windows_NT)
  ## TODO: detect more specific Windows set-ups,
  ## e.g. CygWin, MingW, VisualC, Watcom, Interix
    HOST_OS := Windows
  else
    HOST_OS := $(shell uname)
  endif
endif

usage:
	@echo "make MAKETARGETS... [TARGET=(TARGET)] [savetarget] [targets]"

targets:
	@ls -1 $(CONTIKI)/platform $(TARGETDIRS) | grep -v CVS

savetarget:
	-@rm -f Makefile.target
	@echo "saving Makefile.target"
	@echo >Makefile.target "TARGET = $(TARGET)"

savedefines:
	-@rm -f Makefile.$(TARGET).defines
	@echo "saving Makefile.$(TARGET).defines"
	@echo >Makefile.$(TARGET).defines "DEFINES = $(DEFINES)"

OBJECTDIR = obj_$(TARGET)

LOWERCASE = -abcdefghijklmnopqrstuvwxyz
UPPERCASE = _ABCDEFGHIJKLMNOPQRSTUVWXYZ
TARGET_UPPERCASE := ${strip ${shell echo $(TARGET) | sed y!$(LOWERCASE)!$(UPPERCASE)!}}
CFLAGS += -DCONTIKI=1 -DCONTIKI_TARGET_$(TARGET_UPPERCASE)=1

include $(CONTIKI)/core/net/rime/Makefile.rime
include $(CONTIKI)/core/net/mac/Makefile.mac
SYSTEM  = process.c procinit.c autostart.c elfloader.c profile.c \
          timetable.c timetable-aggregate.c compower.c serial-line.c
THREADS = mt.c
LIBS    = memb.c mmem.c timer.c list.c etimer.c ctimer.c energest.c rtimer.c stimer.c trickle-timer.c \
          print-stats.c ifft.c crc16.c random.c checkpoint.c ringbuf.c settings.c
DEV     = nullradio.c

include $(CONTIKI)/core/net/Makefile.uip
include $(CONTIKI)/core/net/rpl/Makefile.rpl

CTK     = ctk.c
CTKVNC  = $(CTK) ctk-vncserver.c libconio.c vnc-server.c vnc-out.c ctk-vncfont.c

ifndef CONTIKI_NO_NET
  CONTIKIFILES = $(SYSTEM) $(LIBS) $(NET) $(THREADS) $(DHCP) $(DEV)
else
  CONTIKIFILES = $(SYSTEM) $(LIBS) $(THREADS) $(DEV) sicslowpan.c fakeuip.c
endif

CONTIKI_SOURCEFILES += $(CONTIKIFILES)

CONTIKIDIRS += ${addprefix $(CONTIKI)/core/,dev lib net net/mac net/rime \
                 net/rpl sys cfs ctk lib/ctk loader . }

oname = ${patsubst %.c,%.o,${patsubst %.S,%.o,$(1)}}

CONTIKI_OBJECTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(CONTIKI_SOURCEFILES)}}

PROJECT_OBJECTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(PROJECT_SOURCEFILES)}}

# Provide way to create $(OBJECTDIR) if it has been removed by make clean
$(OBJECTDIR):
	mkdir $@

### Include application makefiles

ifdef APPS
  APPDS = ${wildcard ${foreach DIR, $(APPDIRS), ${addprefix $(DIR)/, $(APPS)}}} \
             ${wildcard ${addprefix $(CONTIKI)/apps/, $(APPS)} \
             ${addprefix $(CONTIKI)/platform/$(TARGET)/apps/, $(APPS)} \
             $(APPS)}
  APPINCLUDES = ${foreach APP, $(APPS), ${wildcard ${foreach DIR, $(APPDS), $(DIR)/Makefile.$(APP)}}}
  -include $(APPINCLUDES)
  APP_SOURCES = ${foreach APP, $(APPS), $($(APP)_src)}
  DSC_SOURCES = ${foreach APP, $(APPS), $($(APP)_dsc)}
  CONTIKI_SOURCEFILES += $(APP_SOURCES) $(DSC_SOURCES)
endif

### Include target makefile (TODO Unsafe?)

target_makefile := $(wildcard $(CONTIKI)/platform/$(TARGET)/Makefile.$(TARGET) ${foreach TDIR, $(TARGETDIRS), $(TDIR)/$(TARGET)/Makefile.$(TARGET)})

# Check if the target makefile exists, and create the object directory if necessary.
ifeq ($(strip $(target_makefile)),)
  ${error The target platform "$(TARGET)" does not exist (maybe it was misspelled?)}
else
  ifneq (1, ${words $(target_makefile)})
    ${error More than one TARGET Makefile found: $(target_makefile)}
  endif
  include $(target_makefile)
endif

ifdef PLATFORMAPPS
  PLATFORMAPPDS = ${wildcard ${foreach DIR, $(APPDIRS), ${addprefix $(DIR)/, $(PLATFORMAPPS)}}} \
             ${wildcard ${addprefix $(CONTIKI)/apps/, $(PLATFORMAPPS)} \
             ${addprefix $(CONTIKI)/platform/$(TARGET)/apps/, $(PLATFORMAPPS)} \
             $(PLATFORMAPPS)}
  PLATFORMAPPINCLUDES = ${foreach APP, $(PLATFORMAPPS), \
      ${wildcard ${foreach DIR, $(PLATFORMAPPDS), $(DIR)/Makefile.$(APP)}}}
  -include $(PLATFORMAPPINCLUDES)
  PLATFORMAPP_SOURCES = ${foreach APP, $(PLATFORMAPPS), $($(APP)_src)}
  CONTIKI_SOURCEFILES += $(PLATFORMAPP_SOURCES)
  APPDS += $(PLATFORMAPPDS)
endif

### Verbosity control. Use  make V=1  to get verbose builds.

ifeq ($(V),1)
  TRACE_CC =
  TRACE_LD =
  TRACE_AR =
  TRACE_AS =
  Q=
else
  TRACE_CC = @echo "  CC       " $<
  TRACE_LD = @echo "  LD       " $@
  TRACE_AR = @echo "  AR       " $@
  TRACE_AS = @echo "  AS       " $<
  Q=@
endif

### Forward comma-separated list of arbitrary defines to the compiler

COMMA := ,
CFLAGS += ${addprefix -D,${subst $(COMMA), ,$(DEFINES)}}

### Setup directory search path for source and header files

CONTIKI_TARGET_DIRS_CONCAT = ${addprefix ${dir $(target_makefile)}, \
                               $(CONTIKI_TARGET_DIRS)}
CONTIKI_CPU_DIRS_CONCAT    = ${addprefix $(CONTIKI_CPU)/, \
                               $(CONTIKI_CPU_DIRS)}

SOURCEDIRS = . $(PROJECTDIRS) $(CONTIKI_TARGET_DIRS_CONCAT) \
             $(CONTIKI_CPU_DIRS_CONCAT) $(CONTIKIDIRS) $(APPDS) ${dir $(target_makefile)}

vpath %.c $(SOURCEDIRS)
vpath %.S $(SOURCEDIRS)

CFLAGS += ${addprefix -I,$(SOURCEDIRS)}

### Check for a git repo and pass version if found
### git.exe in Windows cmd shells may require no stderr redirection
#RELSTR=${shell git describe --tags}
RELSTR=${shell git describe --tags 2>/dev/null}
ifneq ($(RELSTR),)
CFLAGS += -DCONTIKI_VERSION_STRING=\"Contiki-$(RELSTR)\"
endif

### Automatic dependency generation

ifneq ($(MAKECMDGOALS),clean)
-include ${addprefix $(OBJECTDIR)/,$(CONTIKI_SOURCEFILES:.c=.d) \
                                   $(PROJECT_SOURCEFILES:.c=.d)}
endif

### See http://make.paulandlesley.org/autodep.html#advanced

define FINALIZE_DEPENDENCY
cp $(@:.o=.d) $(@:.o=.$$$$); \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
    -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.$$$$) >> $(@:.o=.d); \
rm -f $(@:.o=.$$$$)
endef

clean:
	rm -f *~ *core core *.srec \
	*.lst *.map \
	*.cprg *.bin *.data contiki*.a *.firmware core-labels.S *.ihex *.ini \
	*.ce *.co
	rm -rf $(CLEAN)
	-rm -rf $(OBJECTDIR)

distclean: clean
	-rm -rf $(CONTIKI_PROJECT).$(TARGET)

ifndef CUSTOM_RULE_C_TO_CE
%.ce: %.c
	$(TRACE_CC)
	$(Q)$(CC) $(CFLAGS) -DAUTOSTART_ENABLE -c $< -o $@
	$(STRIP) --strip-unneeded -g -x $@
endif

ifndef CUSTOM_RULE_C_TO_OBJECTDIR_O
$(OBJECTDIR)/%.o: %.c | $(OBJECTDIR)
	$(TRACE_CC)
	$(Q)$(CC) $(CFLAGS) -MMD -c $< -o $@
	@$(FINALIZE_DEPENDENCY)
endif

ifndef CUSTOM_RULE_S_TO_OBJECTDIR_O
$(OBJECTDIR)/%.o: %.S | $(OBJECTDIR)
	$(TRACE_AS)
	$(Q)$(AS) $(ASFLAGS) -o $@ $<
endif

ifndef CUSTOM_RULE_C_TO_O
%.o: %.c
	$(TRACE_CC)
	$(Q)$(CC) $(CFLAGS) -c $< -o $@
endif


ifndef CUSTOM_RULE_C_TO_CO
%.co: %.c
	$(TRACE_CC)
	$(Q)$(CC) $(CFLAGS) -DAUTOSTART_ENABLE -c $< -o $@
endif

ifndef AROPTS
  AROPTS = rcf
endif

ifndef CUSTOM_RULE_ALLOBJS_TO_TARGETLIB
contiki-$(TARGET).a: $(CONTIKI_OBJECTFILES)
	$(TRACE_AR)
	$(Q)$(AR) $(AROPTS) $@ $^
endif

ifndef LD
  LD = $(CC)
endif

ifndef CUSTOM_RULE_LINK
%.$(TARGET): %.co $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) contiki-$(TARGET).a
	$(TRACE_LD)
	$(Q)$(LD) $(LDFLAGS) $(TARGET_STARTFILES) ${filter-out %.a,$^} \
	    ${filter %.a,$^} $(TARGET_LIBFILES) -o $@
endif

%.ramprof: %.$(TARGET)
	$(NM) -S -td --size-sort $< | grep -i " [abdrw] " | cut -d' ' -f2,4

%.flashprof: %.$(TARGET)
	$(NM) -S -td --size-sort $< | grep -i " [t] " | cut -d' ' -f2,4

# Don't treat %.$(TARGET) as an intermediate file because it is
# in fact the primary target.
.PRECIOUS: %.$(TARGET)

# Cancel the predefined implict rule for compiling and linking
# a single C source into a binary to force GNU make to consider
# the match-anything rule below instead.
%: %.c

# Match-anything pattern rule to allow the project makefiles to
# abstract from the actual binary name. It needs to contain some
# command in order to be a rule, not just a prerequisite.
%: %.$(TARGET)
	@