| 1 | # Usage/help |
| 2 | all help: |
| 3 | @echo |
| 4 | @echo 'USAGE:' |
| 5 | @echo |
| 6 | @echo 'Rules/Targets:' |
| 7 | @echo |
| 8 | @echo 'make "IMPL" # build all steps of IMPL' |
| 9 | @echo 'make "build^IMPL" # build all steps of IMPL' |
| 10 | @echo 'make "IMPL^STEP" # build STEP of IMPL' |
| 11 | @echo 'make "build^IMPL^STEP" # build STEP of IMPL' |
| 12 | @echo |
| 13 | @echo 'make "test" # test all implementations' |
| 14 | @echo 'make "test^IMPL" # test all steps of IMPL' |
| 15 | @echo 'make "test^STEP" # test STEP for all implementations' |
| 16 | @echo 'make "test^IMPL^STEP" # test STEP of IMPL' |
| 17 | @echo |
| 18 | @echo 'make "perf" # run microbenchmarks for all implementations' |
| 19 | @echo 'make "perf^IMPL" # run microbenchmarks for IMPL' |
| 20 | @echo |
| 21 | @echo 'make "repl^IMPL" # run stepA of IMPL' |
| 22 | @echo 'make "repl^IMPL^STEP" # test STEP of IMPL' |
| 23 | @echo |
| 24 | @echo 'make "clean" # run 'make clean' for all implementations' |
| 25 | @echo 'make "clean^IMPL" # run 'make clean' for IMPL' |
| 26 | @echo |
| 27 | @echo 'make "stats" # run 'make stats' for all implementations' |
| 28 | @echo 'make "stats-lisp" # run 'make stats-lisp' for all implementations' |
| 29 | @echo 'make "stats^IMPL" # run 'make stats' for IMPL' |
| 30 | @echo 'make "stats-lisp^IMPL" # run 'make stats-lisp' for IMPL' |
| 31 | @echo |
| 32 | @echo 'Options/Settings:' |
| 33 | @echo |
| 34 | @echo 'make MAL_IMPL=IMPL "test^mal..." # use IMPL for self-host tests' |
| 35 | @echo 'make REGRESS=1 "test..." # test with previous step tests too' |
| 36 | @echo 'make DOCKERIZE=1 ... # to dockerize above rules/targets' |
| 37 | @echo 'make TEST_OPTS="--opt ..." # options to pass to runtest.py' |
| 38 | @echo |
| 39 | @echo 'Other:' |
| 40 | @echo |
| 41 | @echo 'make "docker-build^IMPL" # build docker image for IMPL' |
| 42 | @echo |
| 43 | @echo 'make "docker-shell^IMPL" # start bash shell in docker image for IMPL' |
| 44 | @echo |
| 45 | |
| 46 | # |
| 47 | # Command line settings |
| 48 | # |
| 49 | |
| 50 | MAL_IMPL = js |
| 51 | |
| 52 | # cbm or qbasic |
| 53 | basic_MODE = cbm |
| 54 | # clj or cljs (Clojure vs ClojureScript/lumo) |
| 55 | clojure_MODE = clj |
| 56 | # gdc, ldc2, or dmd |
| 57 | d_MODE = gdc |
| 58 | # python, js, cpp, or neko |
| 59 | haxe_MODE = neko |
| 60 | # octave or matlab |
| 61 | matlab_MODE = octave |
| 62 | # python, python2 or python3 |
| 63 | python_MODE = python |
| 64 | # scheme (chibi, kawa, gauche, chicken, sagittarius, cyclone, foment) |
| 65 | scheme_MODE = chibi |
| 66 | # wasmtime wasmer lucet wax node warpy wace_libc |
| 67 | wasm_MODE = wasmtime |
| 68 | |
| 69 | # Path to loccount for counting LOC stats |
| 70 | LOCCOUNT = loccount |
| 71 | |
| 72 | # Extra options to pass to runtest.py |
| 73 | TEST_OPTS = |
| 74 | |
| 75 | # Test with previous test files not just the test files for the |
| 76 | # current step. Step 0 and 1 tests are special and not included in |
| 77 | # later steps. |
| 78 | REGRESS = |
| 79 | |
| 80 | HARD= |
| 81 | DEFERRABLE=1 |
| 82 | OPTIONAL=1 |
| 83 | |
| 84 | # Run target/rule within docker image for the implementation |
| 85 | DOCKERIZE = |
| 86 | |
| 87 | |
| 88 | # |
| 89 | # Implementation specific settings |
| 90 | # |
| 91 | |
| 92 | IMPLS = ada ada.2 awk bash basic bbc-basic c chuck clojure coffee common-lisp cpp crystal cs d dart \ |
| 93 | elisp elixir elm erlang es6 factor fantom forth fsharp go groovy gnu-smalltalk \ |
| 94 | guile haskell haxe hy io java js jq julia kotlin livescript logo lua make mal \ |
| 95 | matlab miniMAL nasm nim objc objpascal ocaml perl perl6 php picolisp pike plpgsql \ |
| 96 | plsql powershell ps python python.2 r racket rexx rpython ruby rust scala scheme skew \ |
| 97 | swift swift3 swift4 swift5 tcl ts vala vb vhdl vimscript wasm wren yorick xslt zig |
| 98 | |
| 99 | EXTENSION = .mal |
| 100 | |
| 101 | step0 = step0_repl |
| 102 | step1 = step1_read_print |
| 103 | step2 = step2_eval |
| 104 | step3 = step3_env |
| 105 | step4 = step4_if_fn_do |
| 106 | step5 = step5_tco |
| 107 | step6 = step6_file |
| 108 | step7 = step7_quote |
| 109 | step8 = step8_macros |
| 110 | step9 = step9_try |
| 111 | stepA = stepA_mal |
| 112 | |
| 113 | argv_STEP = step6_file |
| 114 | |
| 115 | |
| 116 | regress_step0 = step0 |
| 117 | regress_step1 = step1 |
| 118 | regress_step2 = step2 |
| 119 | regress_step3 = $(regress_step2) step3 |
| 120 | regress_step4 = $(regress_step3) step4 |
| 121 | regress_step5 = $(regress_step4) step5 |
| 122 | regress_step6 = $(regress_step5) step6 |
| 123 | regress_step7 = $(regress_step6) step7 |
| 124 | regress_step8 = $(regress_step7) step8 |
| 125 | regress_step9 = $(regress_step8) step9 |
| 126 | regress_stepA = $(regress_step9) stepA |
| 127 | |
| 128 | step5_EXCLUDES += bash # never completes at 10,000 |
| 129 | step5_EXCLUDES += basic # too slow, and limited to ints of 2^16 |
| 130 | step5_EXCLUDES += logo # too slow for 10,000 |
| 131 | step5_EXCLUDES += make # no TCO capability (iteration or recursion) |
| 132 | step5_EXCLUDES += mal # host impl dependent |
| 133 | step5_EXCLUDES += matlab # never completes at 10,000 |
| 134 | step5_EXCLUDES += plpgsql # too slow for 10,000 |
| 135 | step5_EXCLUDES += plsql # too slow for 10,000 |
| 136 | step5_EXCLUDES += powershell # too slow for 10,000 |
| 137 | step5_EXCLUDES += $(if $(filter cpp,$(haxe_MODE)),haxe,) # cpp finishes 10,000, segfaults at 100,000 |
| 138 | |
| 139 | dist_EXCLUDES += mal |
| 140 | # TODO: still need to implement dist |
| 141 | dist_EXCLUDES += guile io julia matlab swift |
| 142 | |
| 143 | |
| 144 | # Extra options to pass to runtest.py |
| 145 | bbc-basic_TEST_OPTS = --test-timeout 60 |
| 146 | guile_TEST_OPTS = --test-timeout 120 |
| 147 | io_TEST_OPTS = --test-timeout 120 |
| 148 | logo_TEST_OPTS = --start-timeout 60 --test-timeout 120 |
| 149 | mal_TEST_OPTS = --start-timeout 60 --test-timeout 120 |
| 150 | miniMAL_TEST_OPTS = --start-timeout 60 --test-timeout 120 |
| 151 | perl6_TEST_OPTS = --test-timeout=60 |
| 152 | plpgsql_TEST_OPTS = --start-timeout 60 --test-timeout 180 |
| 153 | plsql_TEST_OPTS = --start-timeout 120 --test-timeout 120 |
| 154 | vimscript_TEST_OPTS = --test-timeout 30 |
| 155 | ifeq ($(MAL_IMPL),vimscript) |
| 156 | mal_TEST_OPTS = --start-timeout 60 --test-timeout 180 |
| 157 | else ifeq ($(MAL_IMPL),powershell) |
| 158 | mal_TEST_OPTS = --start-timeout 60 --test-timeout 180 |
| 159 | endif |
| 160 | |
| 161 | |
| 162 | # |
| 163 | # Implementation specific utility functions |
| 164 | # |
| 165 | |
| 166 | basic_STEP_TO_PROG_cbm = impls/basic/$($(1)).bas |
| 167 | basic_STEP_TO_PROG_qbasic = impls/basic/$($(1)) |
| 168 | |
| 169 | clojure_STEP_TO_PROG_clj = impls/clojure/target/$($(1)).jar |
| 170 | clojure_STEP_TO_PROG_cljs = impls/clojure/src/mal/$($(1)).cljc |
| 171 | |
| 172 | haxe_STEP_TO_PROG_neko = impls/haxe/$($(1)).n |
| 173 | haxe_STEP_TO_PROG_python = impls/haxe/$($(1)).py |
| 174 | haxe_STEP_TO_PROG_cpp = impls/haxe/cpp/$($(1)) |
| 175 | haxe_STEP_TO_PROG_js = impls/haxe/$($(1)).js |
| 176 | |
| 177 | scheme_STEP_TO_PROG_chibi = impls/scheme/$($(1)).scm |
| 178 | scheme_STEP_TO_PROG_kawa = impls/scheme/out/$($(1)).class |
| 179 | scheme_STEP_TO_PROG_gauche = impls/scheme/$($(1)).scm |
| 180 | scheme_STEP_TO_PROG_chicken = impls/scheme/$($(1)) |
| 181 | scheme_STEP_TO_PROG_sagittarius = impls/scheme/$($(1)).scm |
| 182 | scheme_STEP_TO_PROG_cyclone = impls/scheme/$($(1)) |
| 183 | scheme_STEP_TO_PROG_foment = impls/scheme/$($(1)).scm |
| 184 | |
| 185 | # Map of step (e.g. "step8") to executable file for that step |
| 186 | ada_STEP_TO_PROG = ada/$($(1)) |
| 187 | ada.2_STEP_TO_PROG = ada.2/$($(1)) |
| 188 | awk_STEP_TO_PROG = awk/$($(1)).awk |
| 189 | bash_STEP_TO_PROG = bash/$($(1)).sh |
| 190 | basic_STEP_TO_PROG = $(basic_STEP_TO_PROG_$(basic_MODE)) |
| 191 | bbc-basic_STEP_TO_PROG = bbc-basic/$($(1)).bas |
| 192 | c_STEP_TO_PROG = c/$($(1)) |
| 193 | chuck_STEP_TO_PROG = chuck/$($(1)).ck |
| 194 | clojure_STEP_TO_PROG = $(clojure_STEP_TO_PROG_$(clojure_MODE)) |
| 195 | coffee_STEP_TO_PROG = coffee/$($(1)).coffee |
| 196 | common-lisp_STEP_TO_PROG = common-lisp/$($(1)) |
| 197 | cpp_STEP_TO_PROG = cpp/$($(1)) |
| 198 | crystal_STEP_TO_PROG = crystal/$($(1)) |
| 199 | cs_STEP_TO_PROG = cs/$($(1)).exe |
| 200 | d_STEP_TO_PROG = d/$($(1)) |
| 201 | dart_STEP_TO_PROG = dart/$($(1)).dart |
| 202 | elisp_STEP_TO_PROG = elisp/$($(1)).el |
| 203 | elixir_STEP_TO_PROG = elixir/lib/mix/tasks/$($(1)).ex |
| 204 | elm_STEP_TO_PROG = elm/$($(1)).js |
| 205 | erlang_STEP_TO_PROG = erlang/$($(1)) |
| 206 | es6_STEP_TO_PROG = es6/$($(1)).mjs |
| 207 | factor_STEP_TO_PROG = factor/$($(1))/$($(1)).factor |
| 208 | fantom_STEP_TO_PROG = fantom/lib/fan/$($(1)).pod |
| 209 | forth_STEP_TO_PROG = forth/$($(1)).fs |
| 210 | fsharp_STEP_TO_PROG = fsharp/$($(1)).exe |
| 211 | go_STEP_TO_PROG = go/$($(1)) |
| 212 | groovy_STEP_TO_PROG = groovy/$($(1)).groovy |
| 213 | gnu-smalltalk_STEP_TO_PROG = gnu-smalltalk/$($(1)).st |
| 214 | guile_STEP_TO_PROG = guile/$($(1)).scm |
| 215 | haskell_STEP_TO_PROG = haskell/$($(1)) |
| 216 | haxe_STEP_TO_PROG = $(haxe_STEP_TO_PROG_$(haxe_MODE)) |
| 217 | hy_STEP_TO_PROG = hy/$($(1)).hy |
| 218 | io_STEP_TO_PROG = io/$($(1)).io |
| 219 | java_STEP_TO_PROG = java/target/classes/mal/$($(1)).class |
| 220 | js_STEP_TO_PROG = js/$($(1)).js |
| 221 | jq_STEP_PROG = jq/$($(1)).jq |
| 222 | julia_STEP_TO_PROG = julia/$($(1)).jl |
| 223 | kotlin_STEP_TO_PROG = kotlin/$($(1)).jar |
| 224 | livescript_STEP_TO_PROG = livescript/$($(1)).js |
| 225 | logo_STEP_TO_PROG = logo/$($(1)).lg |
| 226 | lua_STEP_TO_PROG = lua/$($(1)).lua |
| 227 | make_STEP_TO_PROG = make/$($(1)).mk |
| 228 | mal_STEP_TO_PROG = mal/$($(1)).mal |
| 229 | matlab_STEP_TO_PROG = matlab/$($(1)).m |
| 230 | miniMAL_STEP_TO_PROG = miniMAL/$($(1)).json |
| 231 | nasm_STEP_TO_PROG = nasm/$($(1)) |
| 232 | nim_STEP_TO_PROG = nim/$($(1)) |
| 233 | objc_STEP_TO_PROG = objc/$($(1)) |
| 234 | objpascal_STEP_TO_PROG = objpascal/$($(1)) |
| 235 | ocaml_STEP_TO_PROG = ocaml/$($(1)) |
| 236 | perl_STEP_TO_PROG = perl/$($(1)).pl |
| 237 | perl6_STEP_TO_PROG = perl6/$($(1)).pl |
| 238 | php_STEP_TO_PROG = php/$($(1)).php |
| 239 | picolisp_STEP_TO_PROG = picolisp/$($(1)).l |
| 240 | pike_STEP_TO_PROG = pike/$($(1)).pike |
| 241 | plpgsql_STEP_TO_PROG = plpgsql/$($(1)).sql |
| 242 | plsql_STEP_TO_PROG = plsql/$($(1)).sql |
| 243 | powershell_STEP_TO_PROG = powershell/$($(1)).ps1 |
| 244 | ps_STEP_TO_PROG = ps/$($(1)).ps |
| 245 | python_STEP_TO_PROG = python/$($(1)).py |
| 246 | python.2_STEP_TO_PROG = python.2/$($(1)).py |
| 247 | r_STEP_TO_PROG = r/$($(1)).r |
| 248 | racket_STEP_TO_PROG = racket/$($(1)).rkt |
| 249 | rexx_STEP_TO_PROG = rexx/$($(1)).rexxpp |
| 250 | rpython_STEP_TO_PROG = rpython/$($(1)) |
| 251 | ruby_STEP_TO_PROG = ruby/$($(1)).rb |
| 252 | rust_STEP_TO_PROG = rust/$($(1)) |
| 253 | scala_STEP_TO_PROG = scala/target/scala-2.11/classes/$($(1)).class |
| 254 | scheme_STEP_TO_PROG = $(scheme_STEP_TO_PROG_$(scheme_MODE)) |
| 255 | skew_STEP_TO_PROG = skew/$($(1)).js |
| 256 | swift_STEP_TO_PROG = swift/$($(1)) |
| 257 | swift3_STEP_TO_PROG = swift3/$($(1)) |
| 258 | swift4_STEP_TO_PROG = swift4/$($(1)) |
| 259 | swift5_STEP_TO_PROG = swift5/$($(1)) |
| 260 | tcl_STEP_TO_PROG = tcl/$($(1)).tcl |
| 261 | ts_STEP_TO_PROG = ts/$($(1)).js |
| 262 | vala_STEP_TO_PROG = vala/$($(1)) |
| 263 | vb_STEP_TO_PROG = vb/$($(1)).exe |
| 264 | vhdl_STEP_TO_PROG = vhdl/$($(1)) |
| 265 | vimscript_STEP_TO_PROG = vimscript/$($(1)).vim |
| 266 | wasm_STEP_TO_PROG = wasm/$($(1)).$(if $(filter lucet,$(wasm_MODE)),so,wasm) |
| 267 | wren_STEP_TO_PROG = wren/$($(1)).wren |
| 268 | yorick_STEP_TO_PROG = yorick/$($(1)).i |
| 269 | xslt_STEP_TO_PROG = xslt/$($(1)) |
| 270 | zig_STEP_TO_PROG = zig/$($(1)) |
| 271 | |
| 272 | # |
| 273 | # General settings and utility functions |
| 274 | # |
| 275 | |
| 276 | # Needed some argument munging |
| 277 | COMMA = , |
| 278 | noop = |
| 279 | SPACE = $(noop) $(noop) |
| 280 | export FACTOR_ROOTS := . |
| 281 | |
| 282 | opt_HARD = $(if $(strip $(HARD)),$(if $(filter t true T True TRUE 1 y yes Yes YES,$(HARD)),--hard,),) |
| 283 | opt_DEFERRABLE = $(if $(strip $(DEFERRABLE)),$(if $(filter t true T True TRUE 1 y yes Yes YES,$(DEFERRABLE)),--deferrable,--no-deferrable),--no-deferrable) |
| 284 | opt_OPTIONAL = $(if $(strip $(OPTIONAL)),$(if $(filter t true T True TRUE 1 y yes Yes YES,$(OPTIONAL)),--optional,--no-optional),--no-optional) |
| 285 | |
| 286 | # Return list of test files for a given step. If REGRESS is set then |
| 287 | # test files will include step 2 tests through tests for the step |
| 288 | # being tested. |
| 289 | STEP_TEST_FILES = $(strip $(wildcard \ |
| 290 | $(foreach s,$(if $(strip $(REGRESS)),\ |
| 291 | $(filter-out $(if $(filter $(1),$(step5_EXCLUDES)),step5,),\ |
| 292 | $(regress_$(2)))\ |
| 293 | ,$(2)),\ |
| 294 | impls/$(1)/tests/$($(s))$(EXTENSION) impls/tests/$($(s))$(EXTENSION)))) |
| 295 | |
| 296 | # DOCKERIZE utility functions |
| 297 | 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)))))))))))))))))))))))))) |
| 298 | impl_to_image = kanaka/mal-test-$(call lc,$(1)) |
| 299 | |
| 300 | actual_impl = $(if $(filter mal,$(1)),$(patsubst %-mal,%,$(MAL_IMPL)),$(1)) |
| 301 | |
| 302 | # Takes impl |
| 303 | # Returns nothing if DOCKERIZE is not set, otherwise returns the |
| 304 | # docker prefix necessary to run make within the docker environment |
| 305 | # for this impl |
| 306 | get_build_command = $(strip $(foreach mode,$(1)_MODE, \ |
| 307 | $(if $(strip $(DOCKERIZE)),\ |
| 308 | docker run \ |
| 309 | -it --rm -u $(shell id -u) \ |
| 310 | -v $(dir $(abspath $(lastword $(MAKEFILE_LIST)))):/mal \ |
| 311 | -w /mal/impls/$(1) \ |
| 312 | $(if $(strip $($(mode))),-e $(mode)=$($(mode)),) \ |
| 313 | $(if $(filter factor,$(1)),-e FACTOR_ROOTS=$(FACTOR_ROOTS),) \ |
| 314 | $(call impl_to_image,$(1)) \ |
| 315 | $(MAKE) $(if $(strip $($(mode))),$(mode)=$($(mode)),) \ |
| 316 | ,\ |
| 317 | $(MAKE) $(if $(strip $($(mode))),$(mode)=$($(mode)),) -C impls/$(impl)))) |
| 318 | |
| 319 | # Takes impl and step args. Optional env vars and dockerize args |
| 320 | # Returns a command prefix (docker command and environment variables) |
| 321 | # necessary to launch the given impl and step |
| 322 | get_run_prefix = $(strip $(foreach mode,$(call actual_impl,$(1))_MODE, \ |
| 323 | $(if $(strip $(DOCKERIZE) $(4)),\ |
| 324 | docker run -e STEP=$($2) -e MAL_IMPL=$(MAL_IMPL) \ |
| 325 | -it --rm -u $(shell id -u) \ |
| 326 | -v $(dir $(abspath $(lastword $(MAKEFILE_LIST)))):/mal \ |
| 327 | -w /mal/impls/$(call actual_impl,$(1)) \ |
| 328 | $(if $(strip $($(mode))),-e $(mode)=$($(mode)),) \ |
| 329 | $(if $(filter factor,$(1)),-e FACTOR_ROOTS=$(FACTOR_ROOTS),) \ |
| 330 | $(foreach env,$(3),-e $(env)) \ |
| 331 | $(call impl_to_image,$(call actual_impl,$(1))) \ |
| 332 | ,\ |
| 333 | env STEP=$($2) MAL_IMPL=$(MAL_IMPL) \ |
| 334 | $(if $(strip $($(mode))),$(mode)=$($(mode)),) \ |
| 335 | $(if $(filter factor,$(1)),FACTOR_ROOTS=$(FACTOR_ROOTS),) \ |
| 336 | $(3)))) |
| 337 | |
| 338 | # Takes impl and step |
| 339 | # Returns the runtest command prefix (with runtest options) for testing the given step |
| 340 | get_runtest_cmd = $(call get_run_prefix,$(1),$(2),$(if $(filter cs fsharp mal tcl vb,$(1)),RAW=1,)) \ |
| 341 | ../../runtest.py $(opt_HARD) $(opt_DEFERRABLE) $(opt_OPTIONAL) $(call $(1)_TEST_OPTS) $(TEST_OPTS) |
| 342 | |
| 343 | # Takes impl and step |
| 344 | # Returns the runtest command prefix (with runtest options) for testing the given step |
| 345 | get_argvtest_cmd = $(call get_run_prefix,$(1),$(2)) ../tests/run_argv_test.sh |
| 346 | |
| 347 | # Derived lists |
| 348 | STEPS = $(sort $(filter-out %_EXCLUDES,$(filter step%,$(.VARIABLES)))) |
| 349 | DO_IMPLS = $(filter-out $(SKIP_IMPLS),$(IMPLS)) |
| 350 | IMPL_TESTS = $(foreach impl,$(DO_IMPLS),test^$(impl)) |
| 351 | STEP_TESTS = $(foreach step,$(STEPS),test^$(step)) |
| 352 | ALL_TESTS = $(filter-out $(foreach e,$(step5_EXCLUDES),test^$(e)^step5),\ |
| 353 | $(strip $(sort \ |
| 354 | $(foreach impl,$(DO_IMPLS),\ |
| 355 | $(foreach step,$(STEPS),test^$(impl)^$(step)))))) |
| 356 | ALL_BUILDS = $(strip $(sort \ |
| 357 | $(foreach impl,$(DO_IMPLS),\ |
| 358 | $(foreach step,$(STEPS),build^$(impl)^$(step))))) |
| 359 | |
| 360 | DOCKER_BUILD = $(foreach impl,$(DO_IMPLS),docker-build^$(impl)) |
| 361 | |
| 362 | DOCKER_SHELL = $(foreach impl,$(DO_IMPLS),docker-shell^$(impl)) |
| 363 | |
| 364 | IMPL_PERF = $(foreach impl,$(filter-out $(perf_EXCLUDES),$(DO_IMPLS)),perf^$(impl)) |
| 365 | |
| 366 | IMPL_STATS = $(foreach impl,$(DO_IMPLS),stats^$(impl)) |
| 367 | |
| 368 | IMPL_REPL = $(foreach impl,$(DO_IMPLS),repl^$(impl)) |
| 369 | ALL_REPL = $(strip $(sort \ |
| 370 | $(foreach impl,$(DO_IMPLS),\ |
| 371 | $(foreach step,$(STEPS),repl^$(impl)^$(step))))) |
| 372 | |
| 373 | |
| 374 | # |
| 375 | # Build rules |
| 376 | # |
| 377 | |
| 378 | # Enable secondary expansion for all rules |
| 379 | .SECONDEXPANSION: |
| 380 | |
| 381 | # Build a program in an implementation directory |
| 382 | # Make sure we always try and build first because the dependencies are |
| 383 | # encoded in the implementation Makefile not here |
| 384 | .PHONY: $(foreach i,$(DO_IMPLS),$(foreach s,$(STEPS),$(call $(i)_STEP_TO_PROG,$(s)))) |
| 385 | $(foreach i,$(DO_IMPLS),$(foreach s,$(STEPS),$(call $(i)_STEP_TO_PROG,$(s)))): |
| 386 | $(foreach impl,$(word 2,$(subst /, ,$(@))),\ |
| 387 | $(if $(DOCKERIZE), \ |
| 388 | $(call get_build_command,$(impl)) $(patsubst impls/$(impl)/%,%,$(@)), \ |
| 389 | $(call get_build_command,$(impl)) $(subst impls/$(impl)/,,$(@)))) |
| 390 | |
| 391 | # Allow IMPL, build^IMPL, IMPL^STEP, and build^IMPL^STEP |
| 392 | $(DO_IMPLS): $$(foreach s,$$(STEPS),$$(call $$(@)_STEP_TO_PROG,$$(s))) |
| 393 | |
| 394 | $(foreach i,$(DO_IMPLS),$(foreach s,$(STEPS),build^$(i))): $$(foreach s,$$(STEPS),$$(call $$(word 2,$$(subst ^, ,$$(@)))_STEP_TO_PROG,$$(s))) |
| 395 | |
| 396 | $(foreach i,$(DO_IMPLS),$(foreach s,$(STEPS),$(i)^$(s))): $$(call $$(word 1,$$(subst ^, ,$$(@)))_STEP_TO_PROG,$$(word 2,$$(subst ^, ,$$(@)))) |
| 397 | |
| 398 | $(foreach i,$(DO_IMPLS),$(foreach s,$(STEPS),build^$(i)^$(s))): $$(call $$(word 2,$$(subst ^, ,$$(@)))_STEP_TO_PROG,$$(word 3,$$(subst ^, ,$$(@)))) |
| 399 | |
| 400 | |
| 401 | |
| 402 | # |
| 403 | # Test rules |
| 404 | # |
| 405 | |
| 406 | $(ALL_TESTS): $$(call $$(word 2,$$(subst ^, ,$$(@)))_STEP_TO_PROG,$$(word 3,$$(subst ^, ,$$(@)))) |
| 407 | @$(foreach impl,$(word 2,$(subst ^, ,$(@))),\ |
| 408 | $(foreach step,$(word 3,$(subst ^, ,$(@))),\ |
| 409 | echo "(call STEP_TEST_FILES,$(impl),$(step)): $(call STEP_TEST_FILES,$(impl),$(step))" && \ |
| 410 | cd impls/$(call actual_impl,$(impl)) && \ |
| 411 | $(foreach test,$(patsubst impls/%,%,$(call STEP_TEST_FILES,$(impl),$(step))),\ |
| 412 | echo '----------------------------------------------' && \ |
| 413 | echo 'Testing $@; step file: $+, test file: $(test)' && \ |
| 414 | echo 'Running: $(call get_runtest_cmd,$(impl),$(step)) ../$(test) -- ../$(impl)/run' && \ |
| 415 | $(call get_runtest_cmd,$(impl),$(step)) ../$(test) -- ../$(impl)/run && \ |
| 416 | $(if $(filter tests/$(argv_STEP)$(EXTENSION),$(test)),\ |
| 417 | echo '----------------------------------------------' && \ |
| 418 | echo 'Testing ARGV of $@; step file: $+' && \ |
| 419 | echo 'Running: $(call get_argvtest_cmd,$(impl),$(step)) ../$(impl)/run ' && \ |
| 420 | $(call get_argvtest_cmd,$(impl),$(step)) ../$(impl)/run && ,\ |
| 421 | true && ))\ |
| 422 | true)) |
| 423 | |
| 424 | # Allow test, tests, test^STEP, test^IMPL, and test^IMPL^STEP |
| 425 | test: $(ALL_TESTS) |
| 426 | tests: $(ALL_TESTS) |
| 427 | |
| 428 | $(IMPL_TESTS): $$(filter $$@^%,$$(ALL_TESTS)) |
| 429 | |
| 430 | $(STEP_TESTS): $$(foreach step,$$(subst test^,,$$@),$$(filter %^$$(step),$$(ALL_TESTS))) |
| 431 | |
| 432 | |
| 433 | # |
| 434 | # Docker build rules |
| 435 | # |
| 436 | |
| 437 | docker-build: $(DOCKER_BUILD) |
| 438 | |
| 439 | $(DOCKER_BUILD): |
| 440 | @echo "----------------------------------------------"; \ |
| 441 | $(foreach impl,$(word 2,$(subst ^, ,$(@))),\ |
| 442 | echo "Running: docker build -t $(call impl_to_image,$(impl)) .:"; \ |
| 443 | cd impls/$(impl) && docker build -t $(call impl_to_image,$(impl)) .) |
| 444 | |
| 445 | # |
| 446 | # Docker shell rules |
| 447 | # |
| 448 | |
| 449 | $(DOCKER_SHELL): |
| 450 | @echo "----------------------------------------------"; \ |
| 451 | $(foreach impl,$(word 2,$(subst ^, ,$(@))),\ |
| 452 | echo "Running: $(call get_run_prefix,$(impl),stepA,,dockerize) bash"; \ |
| 453 | $(call get_run_prefix,$(impl),stepA,,dockerize) bash) |
| 454 | |
| 455 | |
| 456 | # |
| 457 | # Performance test rules |
| 458 | # |
| 459 | |
| 460 | perf: $(IMPL_PERF) |
| 461 | |
| 462 | $(IMPL_PERF): |
| 463 | @echo "----------------------------------------------"; \ |
| 464 | $(foreach impl,$(word 2,$(subst ^, ,$(@))),\ |
| 465 | cd impls/$(call actual_impl,$(impl)); \ |
| 466 | echo "Performance test for $(impl):"; \ |
| 467 | echo 'Running: $(call get_run_prefix,$(impl),stepA) ../$(impl)/run ../tests/perf1.mal'; \ |
| 468 | $(call get_run_prefix,$(impl),stepA) ../$(impl)/run ../tests/perf1.mal; \ |
| 469 | echo 'Running: $(call get_run_prefix,$(impl),stepA) ../$(impl)/run ../tests/perf2.mal'; \ |
| 470 | $(call get_run_prefix,$(impl),stepA) ../$(impl)/run ../tests/perf2.mal; \ |
| 471 | echo 'Running: $(call get_run_prefix,$(impl),stepA) ../$(impl)/run ../tests/perf3.mal'; \ |
| 472 | $(call get_run_prefix,$(impl),stepA) ../$(impl)/run ../tests/perf3.mal) |
| 473 | |
| 474 | |
| 475 | # |
| 476 | # REPL invocation rules |
| 477 | # |
| 478 | |
| 479 | $(ALL_REPL): $$(call $$(word 2,$$(subst ^, ,$$(@)))_STEP_TO_PROG,$$(word 3,$$(subst ^, ,$$(@)))) |
| 480 | @$(foreach impl,$(word 2,$(subst ^, ,$(@))),\ |
| 481 | $(foreach step,$(word 3,$(subst ^, ,$(@))),\ |
| 482 | cd impls/$(call actual_impl,$(impl)); \ |
| 483 | echo 'REPL implementation $(impl), step file: $+'; \ |
| 484 | echo 'Running: $(call get_run_prefix,$(impl),$(step)) ../$(impl)/run $(RUN_ARGS)'; \ |
| 485 | $(call get_run_prefix,$(impl),$(step)) ../$(impl)/run $(RUN_ARGS);)) |
| 486 | |
| 487 | # Allow repl^IMPL^STEP and repl^IMPL (which starts REPL of stepA) |
| 488 | $(IMPL_REPL): $$@^stepA |
| 489 | |
| 490 | # |
| 491 | # Stats test rules |
| 492 | # |
| 493 | |
| 494 | # For a concise summary: |
| 495 | # make stats | egrep -A1 "^Stats for|^all" | egrep -v "^all|^--" |
| 496 | stats: $(IMPL_STATS) |
| 497 | |
| 498 | $(IMPL_STATS): |
| 499 | @$(foreach impl,$(word 2,$(subst ^, ,$(@))),\ |
| 500 | echo "Stats for $(impl):"; \ |
| 501 | $(LOCCOUNT) -x "[sS]tep[0-9]_.*|[.]md$$|tests|examples|Makefile|package.json|tsconfig.json|Cargo.toml|project.clj|node_modules|getline.cs|terminal.cs|elm-stuff|objpascal/regexpr|rdyncall|swift/templates" impls/$(impl)) |
| 502 | |
| 503 | # |
| 504 | # Utility functions |
| 505 | # |
| 506 | print-%: |
| 507 | @echo "$($(*))" |
| 508 | |
| 509 | # |
| 510 | # Recursive rules (call make FOO in each subdirectory) |
| 511 | # |
| 512 | |
| 513 | define recur_template |
| 514 | .PHONY: $(1) |
| 515 | $(1): $(2) |
| 516 | $(2): |
| 517 | @echo "----------------------------------------------"; \ |
| 518 | $$(foreach impl,$$(word 2,$$(subst ^, ,$$(@))),\ |
| 519 | echo "Running: $$(call get_build_command,$$(impl)) --no-print-directory $(1)"; \ |
| 520 | $$(call get_build_command,$$(impl)) --no-print-directory $(1)) |
| 521 | endef |
| 522 | |
| 523 | recur_impls_ = $(filter-out $(foreach impl,$($(1)_EXCLUDES),$(1)^$(impl)),$(foreach impl,$(IMPLS),$(1)^$(impl))) |
| 524 | |
| 525 | # recursive clean |
| 526 | $(eval $(call recur_template,clean,$(call recur_impls_,clean))) |
| 527 | |
| 528 | # recursive dist |
| 529 | $(eval $(call recur_template,dist,$(call recur_impls_,dist))) |