-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathmakefile
334 lines (274 loc) · 15.2 KB
/
makefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# Copyright (c) 2015 Roc Project. This is free software. See
# LICENSE.txt for details.
#
# Builds all the aspects of Roc until a better build situation comes
# along.
########################################
# Documentation
# =============
#
# Useful Targets and their Descriptions
# -------------------------------------
#
# help: Display this list of targets.
#
# main: Compile application main
#
# tests: Compile, run core JUnit tests.
#
# usertests: Compile, run JUnit user scenarios (functionality/acceptance
# tests).
#
# alltests: Combines all above tests.
#
# javadoc: Generate the Java API documentation for this software.
#
# release-javadoc: Generate the public Java API documentation for this
# software.
#
# jar: Create a Java archive (package) for this software.
#
# clean-java: Removes the Java build directory containing all compiled
# Java classes.
#
# clean-javadoc: Remove generated Java documentation.
#
# clean: Same as clean-java for now.
#
# allclean: Combines all above clean targets as well as removing editor
# backups (*~) and the base build directory.
#
# listconfig: Lists all internal variables and their values.
#
# Individual Java files can be compiled by making *.class files, e.g.
# make build/java/mloss/roc/Curve.class
#
########################################
# List all the phony targets (targets that are really commands, not
# files). Keep this next to the documentation so they can easily be
# kept in sync.
.PHONY: help tests usertests alltests javadoc release-javadoc jar clean-java clean-javadoc clean allclean listconfig selftest
########################################
# Variables
# Use bash as the shell. Have make look it up rather than specifying a
# complete path as that should be more flexible/portable.
SHELL := bash
# Variables for string substitution
emptyString :=
space := $(emptyString) $(emptyString)
indent := $(emptyString) $(emptyString)
define newline
endef
makefileName := $(firstword $(MAKEFILE_LIST))
# Target Java version
javaVersion := 7
# Java compiler version
javacVersion := $(word 2, $(subst ., , $(word 2, $(shell javac -version 2>&1))))
# Location of the Java runtime JAR for the target Java version. Needed
# for cross-compiling.
rtJarLocations := /usr/lib/jvm/jre-1.$(javaVersion).0/lib/rt.jar
rtJar := $(wildcard $(rtjar) $(rtJarLocations))
# If the target Java version and the Java compiler version are
# different, check for the runtime JAR for the target version and set
# the bootclasspath option to enable proper cross-compilation. Set
# empty bootclasspath option when not cross-compiling.
crossCompileOpts :=
ifneq ($(javaVersion),$(javacVersion))
ifndef rtJar
$(error Error: The target Java version is $(javaVersion) but cannot find the Java $(javaVersion) runtime JAR. (The compiler is version $(javacVersion).) Add some alternative locations to the makefile, assign variable 'rtjar' on the command line, or set 'javaVersion' to the intended version.$(newline)$(indent)Searched: $(rtJarLocations))
else
rtJar := $(firstword $(rtJar))
# Set the bootclasspath option to the discovered runtime JAR to enable
# proper cross-compilation
crossCompileOpts := -bootclasspath $(rtJar)
endif
endif
# Java compiler options (e.g. -source 7 -target 7)
javacOpts := -source $(javaVersion) -target $(javaVersion) -Xlint
# Project layout
buildBaseDir := build
javaSrcDir := java/src
javaTestDir := java/test
javaDocDir := java/doc
javaBuildDir := $(buildBaseDir)/java
javaPkgDir := mloss/roc
# Locations for the JUnit and Hamcrest JARs required for testing. Note
# that some versions of JUnit 4 include some of the core Hamcrest
# classes. The /usr/share/java paths exist on Red Hat and Fedora.
# Presumably they also exist on other distributions. Only use the first
# location found to help keep the classpath short and manageable: to
# assist in debugging classpath problems and appropriately setting
# variables. (The system JUnit JAR might conflict with the Hamcrest
# JAR, i.e. be old enough to contain Hamcrest classes that will override
# those in the Hamcrest JAR.)
junitLocations := junit.jar ~/opt/junit.jar /usr/share/java/junit4.jar
junitJars := $(firstword $(wildcard $(junit) $(junitLocations)))
hamcrestLocations := hamcrest-core.jar ~/opt/hamcrest-core.jar /usr/share/java/hamcrest/core.jar
hamcrestJars := $(firstword $(wildcard $(hamcrest) $(hamcrestLocations)))
# Java class paths. The regular one includes any existing classpath and
# the build directory. The testing one adds JUnit and Hamcrest JARs to
# that. Use 'strip' to remove extra whitespace and avoid empty
# classpath entries.
classpath := $(subst $(space),:,$(strip $(CLASSPATH) $(CURDIR)/$(javaBuildDir)))
testClasspath := $(subst $(space),:,$(strip $(classpath) $(junitJars) $(hamcrestJars)))
# Java sources
javaSrcFiles := $(shell find $(javaSrcDir) -name '*.java' -not -name 'package-info.java' | sort)
javaTestFiles := $(shell find $(javaTestDir) -name '*.java' | sort)
javaDocFiles := $(shell find $(javaSrcDir) -name 'package-info.java' | sort)
javaReleaseSrcFiles := $(subst $(javaSrcDir),$(javaBuildDir),$(javaSrcFiles))
# Java classes
javaSrcClasses := $(subst $(javaSrcDir),$(javaBuildDir),$(javaSrcFiles:.java=.class))
javaTestClasses := $(subst $(javaTestDir),$(javaBuildDir),$(javaTestFiles:.java=.class))
# Limit 'javaTestClasses' to actual unit tests (omit helper classes).
javaUnitTestClasses := $(filter %Test.class,$(javaTestClasses))
# Project version (anything in the README after the identifying phrase
# that consists of digits and periods with digits on the ends)
version := $(shell grep VERSION_STRING $(javaSrcDir)/$(javaPkgDir)/MetaInfo.java | sed -e 's/.*"\([0-9][0-9.]*[0-9]\)".*/\1/')
########################################
# General targets
# Print documentation
help:
@sed -n '/^# Documentation/,/^#####/p' $(makefileName) | cut -c 3- | head -n -1
# List variables and values
listconfig:
@echo Variables:
@echo version: $(version)
@echo classpath: $(classpath)
@echo testClasspath: $(testClasspath)
@echo junitJars: $(junitJars)
@echo hamcrestJars: $(hamcrestJars)
@echo javaSrcFiles:
@echo -e "$(indent)$(subst $(space),\n$(indent),$(javaSrcFiles))"
@echo javaSrcClasses:
@echo -e "$(indent)$(subst $(space),\n$(indent),$(javaSrcClasses))"
@echo javaTestFiles:
@echo -e "$(indent)$(subst $(space),\n$(indent),$(javaTestFiles))"
@echo javaTestClasses:
@echo -e "$(indent)$(subst $(space),\n$(indent),$(javaTestClasses))"
@echo javaUnitTestClasses:
@echo -e "$(indent)$(subst $(space),\n$(indent),$(javaUnitTestClasses))"
# General targets
# Build directory target. Use a hidden file to test against because
# directory timestamps are frequently updated and therefore directories
# are not appropriate prerequisites for other targets.
$(buildBaseDir)/.exists:
mkdir -p $(@D)
@touch $@
$(javaBuildDir)/.exists:
mkdir -p $(@D)
@touch $@
########################################
# Java
# Java sources compilation
$(javaBuildDir)/%.class: $(javaBuildDir)/.exists $(javaSrcDir)/%.java
javac -cp $(classpath) $(crossCompileOpts) -d $(javaBuildDir) $(javacOpts) $(javaSrcDir)/$*.java
# Java tests compilation. Depends on JUnit and Hamcrest.
$(javaBuildDir)/%.class: $(javaBuildDir)/.junitClassesExist $(javaBuildDir)/.hamcrestClassesExist $(javaTestDir)/%.java
javac -cp $(testClasspath) $(crossCompileOpts) -d $(javaBuildDir) $(javacOpts) $(javaTestDir)/$*.java
# List Java dependencies here
# Application classes
$(javaBuildDir)/$(javaPkgDir)/Curve.class:
$(javaBuildDir)/$(javaPkgDir)/Main.class: $(javaBuildDir)/$(javaPkgDir)/Curve.class $(javaBuildDir)/$(javaPkgDir)/Reports.class $(javaBuildDir)/$(javaPkgDir)/util/NaiveCsvReader.class $(javaBuildDir)/$(javaPkgDir)/util/CsvProcessing.class $(javaBuildDir)/$(javaPkgDir)/MetaInfo.class $(javaBuildDir)/$(javaPkgDir)/util/ArrayUtils.class
$(javaBuildDir)/$(javaPkgDir)/Reports.class: $(javaBuildDir)/$(javaPkgDir)/Curve.class
$(javaBuildDir)/$(javaPkgDir)/util/ArrayIterator.class:
$(javaBuildDir)/$(javaPkgDir)/util/ArrayUtils.class:
$(javaBuildDir)/$(javaPkgDir)/util/CsvProcessing.class:
$(javaBuildDir)/$(javaPkgDir)/util/IterableArray.class: $(javaBuildDir)/$(javaPkgDir)/util/ArrayIterator.class
$(javaBuildDir)/$(javaPkgDir)/util/NaiveCsvReader.class:
# Test classes
$(javaBuildDir)/$(javaPkgDir)/CurveTest.class: $(javaBuildDir)/$(javaPkgDir)/Curve.class
$(javaBuildDir)/$(javaPkgDir)/CurveBuilderTest.class: $(javaBuildDir)/$(javaPkgDir)/Curve.class $(javaBuildDir)/$(javaPkgDir)/util/Assert.class $(javaBuildDir)/$(javaPkgDir)/util/IterableArray.class
$(javaBuildDir)/$(javaPkgDir)/CurvePrimitivesBuilderTest.class: $(javaBuildDir)/$(javaPkgDir)/Curve.class $(javaBuildDir)/$(javaPkgDir)/util/Assert.class $(javaBuildDir)/$(javaPkgDir)/util/ArrayUtils.class $(javaBuildDir)/$(javaPkgDir)/util/IterableArray.class $(javaBuildDir)/$(javaPkgDir)/CurveTest.class $(javaBuildDir)/$(javaPkgDir)/CurveBuilderTest.class
$(javaBuildDir)/$(javaPkgDir)/MainTest.class: $(javaBuildDir)/$(javaPkgDir)/Main.class
$(javaBuildDir)/$(javaPkgDir)/UserScenarios.class: $(javaBuildDir)/$(javaPkgDir)/Curve.class $(javaBuildDir)/$(javaPkgDir)/CurveTest.class
$(javaBuildDir)/$(javaPkgDir)/util/Assert.class:
$(javaBuildDir)/$(javaPkgDir)/util/CsvProcessingTest.class: $(javaBuildDir)/$(javaPkgDir)/util/CsvProcessing.class $(javaBuildDir)/$(javaPkgDir)/util/IterableArray.class
#####
# Main
main: $(javaBuildDir)/$(javaPkgDir)/Main.class
# Test dependencies
# Check for JUnit 4 JARs (>= 4.6) and the required JUnit classes
junitClasses := org.junit.Assert org.junit.Test
junitClassesFiles := $(addsuffix .class,$(subst .,/,$(junitClasses)))
$(javaBuildDir)/.junitClassesExist: $(javaBuildDir)/.exists
@[[ -n "$(junitJars)" ]] && true || { echo -e "make: *** Error: Cannot find the JUnit 4 JAR. Assign variable 'junit' on the command line or add some alternative locations to the makefile.\n$(indent)Searched locations: $(junitLocations)"; exit 1; }
@junitVersion=$$(java -cp $(testClasspath) junit.runner.Version); junitVersionParts=( $$(echo $$junitVersion | tr '.-' ' ') ); [[ $${junitVersionParts[0]} -gt 4 || ( $${junitVersionParts[0]} -eq 4 && $${junitVersionParts[1]} -ge 6 ) ]] && true || { echo -e "make: *** Error: The JUnit version is too old. Expected >= 4.6 but found $$junitVersion.\n$(indent)Searched classpath: $(testClasspath)"; exit 1; }
@{ for jar in $(junitJars); do jar tf $$jar; done; } | sort | uniq > $(javaBuildDir)/.junitJarsContents
@[[ "$$(grep -c $(foreach pattern,$(junitClassesFiles),-e $(pattern)) $(javaBuildDir)/.junitJarsContents)" -eq "$(words $(junitClassesFiles))" ]] && touch $@ || { echo -e "make: *** Error: The JUnit 4 JAR(s) do not contain the required classes.\n$(indent)Searched JARs: $(junitJars)"; exit 1; }
# Check for Hamcrest JARs and the required Hamcrest classes (which may
# be contained in the JUnit JARs in some versions)
hamcrestClasses := org.hamcrest.CoreMatchers org.hamcrest.Matcher
hamcrestClassesFiles := $(addsuffix .class,$(subst .,/,$(hamcrestClasses)))
$(javaBuildDir)/.hamcrestClassesExist: $(javaBuildDir)/.exists
@[[ -n "$(wildcard $(hamcrestJars) $(junitJars))" ]] && true || { echo -e "make: *** Error: Cannot find any Hamcrest JARs. Assign variable 'hamcrest' on the command line or add some alternative locations to the makefile.\n$(indent)Searched locations: $(hamcrestLocations) $(junitLocations)"; exit 1; }
@{ for jar in $(hamcrestJars) $(junitJars); do jar tf $$jar; done; } | sort | uniq > $(javaBuildDir)/.hamcrestJarsContents
@[[ "$$(grep -c $(foreach pattern,$(hamcrestClassesFiles),-e $(pattern)) $(javaBuildDir)/.hamcrestJarsContents)" -eq "$(words $(hamcrestClassesFiles))" ]] && touch $@ || { echo -e "make: *** Error: The Hamcrest JAR(s) do not contain the required classes.\n$(indent)Searched JARs: $(junitJars) $(hamcrestJars)"; exit 1; }
#####
# JUnit
# Run unit tests
tests: $(javaUnitTestClasses)
java -cp $(testClasspath) org.junit.runner.JUnitCore $(subst /,.,$(subst $(javaBuildDir)/,,$(javaUnitTestClasses:.class=)))
# Run acceptance tests
usertests: $(javaBuildDir)/$(javaPkgDir)/UserScenarios.class
java -cp $(testClasspath) org.junit.runner.JUnitCore mloss.roc.UserScenarios
# Run all tests
alltests: $(javaUnitTestClasses) $(javaBuildDir)/$(javaPkgDir)/UserScenarios.class
java -cp $(testClasspath) org.junit.runner.JUnitCore $(subst /,.,$(subst $(javaBuildDir)/,,$(^:.class=)))
#####
# Javadoc for internal reading
# Java documentation for the full API (including private) but not the tests
javadoc: $(javaDocDir)/index.html
$(javaSrcDir)/doc-files/LICENSE.txt: LICENSE.txt
mkdir -p $(javaSrcDir)/doc-files
cp $< $@
# Javadoc level private
$(javaDocDir)/index.html: $(javaSrcDir)/overview.html $(javaSrcDir)/javadocOptions.txt $(javaSrcFiles) $(javaDocFiles) $(javaSrcDir)/doc-files/LICENSE.txt $(javaSrcDir)/overview-summary.html.patch
javadoc -d $(javaDocDir) -sourcepath $(javaSrcDir) -private @$(javaSrcDir)/javadocOptions.txt -overview $< $(javaSrcFiles)
# Work around javadoc bug where content is put in div with footer class
# (but only if present)
grep -q 'class="footer".*name="overview_description"' $(javaDocDir)/overview-summary.html && patch --forward --input $(javaSrcDir)/overview-summary.html.patch $(javaDocDir)/overview-summary.html || true
#####
# Javadoc for release. Same as 'javadoc' above but level public.
release-javadoc: $(javaBuildDir)/doc/index.html
$(javaBuildDir)/doc/index.html: $(javaSrcDir)/overview.html $(javaSrcDir)/javadocOptions.txt $(javaSrcFiles) $(javaDocFiles) $(javaSrcDir)/doc-files/LICENSE.txt $(javaSrcDir)/overview-summary.html.patch
javadoc -d $(javaBuildDir)/doc -sourcepath $(javaSrcDir) @$(javaSrcDir)/javadocOptions.txt -overview $< $(javaSrcFiles)
# Work around javadoc bug where content is put in div with footer class
# (but only do if bug present)
grep -q 'class="footer".*name="overview_description"' $(javaBuildDir)/doc/overview-summary.html && patch --forward --input $(javaSrcDir)/overview-summary.html.patch $(javaBuildDir)/doc/overview-summary.html || true
#####
# JAR package of library source, bytecode, and docs; a distribution for use, not for development
# Redirect to a JAR for the current version
jar: $(javaBuildDir)/roc-$(version).jar
# Copy files from src to build for packaging
$(javaBuildDir)/%.java: $(javaSrcDir)/%.java
mkdir -p $(@D) # Make sure the destination directory exists
cp $< $@
# Build a JAR for the current version
$(javaBuildDir)/roc-$(version).jar: README.md LICENSE.txt $(javaReleaseSrcFiles) $(javaSrcClasses) release-javadoc
jar cfe $@ mloss.roc.Main README.md LICENSE.txt -C $(javaBuildDir) mloss -C $(javaBuildDir) doc
########################################
# Cleanup
# Remove all derived files
clean: clean-java
clean-java:
@rm -Rf $(javaBuildDir)
clean-javadoc:
@rm -Rf $(javaDocDir)
# Named allclean to distinguish from clean* when typing
allclean: clean-java clean-javadoc
@find -name '*~' -delete
@rm -Rf $(buildBaseDir)
########################################
# Test the makefile to make sure each target runs (not necessarily
# correctly)
selfTestCommands := $(shell grep '^.PHONY:' $(makefileName) | sed -e 's/.PHONY://' -e 's/selftest//')
selftest:
@for command in $(javaSrcClasses) $(javaTestClasses) $(selfTestCommands); do \
echo -n "Testing 'make $$command' ... "; \
output=$$( make allclean 2>&1 && make $$command 2>&1 ); \
if [[ $$? -ne 0 ]]; then \
echo -e "\n----------\n$$output\n----------\nFAIL: $$command" ; exit 1; \
else \
echo OK; \
fi \
done