#!/usr/bin/make -f # Copyright © 2013-2014 Luke Shumaker # This work is free. You can redistribute it and/or modify it under the # terms of the Do What The Fuck You Want To Public License, Version 2, # as published by Sam Hocevar. See the COPYING file for more details. # Install paths DESTDIR ?= MAVEN_LOCAL_REPO ?= ~/.m2 # Utilities CP = cp ECHO = echo EXISTS = test -e FAIL = exit 1 FIND = find INSTALL = install JAR = jar JAVA = java JAVAC = javac MKDIRS = mkdir -p PRINTF = printf RM = rm -f SED = sed TOUCH = touch XMLSTARLET = xml JAVAC_FLAGS += $(if $(javac_source),-source $(javac_source)) JAVAC_FLAGS += $(if $(javac_target),-target $(javac_target)) JAVAC_FLAGS += $(if $(javac_encoding),-encoding $(javac_encoding)) # Detect information from POMs pom_get = $(shell $(XMLSTARLET) sel -T -t $(foreach xpath,$1, -v '$(subst /,/_:,$(xpath))' -n) pom.xml) plugin_conf = /project/build/plugins/plugin[./artifactId[text()="$1"]]/configuration/$2 artifactId := $(call pom_get,/project/artifactId) version := $(firstword $(call pom_get,/project/version /project/parent/version) $(value version)) groupId := $(firstword $(call pom_get,/project/groupId /project/parent/groupId)) sourceDirectory := $(firstword $(call pom_get,/project/build/sourceDirectory) $(value sourceDirectory) src/main/java ) resources := $(firstword $(call pom_get,/project/build/resources ) $(value resources) src/main/resources) # The order of precidence with these isn't quite right, but it's rare that multiple are set. javac_source := $(firstword $(call pom_get,/project/properties/maven.compile.source /project/properties/maven.compiler.source $(call plugin_conf,maven-compiler-plugin,source) ) $(value javac_source)) javac_target := $(firstword $(call pom_get,/project/properties/maven.compile.target /project/properties/maven.compiler.target $(call plugin_conf,maven-compiler-plugin,target) ) $(value javac_target)) javac_encoding := $(firstword $(call pom_get,/project/properties/project.build.sourceEncoding $(call plugin_conf,maven-compiler-plugin,encoding)) $(value javac_encoding)) basedir := $(shell pwd) project.basedir = $(basedir) subdirs = $(patsubst %/pom.xml,%,$(wildcard */pom.xml)) targets = pom $(if $(wildcard $(sourceDirectory) $(resources)),jar) # Post-processing inherit_vars = version sourceDirectory resources javac_source javac_target javac_encoding $(foreach var,$(inherit_vars),$(eval $(var) = $($(var)))) $(if $(extra_makefiles),$(eval include $(extra_makefiles))) subdirs := $(subdirs) targets := $(targets) ################################################################################ dep_dir = $1 $(shell $(FIND) $1 2>/dev/null) dep_optdir = $(shell $(FIND) $1 2>/dev/null) all: PHONY \ $(addprefix target/$(artifactId)-$(version).,$(targets)) \ $(addsuffix /all,$(subdirs)) # generate-sources ############################################################# generate-sources: PHONY target/generated-sources target/generated-sources: $(if $^,for dep in $^; do $(EXISTS) $$dep || { $(RM) -r $@; $(FAIL); }; done,$(MKDIRS) $@) $(TOUCH) $@ # generate-resources ########################################################### generate-resources: PHONY target/generated-resources target/generated-resources: \ target/generated-resources/META-INF/maven/$(groupId)/$(artifactId)/pom.properties \ target/generated-resources/META-INF/maven/$(groupId)/$(artifactId)/pom.xml for dep in $^; do $(EXISTS) $$dep || { $(RM) -r $@; $(FAIL); }; done $(TOUCH) $@ target/generated-resources/META-INF/maven/$(groupId)/$(artifactId)/pom.xml: pom.xml $(INSTALL) -Dm644 $< $@ # This is almost the default date format for locale=C, but the DOM is # 0-padded instead of space-padded. target/generated-resources/META-INF/maven/$(groupId)/$(artifactId)/pom.properties: pom.xml $(MKDIRS) $(@D) $(PRINTF) '#Generated by %s\n#%s\n\nversion=%s\ngroupId=%s\nartifactId=%s\n' \ Make "$$(LC_ALL=C date '+%a %b %d %H:%M:%S %Z %Y')" '$(version)' '$(groupId)' '$(artifactId)' \ > $@ # compile ###################################################################### compile: PHONY target/classes # Maven puts `target/classes` in the classpath, but that's unnecessary # here, as we don't do incremental/segmented compilation. target/classes: \ $(call dep_optdir,$(sourceDirectory) $(resources)) \ $(call dep_dir,target/generated-sources target/generated-resources) $(RM) -r $@ $(MKDIRS) $@ $(FIND) $(wildcard $(resources) target/generated-resources) -mindepth 1 -maxdepth 1 -exec $(CP) -r {} $@ \; || { $(RM) -r $@; $(FAIL); } # process-resources $(FIND) $(wildcard $(sourceDirectory) target/generated-sources) -name '*.java' -exec $(JAVAC) $(JAVAC_FLAGS) -d $@ {} + || { $(RM) -r $@; $(FAIL); } # compile $(TOUCH) $@ $(process-classes) # package ###################################################################### package: PHONY \ target/$(artifactId)-$(version).pom \ target/$(artifactId)-$(version).jar target/$(artifactId)-$(version).pom: pom.xml $(INSTALL) -Dm644 $< $@ target/$(artifactId)-$(version).jar: target/classes $(JAR) -cf $@ -C $< . # install ###################################################################### mvndir = $(subst .,/,$(groupId))/$(artifactId)/$(version) install: PHONY \ $(addprefix $(DESTDIR)$(MAVEN_LOCAL_REPO)/$(mvndir)/$(artifactId)-$(version).,$(targets)) \ $(addsuffix /install,$(subdirs)) $(DESTDIR)$(MAVEN_LOCAL_REPO)/$(mvndir)/%: target/% $(INSTALL) -Dm644 $< $@ # clean ######################################################################## clean: PHONY $(addsuffix /clean,$(subdirs)) rm -rf target # recurse ###################################################################### deps2jars = $(wildcard $(patsubst %/all,%/target/*.jar,$(filter $(addsuffix /all,$(subdirs)),$1))) deps2classpath = $(shell $(ECHO) $(abspath $(call deps2jars,$1)) $(CLASSPATH) | $(SED) 'y/ /:/') define recurse-rule $1/%: PHONY $(addsuffix /all,$($1_deps)) CLASSPATH='$$(call deps2classpath,$$^)' $(foreach var,$(inherit_vars),$(subst .,_,$(var))='$$(value $(var))') $$(MAKE) -C '$1' -f '$$(abspath $$(firstword $$(MAKEFILE_LIST)))' '$$*' endef $(foreach subdir,$(subdirs),$(eval $(call recurse-rule,$(subdir)))) # boilerplate ################################################################## .PHONY: PHONY FORCE .DELETE_ON_ERROR: .SECONDARY: