8 @echo
'make "IMPL" # build all steps of IMPL'
9 @echo
'make "IMPL^STEP" # build STEP of IMPL'
11 @echo
'make "test" # test all implementations'
12 @echo
'make "test^IMPL" # test all steps of IMPL'
13 @echo
'make "test^STEP" # test STEP for all implementations'
14 @echo
'make "test^IMPL^STEP" # test STEP of IMPL'
16 @echo
'make "perf" # run microbenchmarks for all implementations'
17 @echo
'make "perf^IMPL" # run microbenchmarks for IMPL'
19 @echo
'make "repl^IMPL" # run stepA of IMPL'
20 @echo
'make "repl^IMPL^STEP" # test STEP of IMPL'
22 @echo
'make "clean" # run 'make
clean' for all implementations'
23 @echo
'make "clean^IMPL" # run 'make
clean' for IMPL'
25 @echo
'make "stats" # run 'make stats
' for all implementations'
26 @echo
'make "stats-lisp" # run 'make stats-lisp
' for all implementations'
27 @echo
'make "stats^IMPL" # run 'make stats
' for IMPL'
28 @echo
'make "stats-lisp^IMPL" # run 'make stats-lisp
' for IMPL'
30 @echo
'Options/Settings:'
32 @echo
'make MAL_IMPL=IMPL "test^mal..." # use IMPL for self-host tests'
33 @echo
'make REGRESS=1 "test..." # test with previous step tests too'
34 @echo
'make DOCKERIZE=1 ... # to dockerize above rules/targets'
38 @echo
'make "docker-build^IMPL" # build docker image for IMPL'
42 # Command line settings
49 # python, js, cpp, or neko are currently supported
52 # Extra options to pass to runtest.py
55 # Test with previous test files not just the test files for the
56 # current step. Step 0 and 1 tests are special and not included in
60 # Extra implementation specific options to pass to runtest.py
61 mal_TEST_OPTS
= --start-timeout
60 --test-timeout
120
62 miniMAL_TEST_OPTS
= --start-timeout
60 --test-timeout
120
66 # Run target/rule within docker image for the implementation
73 IMPLS
= ada awk bash c d clojure coffee
cpp crystal cs erlang elisp \
74 elixir es6 factor forth fsharp go groovy guile haskell haxe \
75 io java julia js kotlin lua make mal ocaml matlab miniMAL \
76 nim objc objpascal perl php plpgsql ps python r racket \
77 rpython ruby rust scala swift swift3 tcl vb vimscript
80 step1
= step1_read_print
83 step4
= step4_if_fn_do
94 regress_step3
= $(regress_step2
) step3
95 regress_step4
= $(regress_step3
) step4
96 regress_step5
= $(regress_step4
) step5
97 regress_step6
= $(regress_step5
) step6
98 regress_step7
= $(regress_step6
) step7
99 regress_step8
= $(regress_step7
) step8
100 regress_step9
= $(regress_step8
) step9
101 regress_stepA
= $(regress_step9
) stepA
103 test_EXCLUDES
+= test^bash^step5
# never completes at 10,000
104 test_EXCLUDES
+= test^make^step5
# no TCO capability (iteration or recursion)
105 test_EXCLUDES
+= test^mal^step5
# host impl dependent
106 test_EXCLUDES
+= test^matlab^step5
# never completes at 10,000
107 test_EXCLUDES
+= test^plpgsql^step5
# too slow for 10,000
109 perf_EXCLUDES
= mal
# TODO: fix this
112 # TODO: still need to implement dist
113 dist_EXCLUDES
+= guile io julia matlab swift
119 MATLAB
= matlab
-nodisplay
-nosplash
-nodesktop
-nojvm
-r
120 OCTAVE
= octave
--no-gui
-q
--traditional
--eval
121 matlab_args
= $(subst $(SPACE
),$(COMMA
),$(foreach x
,$(strip $(1)),'$(x)'))
122 matlab_cmd
= $(if
$(strip $(USE_MATLAB
)),$(MATLAB
),$(OCTAVE
))
124 haxe_STEP_TO_PROG_neko
= haxe
/$($(1)).n
125 haxe_STEP_TO_PROG_python
= haxe
/$($(1)).py
126 haxe_STEP_TO_PROG_cpp
= haxe
/cpp/$($(1))
127 haxe_STEP_TO_PROG_js
= haxe
/$($(1)).js
129 haxe_RUNSTEP_neko
= neko ..
/$(2) $(3)
130 haxe_RUNSTEP_python
= python3 ..
/$(2) $(3)
131 haxe_RUNSTEP_cpp
= ..
/$(2) $(3)
132 haxe_RUNSTEP_js
= node ..
/$(2) $(3)
134 # Return list of test files for a given step. If REGRESS is set then
135 # test files will include step 2 tests through tests for the step
137 STEP_TEST_FILES
= $(strip $(wildcard \
138 $(foreach s
,$(if
$(strip $(REGRESS
)),$(regress_
$(2)),$(2)),\
139 $(1)/tests
/$($(s
)).mal tests
/$($(s
)).mal
)))
141 # Map of step (e.g. "step8") to executable file for that step
142 ada_STEP_TO_PROG
= ada
/$($(1))
143 awk_STEP_TO_PROG
= awk
/$($(1)).awk
144 bash_STEP_TO_PROG
= bash
/$($(1)).sh
145 c_STEP_TO_PROG
= c
/$($(1))
146 d_STEP_TO_PROG
= d
/$($(1))
147 clojure_STEP_TO_PROG
= clojure
/src
/$($(1)).clj
148 coffee_STEP_TO_PROG
= coffee
/$($(1)).coffee
149 cpp_STEP_TO_PROG
= cpp/$($(1))
150 crystal_STEP_TO_PROG
= crystal
/$($(1))
151 cs_STEP_TO_PROG
= cs
/$($(1)).exe
152 elisp_STEP_TO_PROG
= elisp
/$($(1)).el
153 elixir_STEP_TO_PROG
= elixir
/lib
/mix
/tasks
/$($(1)).ex
154 erlang_STEP_TO_PROG
= erlang
/$($(1))
155 es6_STEP_TO_PROG
= es6
/build
/$($(1)).js
156 factor_STEP_TO_PROG
= factor
/$($(1))/$($(1)).factor
157 forth_STEP_TO_PROG
= forth
/$($(1)).fs
158 fsharp_STEP_TO_PROG
= fsharp
/$($(1)).exe
159 go_STEP_TO_PROG
= go
/$($(1))
160 groovy_STEP_TO_PROG
= groovy
/$($(1)).groovy
161 java_STEP_TO_PROG
= java
/target
/classes
/mal
/$($(1)).class
162 haskell_STEP_TO_PROG
= haskell
/$($(1))
163 haxe_STEP_TO_PROG
= $(haxe_STEP_TO_PROG_
$(HAXE_MODE
))
164 io_STEP_TO_PROG
= io
/$($(1)).io
165 julia_STEP_TO_PROG
= julia
/$($(1)).jl
166 js_STEP_TO_PROG
= js
/$($(1)).js
167 kotlin_STEP_TO_PROG
= kotlin
/$($(1)).jar
168 lua_STEP_TO_PROG
= lua
/$($(1)).lua
169 make_STEP_TO_PROG
= make
/$($(1)).mk
170 mal_STEP_TO_PROG
= mal
/$($(1)).mal
171 ocaml_STEP_TO_PROG
= ocaml
/$($(1))
172 matlab_STEP_TO_PROG
= matlab
/$($(1)).m
173 miniMAL_STEP_TO_PROG
= miniMAL
/$($(1)).json
174 nim_STEP_TO_PROG
= nim
/$($(1))
175 objc_STEP_TO_PROG
= objc
/$($(1))
176 objpascal_STEP_TO_PROG
= objpascal
/$($(1))
177 perl_STEP_TO_PROG
= perl
/$($(1)).pl
178 php_STEP_TO_PROG
= php
/$($(1)).php
179 plpgsql_STEP_TO_PROG
= plpgsql
/$($(1)).sql
180 ps_STEP_TO_PROG
= ps
/$($(1)).ps
181 python_STEP_TO_PROG
= python
/$($(1)).py
182 r_STEP_TO_PROG
= r
/$($(1)).r
183 racket_STEP_TO_PROG
= racket
/$($(1)).rkt
184 rpython_STEP_TO_PROG
= rpython
/$($(1))
185 ruby_STEP_TO_PROG
= ruby
/$($(1)).rb
186 rust_STEP_TO_PROG
= rust
/target
/release
/$($(1))
187 scala_STEP_TO_PROG
= scala
/$($(1)).scala
188 swift_STEP_TO_PROG
= swift
/$($(1))
189 swift3_STEP_TO_PROG
= swift3
/$($(1))
190 tcl_STEP_TO_PROG
= tcl
/$($(1)).tcl
191 vb_STEP_TO_PROG
= vb
/$($(1)).exe
192 vimscript_STEP_TO_PROG
= vimscript
/$($(1)).vim
193 guile_STEP_TO_PROG
= guile
/$($(1)).scm
196 # Needed some argument munging
199 SPACE
= $(noop
) $(noop
)
200 export FACTOR_ROOTS
:= .
202 # Macro for running a step:
203 # $(1): step (e.g. "stepA")
204 # $(2): program for step (e.g. result of *_STEP_TO_PROG
205 # $(3): program arguments
206 ada_RUNSTEP
= ..
/$(2) $(3)
207 awk_RUNSTEP
= awk
-O
-f ..
/$(2) $(3)
208 bash_RUNSTEP
= bash ..
/$(2) $(3)
209 c_RUNSTEP
= ..
/$(2) $(3)
210 d_RUNSTEP
= ..
/$(2) $(3)
211 clojure_RUNSTEP
= lein with-profile
+$(1) trampoline run
$(3)
212 coffee_RUNSTEP
= coffee ..
/$(2) $(3)
213 cpp_RUNSTEP
= ..
/$(2) $(3)
214 crystal_RUNSTEP
= ..
/$(2) $(3)
215 cs_RUNSTEP
= mono ..
/$(2) --raw
$(3)
216 elisp_RUNSTEP
= emacs
-Q
--batch
--load ..
/$(2) $(3)
217 elixir_RUNSTEP
= mix
$(notdir $(basename $(2))) $(3)
218 erlang_RUNSTEP
= ..
/$(2) $(3)
219 es6_RUNSTEP
= node ..
/$(2) $(3)
220 factor_RUNSTEP
= factor ..
/$(2) $(3)
221 forth_RUNSTEP
= gforth ..
/$(2) $(3)
222 fsharp_RUNSTEP
= mono ..
/$(2) --raw
$(3)
223 go_RUNSTEP
= ..
/$(2) $(3)
224 groovy_RUNSTEP
= groovy ..
/$(2) $(3)
225 # needs TERM=dumb to work with readline
226 guile_RUNSTEP
= guile
--no-auto-compile
-L ..
/guile ..
/$(2) $(3)
227 haskell_RUNSTEP
= ..
/$(2) $(3)
228 haxe_RUNSTEP
= python3 ..
/$(2) $(3)
229 haxe_RUNSTEP
= $(haxe_RUNSTEP_
$(HAXE_MODE
))
230 io_RUNSTEP
= io ..
/$(2) $(3)
231 java_RUNSTEP
= mvn
-quiet exec
:java
-Dexec.mainClass
="mal.$($(1))" $(if
$(3), -Dexec.args
="$(3)",)
232 julia_RUNSTEP
= ..
/$(2) $(3)
233 js_RUNSTEP
= node ..
/$(2) $(3)
234 kotlin_RUNSTEP
= java
-jar ..
/$(2) $(3)
235 lua_RUNSTEP
= ..
/$(2) $(3)
236 make_RUNSTEP
= make
-f ..
/$(2) $(3)
237 mal_RUNSTEP
= $(call
$(MAL_IMPL
)_RUNSTEP
,stepA
,$(call
$(MAL_IMPL
)_STEP_TO_PROG
,stepA
),..
/$(2),") #"
238 ocaml_RUNSTEP
= ..
/$(2) $(3)
239 matlab_RUNSTEP
= $(matlab_cmd
) "$($(1))($(call matlab_args,$(3)));quit;"
240 miniMAL_RUNSTEP
= miniMAL ..
/$(2) $(3)
241 nim_RUNSTEP
= ..
/$(2) $(3)
242 objc_RUNSTEP
= ..
/$(2) $(3)
243 objpascal_RUNSTEP
= ..
/$(2) $(3)
244 perl_RUNSTEP
= perl ..
/$(2) $(3)
245 php_RUNSTEP
= php ..
/$(2) $(3)
246 plpgsql_RUNSTEP
= .
/wrap.sh ..
/$(2) $(3)
247 ps_RUNSTEP
= gs
-q
-I.
/ -dNODISPLAY
-- ..
/$(2) $(3)
248 python_RUNSTEP
= $(PYTHON
) ..
/$(2) $(3)
249 r_RUNSTEP
= Rscript ..
/$(2) $(3)
250 racket_RUNSTEP
= ..
/$(2) $(3)
251 rpython_RUNSTEP
= ..
/$(2) $(3)
252 ruby_RUNSTEP
= ruby ..
/$(2) $(3)
253 rust_RUNSTEP
= ..
/$(2) $(3)
254 scala_RUNSTEP
= sbt
'run-main $($(1))$(if $(3), $(3),)'
255 swift_RUNSTEP
= ..
/$(2) $(3)
256 swift3_RUNSTEP
= ..
/$(2) $(3)
257 tcl_RUNSTEP
= tclsh ..
/$(2) --raw
$(3)
258 vb_RUNSTEP
= mono ..
/$(2) --raw
$(3)
259 vimscript_RUNSTEP
= .
/run_vimscript.sh ..
/$(2) $(3)
262 # DOCKERIZE utility functions
263 lc
= $(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))))))))))))))))))))))))))
264 impl_to_image
= kanaka
/mal-test-
$(call lc
,$(1))
266 actual_impl
= $(if
$(filter mal
,$(1)),$(MAL_IMPL
),$(1))
268 get_build_prefix
= $(if
$(strip $(DOCKERIZE
)),docker run
-it
--rm -u
$(shell id
-u
) -v
$(dir $(abspath
$(lastword
$(MAKEFILE_LIST
)))):/mal
-w
/mal
/$(1) $(if
$(filter factor
,$(1)),-e FACTOR_ROOTS
=$(FACTOR_ROOTS
),) $(call impl_to_image
,$(1)) ,)
269 get_run_prefix
= $(if
$(strip $(DOCKERIZE
)),docker run
-it
--rm -u
$(shell id
-u
) -v
$(dir $(abspath
$(lastword
$(MAKEFILE_LIST
)))):/mal
-w
/mal
/$(call actual_impl
,$(1)) $(if
$(filter factor
,$(1)),-e FACTOR_ROOTS
=$(FACTOR_ROOTS
),) $(call impl_to_image
,$(call actual_impl
,$(1))) ,)
272 vimscript_TEST_OPTS
= --test-timeout
30
273 ifeq ($(MAL_IMPL
),vimscript
)
274 mal_TEST_OPTS
= --start-timeout
60 --test-timeout
180
278 STEPS
= $(sort $(filter step
%,$(.VARIABLES
)))
279 DO_IMPLS
= $(filter-out $(SKIP_IMPLS
),$(IMPLS
))
280 IMPL_TESTS
= $(foreach impl
,$(DO_IMPLS
),test^
$(impl
))
281 STEP_TESTS
= $(foreach step
,$(STEPS
),test^
$(step
))
282 ALL_TESTS
= $(filter-out $(test_EXCLUDES
),\
284 $(foreach impl
,$(DO_IMPLS
),\
285 $(foreach step
,$(STEPS
),test^
$(impl
)^
$(step
))))))
287 DOCKER_BUILD
= $(foreach impl
,$(DO_IMPLS
),docker-build^
$(impl
))
289 IMPL_PERF
= $(foreach impl
,$(filter-out $(perf_EXCLUDES
),$(DO_IMPLS
)),perf^
$(impl
))
291 IMPL_REPL
= $(foreach impl
,$(DO_IMPLS
),repl^
$(impl
))
292 ALL_REPL
= $(strip $(sort \
293 $(foreach impl
,$(DO_IMPLS
),\
294 $(foreach step
,$(STEPS
),repl^
$(impl
)^
$(step
)))))
300 # Build a program in an implementation directory
301 # Make sure we always try and build first because the dependencies are
302 # encoded in the implementation Makefile not here
303 .PHONY
: $(foreach i
,$(DO_IMPLS
),$(foreach s
,$(STEPS
),$(call
$(i
)_STEP_TO_PROG
,$(s
))))
304 $(foreach i
,$(DO_IMPLS
),$(foreach s
,$(STEPS
),$(call
$(i
)_STEP_TO_PROG
,$(s
)))):
305 $(foreach impl
,$(word 1,$(subst /, ,$(@
))),\
307 $(call get_build_prefix
,$(impl
))$(MAKE
) $(patsubst $(impl
)/%,%,$(@
)), \
308 $(MAKE
) -C
$(impl
) $(subst $(impl
)/,,$(@
))))
310 # Allow IMPL, and IMPL^STEP
312 $(DO_IMPLS
): $$(foreach s
,$$(STEPS
),$$(call
$$(@
)_STEP_TO_PROG
,$$(s
)))
315 $(foreach i
,$(DO_IMPLS
),$(foreach s
,$(STEPS
),$(i
)^
$(s
))): $$(call
$$(word 1,$$(subst ^
, ,$$(@
)))_STEP_TO_PROG
,$$(word 2,$$(subst ^
, ,$$(@
))))
323 $(ALL_TESTS
): $$(call
$$(word 2,$$(subst ^
, ,$$(@
)))_STEP_TO_PROG
,$$(word 3,$$(subst ^
, ,$$(@
))))
324 @
$(foreach impl
,$(word 2,$(subst ^
, ,$(@
))),\
325 $(foreach step
,$(word 3,$(subst ^
, ,$(@
))),\
326 cd
$(if
$(filter mal
,$(impl
)),$(MAL_IMPL
),$(impl
)) && \
327 $(foreach test,$(call STEP_TEST_FILES
,$(impl
),$(step
)),\
328 echo
'----------------------------------------------' && \
329 echo
'Testing $@, step file: $+, test file: $(test)' && \
330 echo
'Running: $(call get_run_prefix,$(impl))../runtest.py $(TEST_OPTS) $(call $(impl)_TEST_OPTS) ../$(test) -- $(call $(impl)_RUNSTEP,$(step),$(+))' && \
331 $(call get_run_prefix
,$(impl
))..
/runtest.py
$(TEST_OPTS
) $(call
$(impl
)_TEST_OPTS
) ..
/$(test) -- $(call
$(impl
)_RUNSTEP
,$(step
),$(+)) &&) \
334 # Allow test, tests, test^STEP, test^IMPL, and test^IMPL^STEP
339 $(IMPL_TESTS
): $$(filter $$@^
%,$$(ALL_TESTS
))
342 $(STEP_TESTS
): $$(foreach step
,$$(subst test^
,,$$@
),$$(filter %^
$$(step
),$$(ALL_TESTS
)))
353 @echo
"----------------------------------------------"; \
354 $(foreach impl
,$(word 2,$(subst ^
, ,$(@
))),\
355 echo
"Running: make -C $(impl) dist"; \
356 $(MAKE
) --no-print-directory
-C
$(impl
) dist)
363 docker-build
: $(DOCKER_BUILD
)
367 echo
"----------------------------------------------"; \
368 $(foreach impl
,$(word 2,$(subst ^
, ,$(@
))),\
369 echo
"Running: docker build -t $(call impl_to_image,$(impl)) .:"; \
370 cd
$(impl
) && docker build
-t
$(call impl_to_image
,$(impl
)) .
)
374 # Performance test rules
381 @echo
"----------------------------------------------"; \
382 $(foreach impl
,$(word 2,$(subst ^
, ,$(@
))),\
383 cd
$(if
$(filter mal
,$(impl
)),$(MAL_IMPL
),$(impl
)); \
384 echo
"Performance test for $(impl):"; \
385 echo
'Running: $(call get_run_prefix,$(impl))$(call $(impl)_RUNSTEP,stepA,$(call $(impl)_STEP_TO_PROG,stepA),../tests/perf1.mal)'; \
386 $(call get_run_prefix
,$(impl
))$(call
$(impl
)_RUNSTEP
,stepA
,$(call
$(impl
)_STEP_TO_PROG
,stepA
),..
/tests
/perf1.mal
); \
387 echo
'Running: $(call $(impl)_RUNSTEP,stepA,$(call $(impl)_STEP_TO_PROG,stepA),../tests/perf2.mal)'; \
388 $(call get_run_prefix
,$(impl
))$(call
$(impl
)_RUNSTEP
,stepA
,$(call
$(impl
)_STEP_TO_PROG
,stepA
),..
/tests
/perf2.mal
); \
389 echo
'Running: $(call $(impl)_RUNSTEP,stepA,$(call $(impl)_STEP_TO_PROG,stepA),../tests/perf3.mal)'; \
390 $(call get_run_prefix
,$(impl
))$(call
$(impl
)_RUNSTEP
,stepA
,$(call
$(impl
)_STEP_TO_PROG
,stepA
),..
/tests
/perf3.mal
))
394 # REPL invocation rules
398 $(ALL_REPL
): $$(call
$$(word 2,$$(subst ^
, ,$$(@
)))_STEP_TO_PROG
,$$(word 3,$$(subst ^
, ,$$(@
))))
399 @
$(foreach impl
,$(word 2,$(subst ^
, ,$(@
))),\
400 $(foreach step
,$(word 3,$(subst ^
, ,$(@
))),\
401 cd
$(if
$(filter mal
,$(impl
)),$(MAL_IMPL
),$(impl
)); \
402 echo
'REPL implementation $(impl), step file: $+'; \
403 echo
'Running: $(call get_run_prefix,$(impl))$(call $(impl)_RUNSTEP,$(step),$(+))'; \
404 $(call get_run_prefix
,$(impl
))$(call
$(impl
)_RUNSTEP
,$(step
),$(+));))
406 # Allow repl^IMPL^STEP and repl^IMPL (which starts REPL of stepA)
408 $(IMPL_REPL
): $$@^stepA
418 # Recursive rules (call make FOO in each subdirectory)
421 define recur_template
426 @echo
"----------------------------------------------"; \
427 $$(foreach impl
,$$(word 2,$$(subst ^
, ,$$(@
))),\
428 $$(if
$$(DOCKERIZE
), \
429 echo
"Running: $$(call get_build_prefix,$$(impl))$$(MAKE) --no-print-directory $(1)"; \
430 $$(call get_build_prefix
,$$(impl
))$$(MAKE
) --no-print-directory
$(1), \
431 echo
"Running: $$(MAKE) --no-print-directory -C $$(impl) $(1)"; \
432 $$(MAKE
) --no-print-directory
-C
$$(impl
) $(1)))
435 recur_impls_
= $(filter-out $(foreach impl
,$($(1)_EXCLUDES
),$(1)^
$(impl
)),$(foreach impl
,$(IMPLS
),$(1)^
$(impl
)))
438 $(eval
$(call recur_template
,clean,$(call recur_impls_
,clean)))
441 $(eval
$(call recur_template
,stats
,$(call recur_impls_
,stats
)))
442 $(eval
$(call recur_template
,stats-lisp
,$(call recur_impls_
,stats-lisp
)))
445 $(eval
$(call recur_template
,dist,$(call recur_impls_
,dist)))