## ## Makefile for building Erlang applications ## # # useful constants and functions # EMPTY := COMMA :=, exist = $(wildcard $(1)) escape_quote = $(subst ",\",$(1)) to_upper = \ $(subst \ a,A,$(subst \ b,B,$(subst \ c,C,$(subst \ d,D,$(subst \ e,E,$(subst \ f,F,$(subst \ g,G,$(subst \ h,H,$(subst \ i,I,$(subst \ j,J,$(subst \ k,K,$(subst \ l,L,$(subst \ m,M,$(subst \ n,N,$(subst \ o,O,$(subst \ p,P,$(subst \ q,Q,$(subst \ r,R,$(subst \ s,S,$(subst \ t,T,$(subst \ u,U,$(subst \ v,V,$(subst \ w,W,$(subst \ x,X,$(subst \ y,Y,$(subst \ z,Z,$(1))))))))))))))))))))))))))) # # default values # DEFAULT_APP_VSN:=0.0.0 # # directories and files # ENV_MK:=../../env.mk ALT_ENV_MK:=../env.mk VSN_MK:=../vsn.mk APP_MK:=../app.mk SRC_DIR:=. EBIN_DIR:=../ebin INCLUDE_DIR:=../include DOC_DIR:=../doc OVERVIEW_DIR:=$(SRC_DIR) DOC_INDEX:=$(DOC_DIR)/index.html OVERVIEW:=$(OVERVIEW_DIR)/overview.edoc SPECIFIC_MK:=$(SRC_DIR)/specific.mk # # do include # -include $(ENV_MK) -include $(ALT_ENV_MK) -include $(VSN_MK) -include $(APP_MK) # # confirm APP_NAME and APP_VSN # ifndef APP_NAME pwd_url = $(subst $(EMPTY) ,%20,$(subst %,%25,$(shell pwd))) this_path := $(pwd_url) parent_path := $(dir $(this_path)) parent_path_list := $(subst /, ,$(parent_path)) app_name := $(lastword $(parent_path_list)) ifdef app_name APP_NAME := $(app_name) else APP_NAME := $(error Cannot define APP_NAME) # Stop! endif # app_name endif # !APP_NAME # now, APP_NAME is defined! APP_NAME_UPPER := $(call to_upper,$(APP_NAME)) ifndef APP_VSN ifdef $(APP_NAME_UPPER)_VSN APP_VSN:=$($(APP_NAME_UPPER)_VSN) else APP_VSN:=$(DEFAULT_APP_VSN) endif # $(APP_NAME_UPPER)_VSN endif # !APP_VSN # # debug stuffs # ifdef debug DEBUG:=$(debug) endif ifdef DEBUG ERLC_DEBUG_FLAG+=-Ddebug -DDEBUG +debug_info endif # # commands and flags # ERLC:=erlc ERLC_INC_FLAG+=-I $(INCLUDE_DIR) -I $(SRC_DIR) ERLC_FLAGS+= $(ERLC_INC_FLAG) $(ERLC_DEBUG_FLAG) \ $(ERLC_EXTRA_FLAGS) -o $(EBIN_DIR) EDOC_OPTS+={def,{version, "$(APP_VSN)"}}, \ {def,{app_name, "$(APP_NAME)"}}, \ {dir, "$(DOC_DIR)"}, {overview, "$(OVERVIEW)"}, private ifdef EDOC_EXTRA_OPTS ESCAPED_EDOC_OPTS_LIST := \ [$(call escape_quote,$(EDOC_OPTS)$(COMMA) $(EDOC_EXTRA_OPTS))] else ESCAPED_EDOC_OPTS_LIST := \ [$(call escape_quote,$(EDOC_OPTS))] endif # EDOC_EXTRA_OPTS # # sources and targets # -include $(SPECIFIC_MK) ifndef SOURCES SOURCES:=$(filter-out $(SRC_DIR)/tmp%,$(wildcard $(SRC_DIR)/*.erl)) ifdef NOT_SOURCES SOURCES:=$(filter-out $(NOT_SOURCES),$(SOURCES)) endif # NOT_SOURCES endif # !SOURCES ifndef INCLUDES INCLUDES:= \ $(filter-out $(INCLUDE_DIR)/tmp%,$(wildcard $(INCLUDE_DIR)/*.hrl))\ $(filter-out $(SRC_DIR)/tmp%,$(wildcard $(SRC_DIR)/*.hrl)) ifdef NOT_INCLUDES INCLUDES:=$(filter-out $(NOT_INCLUDES),$(INCLUDES)) endif # NOT_INCLUDES endif # !INCLUDES OBJECTS:=$(patsubst $(SRC_DIR)/%.erl, $(EBIN_DIR)/%.beam,$(SOURCES)) # application resource file. APP_TARGET:=$(EBIN_DIR)/$(APP_NAME).app # application upgrade file APPUP_TARGET:=$(EBIN_DIR)/$(APP_NAME).appup app_src_full:=$(SRC_DIR)/$(APP_NAME).app.src app_src_simple:=$(SRC_DIR)/app.src appup_src_full:=$(SRC_DIR)/$(APP_NAME).appup.src appup_src_simple:=$(SRC_DIR)/appup.src APP_SRC:=$(if $(call exist,$(app_src_full)),$(app_src_full),$(app_src_simple)) APPUP_SRC:=$(if $(call exist,$(appup_src_full)),$(appup_src_full),$(appup_src_simple)) TEST_MODS:=$(patsubst $(SRC_DIR)/%.erl,%,$(wildcard $(SRC_DIR)/t_*.erl)) all_mods :=$(patsubst $(SRC_DIR)/%.erl,%,$(SOURCES)) mods:=$(filter-out $(TEST_MODS),$(all_mods)) MODS_COMMA_LIST:=$(subst $(EMPTY) ,$(COMMA) ,$(mods)) # # check doc/overview.edoc # danger := $(if $(call exist,$(DOC_DIR)/overview.edoc),danger,) ifdef danger _exit := $(error Move '$(DOC_DIR)/overview.edoc' to '$(SRC_DIR)/overview.edoc') endif # danger # # main targets # .PHONY: obj doc desc all test obj: $(OBJECTS) doc: $(DOC_INDEX) desc: $(APP_TARGET) $(APPUP_TARGET) all: obj doc desc test: obj @for t in dummy $(TEST_MODS); do \ if [ "$$t" != "dummy" ] ; then \ echo "Test module: $$t"; \ erl -boot start_clean -noshell -pa $(EBIN_DIR) \ -s $$t test \ -s init stop;\ fi \ done # # rules # $(OBJECTS) : $(INCLUDES) # each objct depends on include files. $(OBJECTS) : $(EBIN_DIR)/%.beam : $(SRC_DIR)/%.erl $(ERLC) $(ERLC_FLAGS) $< $(VSN_MK) : echo "$(APP_NAME_UPPER)_VSN = $(APP_VSN)" > $@ $(APP_MK) : echo "APP_NAME = $(APP_NAME)" > $@ echo "ERLC_EXTRA_FLAGS=" >> $@ echo "EDOC_EXTRA_OPTS=" >> $@ echo "DEBUG=" >> $@ $(OVERVIEW) : echo "@title {@app_name}" > $@ echo "@version {@version}" >> $@ $(APP_SRC) : echo "{application, %NAME%," > $@ echo " [{description, \"\"}," >> $@ echo " {vsn, \"%VSN%\"}," >> $@ echo " {modules, [%MODS%]}," >> $@ echo " {registered,[]}," >> $@ echo " {applications, [kernel, stdlib]}]}." >> $@ $(APPUP_SRC) : echo "{\"%VSN%\",[],[]}." > $@ $(DOC_INDEX): $(SOURCES) $(OVERVIEW) $(VSN_MK) $(APP_MK) erl -boot start_clean -noshell \ -eval "edoc:application($(APP_NAME), \"$(SRC_DIR)\", \ $(ESCAPED_EDOC_OPTS_LIST))" \ -s init stop $(APP_TARGET): $(SRC_DIR)/$(APP_SRC) $(VSN_MK) $(APP_MK) sed -e 's;%VSN%;$(APP_VSN);' -e 's;%NAME%;$(APP_NAME);' \ -e 's;%MODS%;$(MODS_COMMA_LIST);' $< > $@ $(APPUP_TARGET): $(APPUP_SRC) $(VSN_MK) $(APP_MK) sed -e 's;%VSN%;$(APP_VSN);' -e 's;%NAME%;$(APP_NAME);' $< > $@ # # other targets # .PHONY: clean doc_clean print_vars clean: -rm -f $(OBJECTS) $(APP_TARGET) $(APPUP_TARGET) -rm -f $(SRC_DIR)/*.beam $(SRC_DIR)/erl_crash.dump doc_clean: -rm -f $(DOC_DIR)/* print_vars: # for debugging Makefile @echo "ERLANG_HOME=$(ERLANG_HOME)" @echo "APP_NAME=$(APP_NAME)" @echo "APP_NAME_UPPER=$(APP_NAME_UPPER)" @echo "APP_VSN=$(APP_VSN)" @echo "SRC_DIR=$(SRC_DIR)" @echo "EBIN_DIR=$(EBIN_DIR)" @echo "INCLUDE_DIR=$(INCLUDE_DIR)" @echo "DOC_DIR=$(DOC_DIR)" @echo "OVERVIEW=$(OVERVIEW)" @echo "DOC_INDEX=$(DOC_INDEX)" @echo "ERLC_FLAGS=$(ERLC_FLAGS)" @echo "SOURCES=$(SOURCES)" @echo "INCLUDES=$(INCLUDES)" @echo "APP_TARGET=$(APP_TARGET)" @echo "APPUP_TARGET=$(APPUP_TARGET)" @echo "APP_SRC=$(APP_SRC)" @echo "APPUP_SRC=$(APPUP_SRC)" @echo "EDOC_OPTS=$(EDOC_OPTS)" @echo "EDOC_EXTRA_OPTS=$(EDOC_EXTRA_OPTS)" @echo "TEST_MODS=$(TEST_MODS)" @echo "MODS_COMMA_LIST=$(MODS_COMMA_LIST)" @echo "DEBUG=$(DEBUG)" # # diagnostics # make_msg = \ $(if $(call exist,$(1)), o $(1), x $(1)) make_msg_var = $(call make_msg,$($1)) MSG_env_mk := $(call make_msg_var,ENV_MK) MSG_alt_env_mk := $(call make_msg_var,ALT_ENV_MK) MSG_vsn_mk := $(call make_msg_var,VSN_MK) MSG_app_mk := $(call make_msg_var,APP_MK) MSG_specific_mk := $(call make_msg,$(SPECIFIC_MK)) MSG_overview := $(call make_msg_var,OVERVIEW) MSG_app_src_full := $(call make_msg_var,app_src_full) MSG_app_src_simple := $(call make_msg_var,app_src_simple) MSG_appup_src_full := $(call make_msg_var,appup_src_full) MSG_appup_src_simple := $(call make_msg_var,appup_src_simple) .PHONY: hints hints: @echo "" @echo FILES: @echo "" @echo "$(MSG_env_mk)" @echo "$(MSG_alt_env_mk)" @echo "$(MSG_vsn_mk) (might be automatically created)" @echo "$(MSG_app_mk) (might be automatically created)" @echo "$(MSG_specific_mk)" @echo "$(MSG_overview)" @echo "$(MSG_app_src_full)" @echo "$(MSG_app_src_simple)" @echo "$(MSG_appup_src_full)" @echo "$(MSG_appup_src_simple)" @echo "" @echo VARS: @echo "" @echo "APP_NAME=$(APP_NAME)" @echo "APP_VSN=$(APP_VSN)" @echo "SOURCES=$(SOURCES)" @echo "NOT_SOURCES=$(NOT_SOURCES)" @echo "INCLUDES=$(INCLUDES)" @echo "NOT_INCLUDES=$(NOT_INCLUDES)" @echo "APP_SRC=$(APP_SRC)" @echo "APPUP_SRC=$(APPUP_SRC)" @echo "MODS_COMMA_LIST=$(MODS_COMMA_LIST)" # # aliases # .PHONY: docclean printvars docclean : doc_clean printvars : print_vars # End