Example 9-1 shows a generic makefile for Java; I'll explain each of its parts later in the chapter. Example 9-1. Generic makefile for Java # A generic makefile for a Java project. VERSION_NUMBER := 1.0 # Location of trees. SOURCE_DIR := src OUTPUT_DIR := classes # Unix tools AWK := awk FIND := /bin/find MKDIR := mkdir -p RM := rm -rf SHELL := /bin/bash # Path to support tools JAVA_HOME := /opt/j2sdk1.4.2_03 AXIS_HOME := /opt/axis-1_1 TOMCAT_HOME := /opt/jakarta-tomcat-5.0.18 XERCES_HOME := /opt/xerces-1_4_4 JUNIT_HOME := /opt/junit3.8.1 # Java tools JAVA := $(JAVA_HOME)/bin/java JAVAC := $(JAVA_HOME)/bin/javac JFLAGS := -sourcepath $(SOURCE_DIR) \ -d $(OUTPUT_DIR) \ -source 1.4 JVMFLAGS := -ea \ -esa \ -Xfuture JVM := $(JAVA) $(JVMFLAGS) JAR := $(JAVA_HOME)/bin/jar JARFLAGS := cf JAVADOC := $(JAVA_HOME)/bin/javadoc JDFLAGS := -sourcepath $(SOURCE_DIR) \ -d $(OUTPUT_DIR) \ -link http://java.sun.com/products/jdk/1.4/docs/api # Jars COMMONS_LOGGING_JAR := $(AXIS_HOME)/lib/commons-logging.jar LOG4J_JAR := $(AXIS_HOME)/lib/log4j-1.2.8.jar XERCES_JAR := $(XERCES_HOME)/xerces.jar JUNIT_JAR := $(JUNIT_HOME)/junit.jar # Set the Java classpath class_path := OUTPUT_DIR \ XERCES_JAR \ COMMONS_LOGGING_JAR \ LOG4J_JAR \ JUNIT_JAR # space - A blank space space := $(empty) $(empty) # $(call build-classpath, variable-list) define build-classpath $(strip \ $(patsubst :%,%, \ $(subst : ,:, \ $(strip \ $(foreach j,,$(call get-file,$j):))))) endef # $(call get-file, variable-name) define get-file $(strip \ $() \ $(if $(call file-exists-eval,),, \ $(warning The file referenced by variable \ '' ($()) cannot be found))) endef # $(call file-exists-eval, variable-name) define file-exists-eval $(strip \ $(if $(),,$(warning '' has no value)) \ $(wildcard $())) # $(call brief-help, makefile) define brief-help $(AWK) '$ ~ /^[^.][-A-Za-z0-9]*:/ \ { print substr($, 1, length($)-1) }' \ sort \ pr -T -w 80 -4 endef # $(call file-exists, wildcard-pattern) file-exists = $(wildcard ) # $(call check-file, file-list) define check-file $(foreach f, , \ $(if $(call file-exists, $($f)),, \ $(warning $f ($($f)) is missing))) endef # #(call make-temp-dir, root-opt) define make-temp-dir mktemp -t $(if ,,make).XXXXXXXXXX endef # MANIFEST_TEMPLATE - Manifest input to m4 macro processor MANIFEST_TEMPLATE := src/manifest/manifest.mf TMP_JAR_DIR := $(call make-temp-dir) TMP_MANIFEST := $(TMP_JAR_DIR)/manifest.mf # $(call add-manifest, jar, jar-name, manifest-file-opt) define add-manifest $(RM) $(dir $(TMP_MANIFEST)) $(MKDIR) $(dir $(TMP_MANIFEST)) m4 --define=NAME="$(notdir )" \ --define=IMPL_VERSION=$(VERSION_NUMBER) \ --define=SPEC_VERSION=$(VERSION_NUMBER) \ $(if ,,$(MANIFEST_TEMPLATE)) \ > $(TMP_MANIFEST) $(JAR) -ufm $(TMP_MANIFEST) $(RM) $(dir $(TMP_MANIFEST)) endef # $(call make-jar,jar-variable-prefix) define make-jar .PHONY: $$(_name) : $(_name) $$(_name): cd $(OUTPUT_DIR); \ $(JAR) $(JARFLAGS) $$(notdir $$@) $$(_packages) $$(call add-manifest, $$@, $$(_name), $$(_manifest)) endef # Set the CLASSPATH export CLASSPATH := $(call build-classpath, $(class_path)) # make-directories - Ensure output directory exists. make-directories := $(shell $(MKDIR) $(OUTPUT_DIR)) # help - The default goal .PHONY: help help: @$(call brief-help, $(CURDIR)/Makefile) # all - Perform all tasks for a complete build .PHONY: all all: compile jars javadoc # all_javas - Temp file for holding source file list all_javas := $(OUTPUT_DIR)/all.javas # compile - Compile the source .PHONY: compile compile: $(all_javas) $(JAVAC) $(JFLAGS) @$< # all_javas - Gather source file list .INTERMEDIATE: $(all_javas) $(all_javas): $(FIND) $(SOURCE_DIR) -name '*.java' > $@ # jar_list - List of all jars to create jar_list := server_jar ui_jar # jars - Create all jars .PHONY: jars jars: $(jar_list) # server_jar - Create the $(server_jar) server_jar_name := $(OUTPUT_DIR)/lib/a.jar server_jar_manifest := src/com/company/manifest/foo.mf server_jar_packages := com/company/m com/company/n # ui_jar - create the $(ui_jar) ui_jar_name := $(OUTPUT_DIR)/lib/b.jar ui_jar_manifest := src/com/company/manifest/bar.mf ui_jar_packages := com/company/o com/company/p # Create an explicit rule for each jar # $(foreach j, $(jar_list), $(eval $(call make-jar,$j))) $(eval $(call make-jar,server_jar)) $(eval $(call make-jar,ui_jar)) # javadoc - Generate the Java doc from sources .PHONY: javadoc javadoc: $(all_javas) $(JAVADOC) $(JDFLAGS) @$< .PHONY: clean clean: $(RM) $(OUTPUT_DIR) .PHONY: classpath classpath: @echo CLASSPATH='$(CLASSPATH)' .PHONY: check-config check-config: @echo Checking configuration... $(call check-file, $(class_path) JAVA_HOME) .PHONY: print print: $(foreach v, $(V), \ $(warning $v = $($v))) |