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
63 # Extra implementation specific options to pass to runtest.py
64 logo_TEST_OPTS
= --start-timeout
60 --test-timeout
120
65 mal_TEST_OPTS
= --start-timeout
60 --test-timeout
120
66 miniMAL_TEST_OPTS
= --start-timeout
60 --test-timeout
120
67 plpgsql_TEST_OPTS
= --start-timeout
60 --test-timeout
180
68 plsql_TEST_OPTS
= --start-timeout
120 --test-timeout
120
69 perl6_TEST_OPTS
= --test-timeout
=60
73 # Run target/rule within docker image for the implementation
80 IMPLS
= ada awk bash c d clojure coffee
cpp crystal cs erlang elisp \
81 elixir es6 factor forth fsharp go groovy guile haskell haxe \
82 io java julia js kotlin logo lua make mal ocaml matlab miniMAL \
83 nim objc objpascal perl perl6 php plpgsql plsql ps python r \
84 racket rpython ruby rust scala swift swift3 tcl vb vhdl vimscript
87 step1
= step1_read_print
90 step4
= step4_if_fn_do
100 regress_step2
= step2
101 regress_step3
= $(regress_step2
) step3
102 regress_step4
= $(regress_step3
) step4
103 regress_step5
= $(regress_step4
) step5
104 regress_step6
= $(regress_step5
) step6
105 regress_step7
= $(regress_step6
) step7
106 regress_step8
= $(regress_step7
) step8
107 regress_step9
= $(regress_step8
) step9
108 regress_stepA
= $(regress_step9
) stepA
110 test_EXCLUDES
+= test^bash^step5
# never completes at 10,000
111 test_EXCLUDES
+= test^logo^step5
# too slow for 10,000
112 test_EXCLUDES
+= test^make^step5
# no TCO capability (iteration or recursion)
113 test_EXCLUDES
+= test^mal^step5
# host impl dependent
114 test_EXCLUDES
+= test^matlab^step5
# never completes at 10,000
115 test_EXCLUDES
+= test^plpgsql^step5
# too slow for 10,000
116 test_EXCLUDES
+= test^plsql^step5
# too slow for 10,000
118 perf_EXCLUDES
= mal
# TODO: fix this
121 # TODO: still need to implement dist
122 dist_EXCLUDES
+= guile io julia matlab swift
128 haxe_STEP_TO_PROG_neko
= haxe
/$($(1)).n
129 haxe_STEP_TO_PROG_python
= haxe
/$($(1)).py
130 haxe_STEP_TO_PROG_cpp
= haxe
/cpp/$($(1))
131 haxe_STEP_TO_PROG_js
= haxe
/$($(1)).js
133 opt_DEFERRABLE
= $(if
$(strip $(DEFERRABLE
)),$(if
$(filter t true T True TRUE
1 y yes Yes YES
,$(DEFERRABLE
)),--deferrable
,--no-deferrable
),--no-deferrable
)
134 opt_OPTIONAL
= $(if
$(strip $(OPTIONAL
)),$(if
$(filter t true T True TRUE
1 y yes Yes YES
,$(OPTIONAL
)),--optional
,--no-optional
),--no-optional
)
136 # Return list of test files for a given step. If REGRESS is set then
137 # test files will include step 2 tests through tests for the step
139 STEP_TEST_FILES
= $(strip $(wildcard \
140 $(foreach s
,$(if
$(strip $(REGRESS
)),$(regress_
$(2)),$(2)),\
141 $(1)/tests
/$($(s
)).mal tests
/$($(s
)).mal
)))
143 # Map of step (e.g. "step8") to executable file for that step
144 ada_STEP_TO_PROG
= ada
/$($(1))
145 awk_STEP_TO_PROG
= awk
/$($(1)).awk
146 bash_STEP_TO_PROG
= bash
/$($(1)).sh
147 c_STEP_TO_PROG
= c
/$($(1))
148 d_STEP_TO_PROG
= d
/$($(1))
149 clojure_STEP_TO_PROG
= clojure
/target
/$($(1)).jar
150 coffee_STEP_TO_PROG
= coffee
/$($(1)).coffee
151 cpp_STEP_TO_PROG
= cpp/$($(1))
152 crystal_STEP_TO_PROG
= crystal
/$($(1))
153 cs_STEP_TO_PROG
= cs
/$($(1)).exe
154 elisp_STEP_TO_PROG
= elisp
/$($(1)).el
155 elixir_STEP_TO_PROG
= elixir
/lib
/mix
/tasks
/$($(1)).ex
156 erlang_STEP_TO_PROG
= erlang
/$($(1))
157 es6_STEP_TO_PROG
= es6
/build
/$($(1)).js
158 factor_STEP_TO_PROG
= factor
/$($(1))/$($(1)).factor
159 forth_STEP_TO_PROG
= forth
/$($(1)).fs
160 fsharp_STEP_TO_PROG
= fsharp
/$($(1)).exe
161 go_STEP_TO_PROG
= go
/$($(1))
162 groovy_STEP_TO_PROG
= groovy
/$($(1)).groovy
163 java_STEP_TO_PROG
= java
/target
/classes
/mal
/$($(1)).class
164 haskell_STEP_TO_PROG
= haskell
/$($(1))
165 haxe_STEP_TO_PROG
= $(haxe_STEP_TO_PROG_
$(HAXE_MODE
))
166 io_STEP_TO_PROG
= io
/$($(1)).io
167 julia_STEP_TO_PROG
= julia
/$($(1)).jl
168 js_STEP_TO_PROG
= js
/$($(1)).js
169 kotlin_STEP_TO_PROG
= kotlin
/$($(1)).jar
170 lua_STEP_TO_PROG
= lua
/$($(1)).lua
171 make_STEP_TO_PROG
= make
/$($(1)).mk
172 mal_STEP_TO_PROG
= mal
/$($(1)).mal
173 ocaml_STEP_TO_PROG
= ocaml
/$($(1))
174 matlab_STEP_TO_PROG
= matlab
/$($(1)).m
175 miniMAL_STEP_TO_PROG
= miniMAL
/$($(1)).json
176 nim_STEP_TO_PROG
= nim
/$($(1))
177 objc_STEP_TO_PROG
= objc
/$($(1))
178 objpascal_STEP_TO_PROG
= objpascal
/$($(1))
179 perl_STEP_TO_PROG
= perl
/$($(1)).pl
180 perl6_STEP_TO_PROG
= perl6
/$($(1)).pl
181 php_STEP_TO_PROG
= php
/$($(1)).php
182 plpgsql_STEP_TO_PROG
= plpgsql
/$($(1)).sql
183 plsql_STEP_TO_PROG
= plsql
/$($(1)).sql
184 ps_STEP_TO_PROG
= ps
/$($(1)).ps
185 python_STEP_TO_PROG
= python
/$($(1)).py
186 r_STEP_TO_PROG
= r
/$($(1)).r
187 racket_STEP_TO_PROG
= racket
/$($(1)).rkt
188 rpython_STEP_TO_PROG
= rpython
/$($(1))
189 ruby_STEP_TO_PROG
= ruby
/$($(1)).rb
190 rust_STEP_TO_PROG
= rust
/target
/release
/$($(1))
191 scala_STEP_TO_PROG
= scala
/target
/scala-2.11
/classes
/$($(1)).class
192 swift_STEP_TO_PROG
= swift
/$($(1))
193 swift3_STEP_TO_PROG
= swift3
/$($(1))
194 tcl_STEP_TO_PROG
= tcl
/$($(1)).tcl
195 vb_STEP_TO_PROG
= vb
/$($(1)).exe
196 vhdl_STEP_TO_PROG
= vhdl
/$($(1))
197 vimscript_STEP_TO_PROG
= vimscript
/$($(1)).vim
198 guile_STEP_TO_PROG
= guile
/$($(1)).scm
201 # Needed some argument munging
204 SPACE
= $(noop
) $(noop
)
205 export FACTOR_ROOTS
:= .
207 # DOCKERIZE utility functions
208 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))))))))))))))))))))))))))
209 impl_to_image
= kanaka
/mal-test-
$(call lc
,$(1))
211 actual_impl
= $(if
$(filter mal
,$(1)),$(MAL_IMPL
),$(1))
214 # Returns nothing if DOCKERIZE is not set, otherwise returns the
215 # docker prefix necessary to run make within the docker environment
217 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)) ,)
219 # Takes impl and step arguments
220 # Returns a command prefix (docker command and environment variables)
221 # necessary to launch the given impl and step
222 get_run_prefix
= $(strip $(if
$(strip $(DOCKERIZE
)),\
223 docker run
-e STEP
=$($2) \
224 -it
--rm -u
$(shell id
-u
) \
225 -v
$(dir $(abspath
$(lastword
$(MAKEFILE_LIST
)))):/mal \
226 -w
/mal
/$(call actual_impl
,$(1)) \
227 $(if
$(filter haxe
,$(1)),-e HAXE_MODE
=$(HAXE_MODE
),) \
228 $(if
$(filter factor
,$(1)),-e FACTOR_ROOTS
=$(FACTOR_ROOTS
),) \
229 $(foreach env
,$(3),-e
$(env
)) \
230 $(call impl_to_image
,$(call actual_impl
,$(1))) \
233 $(if
$(filter haxe
,$(1)),HAXE_MODE
=$(HAXE_MODE
),) \
234 $(if
$(filter factor
,$(1)),FACTOR_ROOTS
=$(FACTOR_ROOTS
),) \
237 # Takes impl and step
238 # Returns the runtest command prefix (with runtest options) for testing the given step
239 get_runtest_cmd
= $(call get_run_prefix
,$(1),$(2),$(if
$(filter cs fsharp tcl vb
,$(1)),RAW
=1,)) \
240 ..
/runtest.py
$(opt_DEFERRABLE
) $(opt_OPTIONAL
) $(call
$(1)_TEST_OPTS
) $(TEST_OPTS
)
242 # Takes impl and step
243 # Returns the runtest command prefix (with runtest options) for testing the given step
244 get_argvtest_cmd
= $(call get_run_prefix
,$(1),$(2)) ..
/run_argv_test.sh
246 vimscript_TEST_OPTS
= --test-timeout
30
247 ifeq ($(MAL_IMPL
),vimscript
)
248 mal_TEST_OPTS
= --start-timeout
60 --test-timeout
180
252 STEPS
= $(sort $(filter step
%,$(.VARIABLES
)))
253 DO_IMPLS
= $(filter-out $(SKIP_IMPLS
),$(IMPLS
))
254 IMPL_TESTS
= $(foreach impl
,$(DO_IMPLS
),test^
$(impl
))
255 STEP_TESTS
= $(foreach step
,$(STEPS
),test^
$(step
))
256 ALL_TESTS
= $(filter-out $(test_EXCLUDES
),\
258 $(foreach impl
,$(DO_IMPLS
),\
259 $(foreach step
,$(STEPS
),test^
$(impl
)^
$(step
))))))
261 DOCKER_BUILD
= $(foreach impl
,$(DO_IMPLS
),docker-build^
$(impl
))
263 IMPL_PERF
= $(foreach impl
,$(filter-out $(perf_EXCLUDES
),$(DO_IMPLS
)),perf^
$(impl
))
265 IMPL_REPL
= $(foreach impl
,$(DO_IMPLS
),repl^
$(impl
))
266 ALL_REPL
= $(strip $(sort \
267 $(foreach impl
,$(DO_IMPLS
),\
268 $(foreach step
,$(STEPS
),repl^
$(impl
)^
$(step
)))))
274 # Build a program in an implementation directory
275 # Make sure we always try and build first because the dependencies are
276 # encoded in the implementation Makefile not here
277 .PHONY
: $(foreach i
,$(DO_IMPLS
),$(foreach s
,$(STEPS
),$(call
$(i
)_STEP_TO_PROG
,$(s
))))
278 $(foreach i
,$(DO_IMPLS
),$(foreach s
,$(STEPS
),$(call
$(i
)_STEP_TO_PROG
,$(s
)))):
279 $(foreach impl
,$(word 1,$(subst /, ,$(@
))),\
281 $(call get_build_prefix
,$(impl
))$(MAKE
) $(patsubst $(impl
)/%,%,$(@
)), \
282 $(MAKE
) -C
$(impl
) $(subst $(impl
)/,,$(@
))))
284 # Allow IMPL, and IMPL^STEP
286 $(DO_IMPLS
): $$(foreach s
,$$(STEPS
),$$(call
$$(@
)_STEP_TO_PROG
,$$(s
)))
289 $(foreach i
,$(DO_IMPLS
),$(foreach s
,$(STEPS
),$(i
)^
$(s
))): $$(call
$$(word 1,$$(subst ^
, ,$$(@
)))_STEP_TO_PROG
,$$(word 2,$$(subst ^
, ,$$(@
))))
297 $(ALL_TESTS
): $$(call
$$(word 2,$$(subst ^
, ,$$(@
)))_STEP_TO_PROG
,$$(word 3,$$(subst ^
, ,$$(@
))))
298 @
$(foreach impl
,$(word 2,$(subst ^
, ,$(@
))),\
299 $(foreach step
,$(word 3,$(subst ^
, ,$(@
))),\
300 cd
$(if
$(filter mal
,$(impl
)),$(MAL_IMPL
),$(impl
)) && \
301 $(foreach test,$(call STEP_TEST_FILES
,$(impl
),$(step
)),\
302 echo
'----------------------------------------------' && \
303 echo
'Testing $@; step file: $+, test file: $(test)' && \
304 echo
'Running: $(call get_runtest_cmd,$(impl),$(step)) ../$(test) -- ../$(impl)/run' && \
305 $(call get_runtest_cmd
,$(impl
),$(step
)) ..
/$(test) -- ..
/$(impl
)/run
&& \
306 $(if
$(filter tests
/step6_file.mal
,$(test)),\
307 echo
'----------------------------------------------' && \
308 echo
'Testing ARGV of $@; step file: $+' && \
309 echo
'Running: $(call get_argvtest_cmd,$(impl),$(step)) ../$(impl)/run ' && \
310 $(call get_argvtest_cmd
,$(impl
),$(step
)) ..
/$(impl
)/run
&& ,\
314 # Allow test, tests, test^STEP, test^IMPL, and test^IMPL^STEP
319 $(IMPL_TESTS
): $$(filter $$@^
%,$$(ALL_TESTS
))
322 $(STEP_TESTS
): $$(foreach step
,$$(subst test^
,,$$@
),$$(filter %^
$$(step
),$$(ALL_TESTS
)))
333 @echo
"----------------------------------------------"; \
334 $(foreach impl
,$(word 2,$(subst ^
, ,$(@
))),\
335 echo
"Running: make -C $(impl) dist"; \
336 $(MAKE
) --no-print-directory
-C
$(impl
) dist)
343 docker-build
: $(DOCKER_BUILD
)
347 echo
"----------------------------------------------"; \
348 $(foreach impl
,$(word 2,$(subst ^
, ,$(@
))),\
349 echo
"Running: docker build -t $(call impl_to_image,$(impl)) .:"; \
350 cd
$(impl
) && docker build
-t
$(call impl_to_image
,$(impl
)) .
)
354 # Performance test rules
361 @echo
"----------------------------------------------"; \
362 $(foreach impl
,$(word 2,$(subst ^
, ,$(@
))),\
363 cd
$(if
$(filter mal
,$(impl
)),$(MAL_IMPL
),$(impl
)); \
364 echo
"Performance test for $(impl):"; \
365 echo
'Running: $(call get_run_prefix,$(impl),stepA) ../$(impl)/run ../tests/perf1.mal'; \
366 $(call get_run_prefix
,$(impl
),stepA
) ..
/$(impl
)/run ..
/tests
/perf1.mal
; \
367 echo
'Running: $(call get_run_prefix,$(impl),stepA) ../$(impl)/run ../tests/perf2.mal'; \
368 $(call get_run_prefix
,$(impl
),stepA
) ..
/$(impl
)/run ..
/tests
/perf2.mal
; \
369 echo
'Running: $(call get_run_prefix,$(impl),stepA) ../$(impl)/run ../tests/perf3.mal'; \
370 $(call get_run_prefix
,$(impl
),stepA
) ..
/$(impl
)/run ..
/tests
/perf3.mal
)
374 # REPL invocation rules
378 $(ALL_REPL
): $$(call
$$(word 2,$$(subst ^
, ,$$(@
)))_STEP_TO_PROG
,$$(word 3,$$(subst ^
, ,$$(@
))))
379 @
$(foreach impl
,$(word 2,$(subst ^
, ,$(@
))),\
380 $(foreach step
,$(word 3,$(subst ^
, ,$(@
))),\
381 cd
$(if
$(filter mal
,$(impl
)),$(MAL_IMPL
),$(impl
)); \
382 echo
'REPL implementation $(impl), step file: $+'; \
383 echo
'Running: $(call get_run_prefix,$(impl),$(step)) ../$(impl)/run'; \
384 $(call get_run_prefix
,$(impl
),$(step
)) ..
/$(impl
)/run
;))
386 # Allow repl^IMPL^STEP and repl^IMPL (which starts REPL of stepA)
388 $(IMPL_REPL
): $$@^stepA
398 # Recursive rules (call make FOO in each subdirectory)
401 define recur_template
406 @echo
"----------------------------------------------"; \
407 $$(foreach impl
,$$(word 2,$$(subst ^
, ,$$(@
))),\
408 $$(if
$$(DOCKERIZE
), \
409 echo
"Running: $$(call get_build_prefix,$$(impl))$$(MAKE) --no-print-directory $(1)"; \
410 $$(call get_build_prefix
,$$(impl
))$$(MAKE
) --no-print-directory
$(1), \
411 echo
"Running: $$(MAKE) --no-print-directory -C $$(impl) $(1)"; \
412 $$(MAKE
) --no-print-directory
-C
$$(impl
) $(1)))
415 recur_impls_
= $(filter-out $(foreach impl
,$($(1)_EXCLUDES
),$(1)^
$(impl
)),$(foreach impl
,$(IMPLS
),$(1)^
$(impl
)))
418 $(eval
$(call recur_template
,clean,$(call recur_impls_
,clean)))
421 $(eval
$(call recur_template
,stats
,$(call recur_impls_
,stats
)))
422 $(eval
$(call recur_template
,stats-lisp
,$(call recur_impls_
,stats-lisp
)))
425 $(eval
$(call recur_template
,dist,$(call recur_impls_
,dist)))