-
Notifications
You must be signed in to change notification settings - Fork 108
/
makefile
463 lines (366 loc) · 15.8 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
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
# Main targets of interest for development
#
# make tests Run the full test suite in a clean build
# make run-tests/<file> Run one test file from tests/
# make build Build Dex (fastest complete compile time)
# make watch Build Dex continuously as source is edited
# make check-watch Just typecheck Dex continuously (fastest feedback)
# make build-opt Slower, but gives faster Dex compiles
# make build-dbg Slower, but better Haskell errors
# make build-prof Optimized for profiling the speed of the Dex compiler
#
# We suggest adding the following or equivalent aliases:
#
# alias dex="stack exec dex -- --lib-path lib"
# alias dexopt="stack exec --work-dir .stack-work-opt dex -- --lib-path lib"
# alias dexdbg="stack exec --work-dir .stack-work-dbg --trace dex -- --lib-path lib"
# alias dexprof="stack exec --work-dir .stack-work-prof --trace dex -- --lib-path lib"
# In more detail:
#
# - The default build is for quickly getting feedback on development
# changes: get Haskell type errors and run small Dex test scripts as
# fast as possible.
#
# - The opt build is for developing a Dex program or example (possibly
# against a patched Dex): pay a slow optimizing compile once but have
# the fastest possible Dex development loop.
#
# - The dbg build is for hunting (crash) bugs in Dex: pay slow GHC
# compilation and slow Dex compilation, but get (relatively) detailed
# stack traces from `error` and `C-c`, and extra internal debug checks.
#
# - The prof build is for profiling the Dex compiler: pay very slow GHC
# compilation, but get relatively high signal-to-noise profiling
# information on the Dex compiler's performance.
#
# The prof and dbg builds are different in two ways: prof turns on
# GHC's -O, but turns off Dex's self-checks and GHC's automatic cost
# center insertion. This way (i) you're profiling optimized rather
# than unoptimized Dex, and (ii) the profile data is restricted to our
# {-# SCC #-} annotations, and thus not as overwhelming.
# - As a reminder, runtime profiling is turned on by passing +RTS -p
# -RTS to `dexprof`; you can read the resulting .prof file directly,
# or postprocess it into a more legible form by for example
# running `profiteur` on it and browsing the HTML page so
# created.
#
# We keep the builds in separate .stack-work directories so they don't
# step on each other's GHC-level compilation caches.
#
# The tests are run in the default `build` configuration, namely no
# optimization and no debug aids.
# Set shell to bash to resolve symbolic links when looking up
# executables, to support user-account installation of stack.
SHELL=/usr/bin/env bash
STACK=$(shell command -v stack 2>/dev/null)
ifeq (, $(STACK))
STACK=cabal
DBG := --enable-library-profiling --enable-executable-profiling
dex := cabal exec dex --
else
STACK=stack
PLATFORM := $(shell uname -s)
ifeq ($(PLATFORM),Darwin)
STACK=stack --stack-yaml=stack-macos.yaml
endif
DUMP_FLAGS = --ghc-options="-ddump-simpl" \
--ghc-options="-ddump-stg" \
--ghc-options="-dsuppress-all" \
--ghc-options="-dno-suppress-type-signatures" \
--ghc-options="-ddump-to-file"
# Using separate stack-work directories to avoid recompiling when
# changing between debug and non-debug builds, per
# https://github.com/commercialhaskell/stack/issues/1132#issuecomment-386666166
OPT := --work-dir .stack-work-opt $(DUMP_FLAGS)
DBG := --work-dir .stack-work-dbg --trace
PROF := --work-dir .stack-work-prof --trace --ghc-options="-fno-prof-auto" $(DUMP_FLAGS)
dex := $(STACK) exec dex --
endif
# --- building Dex ---
CFLAGS := -fPIC
STACK_FLAGS := --ghc-options="-j +RTS -A256m -n2m -RTS"
# CUDA
ifneq (,$(wildcard /usr/local/cuda/include/cuda.h))
STACK_FLAGS := $(STACK_FLAGS) --flag dex:cuda
CFLAGS := $(CFLAGS) -I/usr/local/cuda/include -DDEX_CUDA
endif
# libpng
ifneq (,$(wildcard /usr/local/include/png.h))
CFLAGS := $(CFLAGS) -I/usr/local/include
endif
ifneq (,$(PREFIX))
STACK_BIN_PATH := --local-bin-path $(PREFIX)
endif
# Make sure we always use a debug build in CI --- it enables extra checks!
ifneq (,$(DEX_CI))
STACK_FLAGS := $(STACK_FLAGS) --flag dex:debug
endif
possible-clang-locations := clang++-9 clang++-10 clang++-11 clang++-12 clang++
CLANG := clang++
ifeq (1,$(DEX_LLVM_HEAD))
ifeq ($(PLATFORM),Darwin)
$(error LLVM head builds not supported on macOS!)
endif
STACK_FLAGS := $(STACK_FLAGS) --flag dex:llvm-head
STACK := $(STACK) --stack-yaml=stack-llvm-head.yaml
else
CLANG := $(shell for clangversion in $(possible-clang-locations) ; do \
if [[ $$(command -v "$$clangversion" 2>/dev/null) ]]; \
then echo "$$clangversion" ; break ; fi ; done)
ifeq (,$(CLANG))
$(error "Please install clang++-12")
endif
clang-version-compatible := $(shell $(CLANG) -dumpversion | awk '{ print(gsub(/^((9\.)|(10\.)|(11\.)|(12\.)).*$$/, "")) }')
ifneq (1,$(clang-version-compatible))
$(error "Please install clang++-12")
endif
endif
CXXFLAGS := $(CFLAGS) -std=c++11 -fno-exceptions -fno-rtti -pthread
CFLAGS := $(CFLAGS) -std=c11
.PHONY: all
all: build
# type-check only
tc: dexrt-llvm
$(STACK) build $(STACK_FLAGS) --ghc-options -fno-code
static/index.js: static/index.ts
tsc --strict --lib es2015,dom static/index.ts
# Build without clearing the cache. Use at your own risk.
just-build: dexrt-llvm static/index.js
$(STACK) build $(STACK_FLAGS)
build: dexrt-llvm static/index.js
$(STACK) build $(STACK_FLAGS) --fast
$(dex) clean # clear cache
$(dex) script /dev/null # precompile the prelude
watch: dexrt-llvm
$(STACK) build $(STACK_FLAGS) --fast --file-watch
check-watch: dexrt-llvm
$(STACK) build $(STACK_FLAGS) --fast --file-watch --ghc-options="-fno-code"
install: dexrt-llvm
$(STACK) install $(STACK_BIN_PATH) --flag dex:optimized $(STACK_FLAGS) $(OPT)
build-opt: dexrt-llvm
$(STACK) build $(STACK_FLAGS) $(OPT) --flag dex:optimized
build-dbg: dexrt-llvm
$(STACK) build $(STACK_FLAGS) $(DBG) --flag dex:debug
build-prof: dexrt-llvm
$(STACK) build $(STACK_FLAGS) $(PROF) --flag dex:optimized
# For some reason stack fails to detect modifications to foreign library files
build-ffis: dexrt-llvm
$(STACK) build $(STACK_FLAGS) --work-dir .stack-work-ffis --force-dirty --flag dex:foreign --flag dex:optimized
$(eval STACK_INSTALL_DIR=$(shell $(STACK) path --work-dir .stack-work-ffis --local-install-root))
cp $(STACK_INSTALL_DIR)/lib/libDex.so python/dex/
cp $(STACK_INSTALL_DIR)/lib/libDex.so julia/deps/
# This target is for CI, because it wants to be able to both run the
# `dex` executable and load the `dex` Python package from the same
# directory, without a needless recompile.
build-ffis-and-exe: dexrt-llvm
$(STACK) build $(STACK_FLAGS) --work-dir .stack-work-ffis \
--flag dex:foreign --flag dex:optimized --force-dirty
$(STACK) install $(STACK_FLAGS) --work-dir .stack-work-ffis \
--flag dex:foreign --flag dex:optimized --local-bin-path .
$(eval STACK_INSTALL_DIR=$(shell $(STACK) path --work-dir .stack-work-ffis --local-install-root))
cp $(STACK_INSTALL_DIR)/lib/libDex.so python/dex/
cp $(STACK_INSTALL_DIR)/lib/libDex.so julia/deps/
build-ci: dexrt-llvm
$(STACK) build $(STACK_FLAGS) --force-dirty --ghc-options "-Werror -fforce-recomp"
$(dex) clean # clear cache
$(dex) script /dev/null # precompile the prelude
build-nolive: dexrt-llvm
$(STACK) build $(STACK_FLAGS) --flag dex:-live
dexrt-llvm: src/lib/dexrt.bc
%.bc: %.cpp
$(CLANG) $(CXXFLAGS) -DDEX_LIVE -c -emit-llvm $^ -o $@
# --- running tests ---
example-names := \
mandelbrot pi sierpinski rejection-sampler \
regression brownian_motion particle-swarm-optimizer \
ode-integrator mcmc ctc raytrace particle-filter \
fluidsim \
sgd nn \
quaternions manifold-gradients schrodinger tutorial \
latex dither mcts md bfgs
# TODO: re-enable
# fft vega-plotting
# examples depending on linalg: linear-maps, psd, kernelregression
# Only test levenshtein-distance on Linux, because MacOS ships with a
# different (apparently _very_ different) word list.
ifeq ($(shell uname -s),Linux)
example-names += levenshtein-distance
endif
test-names = uexpr-tests print-tests adt-tests type-tests struct-tests cast-tests eval-tests show-tests \
read-tests shadow-tests monad-tests io-tests exception-tests sort-tests \
parser-tests standalone-function-tests instance-methods-tests \
ad-tests serialize-tests parser-combinator-tests \
typeclass-tests complex-tests trig-tests \
linalg-tests set-tests fft-tests stats-tests stack-tests
doc-names = conditionals functions
lib-names = complex fft netpbm plot sort diagram linalg parser png set stats
benchmark-names = \
fused_sum gaussian jvp_matmul matmul_big matmul_small matvec_big matvec_small \
poly vjp_matmul
quine-test-targets = \
$(test-names:%=run-tests/%) \
$(example-names:%=run-examples/%) \
$(doc-names:%=run-doc/%) \
$(lib-names:%=run-lib/%) \
$(benchmark-names:%=run-bench-tests/%)
update-test-targets = $(test-names:%=update-tests/%)
update-doc-targets = $(doc-names:%=update-doc/%)
update-lib-targets = $(lib-names:%=update-lib/%)
update-example-targets = $(example-names:%=update-examples/%)
t10k-images-idx3-ubyte-sha256 = 346e55b948d973a97e58d2351dde16a484bd415d4595297633bb08f03db6a073
t10k-labels-idx1-ubyte-sha256 = 67da17c76eaffca5446c3361aaab5c3cd6d1c2608764d35dfb1850b086bf8dd5
tutorial-data = t10k-images-idx3-ubyte t10k-labels-idx1-ubyte
tutorial-data := $(tutorial-data:%=examples/%)
$(tutorial-data):
wget -qO $@.gz http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/$(@F).gz
@echo $($(@F)-sha256) $@.gz > $@.sha256
sha256sum -c $@.sha256
$(RM) $@.sha256
gunzip $@.gz
.PHONY: tutorial-data
tutorial-data: $(tutorial-data)
run-examples/tutorial: tutorial-data
update-examples/tutorial: tutorial-data
camera-sha256 = c5c69e1bf02f219b6e1c12c13405671425aa1c4dc130c1c380e7416a064341bc
dither-data = camera
dither-data := $(dither-data:%=examples/%)
$(dither-data):
wget -qO $@.ppm https://gist.github.com/niklasschmitz/03be29c2850ac3bbdf6ce86229b71d8f/raw/300962b117fe8595913fb1f35db546b53974576c/$(@F).ppm
@echo $($(@F)-sha256) $@.ppm > $@.sha256
sha256sum -c $@.sha256
$(RM) $@.sha256
.PHONY: dither-data
dither-data: $(dither-data)
run-examples/dither: dither-data
update-examples/dither: dither-data
tests: opt-tests unit-tests lower-tests quine-tests repl-test module-tests doc-format-test file-check-tests
# Keep the unit tests in their own working directory too, due to
# https://github.com/commercialhaskell/stack/issues/4977
unit-tests:
$(STACK) test --work-dir .stack-work-test $(STACK_FLAGS)
watch-unit-tests:
$(STACK) test --work-dir .stack-work-test $(STACK_FLAGS) --file-watch
unit-tests-dbg:
$(STACK) test --work-dir .stack-work-test-dbg --trace $(STACK_FLAGS)
opt-tests: just-build
misc/file-check tests/opt-tests.dx $(dex) -O script
misc/file-check tests/inline-tests.dx $(dex) -O script
doc-format-test: $(doc-files) $(example-files) $(lib-files)
python3 misc/build-web-index "$(doc-files)" "$(example-files)" "$(lib-files)" > /dev/null
quine-tests: $(quine-test-targets)
file-check-tests: just-build
misc/file-check tests/instance-interface-syntax-tests.dx $(dex) -O script
run-%: export DEX_ALLOW_CONTRACTIONS=0
run-%: export DEX_TEST_MODE=t
run-tests/%: tests/%.dx just-build
misc/check-quine $< $(dex) -O script
run-doc/%: doc/%.dx just-build
misc/check-quine $< $(dex) script
run-lib/%: lib/%.dx just-build
misc/check-quine $< $(dex) script
run-examples/%: examples/%.dx just-build
misc/check-quine $< $(dex) -O script
# This runs the benchmark in test mode, which means we're checking
# that it's not broken, but not actually trying to measure runtimes
run-bench-tests/%: benchmarks/%.dx just-build
misc/check-quine $< $(dex) -O script
lower-tests: export DEX_LOWER=1
lower-tests: export DEX_ALLOW_CONTRACTIONS=0
lower-tests: export DEX_TEST_MODE=t
lower-tests: just-build
misc/check-quine tests/lower.dx $(dex) script
update-lower-tests: just-build
$(dex) script tests/lower.dx > tests/lower.dx.tmp
mv tests/lower.dx.tmp tests/lower.dx
lower-vectorize-tests: export DEX_LOWER=1
lower-vectorize-tests: export DEX_VECTORIZE=1
lower-vectorize-tests: export DEX_ALLOW_CONTRACTIONS=0
lower-vectorize-tests: export DEX_TEST_MODE=t
lower-vectorize-tests: just-build
misc/check-quine tests/lower-vectorize.dx $(dex) script
update-lower-vectorize-tests: just-build
DEX_LOWER=1 DEX_VECTORIZE=1 $(dex) script tests/lower-vectorize.dx > tests/lower-vectorize.dx.tmp
mv tests/lower-vectorize.dx.tmp tests/lower-vectorize.dx
update-%: export DEX_ALLOW_CONTRACTIONS=0
update-%: export DEX_TEST_MODE=t
update-all: $(update-test-targets) $(update-doc-targets) $(update-lib-targets) $(update-example-targets)
update-tests/%: tests/%.dx just-build
$(dex) script $< > $<.tmp
mv $<.tmp $<
update-doc/%: doc/%.dx just-build
$(dex) script $< > $<.tmp
mv $<.tmp $<
update-lib/%: lib/%.dx just-build
$(dex) script $< > $<.tmp
mv $<.tmp $<
update-examples/%: examples/%.dx just-build
$(dex) script $< > $<.tmp
mv $<.tmp $<
update-bench-tests/%: benchmarks/%.dx just-build
$(dex) script $< > $<.tmp
mv $<.tmp $<
run-gpu-tests: export DEX_ALLOW_CONTRACTIONS=0
run-gpu-tests: tests/gpu-tests.dx just-build
misc/check-quine $< $(dex) --backend llvm-cuda script
update-gpu-tests: export DEX_ALLOW_CONTRACTIONS=0
update-gpu-tests: tests/gpu-tests.dx just-build
$(dex) --backend llvm-cuda script $< > $<.tmp
mv $<.tmp $<
repl-test: just-build
misc/check-no-diff \
tests/repl-multiline-test-expected-output \
<($(dex) repl < tests/repl-multiline-test.dx)
misc/check-no-diff \
tests/repl-regression-528-test-expected-output \
<($(dex) repl < tests/repl-regression-528-test.dx)
module-tests: just-build
misc/check-quine tests/module-tests.dx \
$(dex) --prelude lib/prelude.dx --lib-path tests script
# --- running and querying benchmarks ---
bench-summary:
sqlite3 results.db < benchmarks/queries/result-summary.sql
# bench-set-standard:
# python3 dexbench.py adhoc --name standard
# bench-compare:
# python3 dexbench.py adhoc --name proposed
# cat <( echo ".parameter set :old_version standard" \
# && echo ".parameter set :new_version proposed" \
# && cat queries/compare-versions.sql ) \
# | sqlite3 bench_results.db
# --- building docs ---
slow-pages = pages/dex-lang/examples/mnist-nearest-neighbors.html
static-names = dynamic.html index.js style.css
doc-files = $(doc-names:%=doc/%.dx)
pages-doc-files = $(doc-names:%=pages/dex-lang/%.html)
example-files = $(example-names:%=examples/%.dx)
pages-example-files = $(example-names:%=pages/dex-lang/examples/%.html)
lib-files = $(filter-out lib/prelude.dx,$(wildcard lib/*.dx))
pages-lib-files = $(patsubst %.dx,pages/dex-lang/%.html,$(lib-files))
static-files = $(static-names:%=pages/dex-lang/static/%)
serve-docs:
cd pages && python3 -m http.server
docs: $(static-files) pages-prelude $(pages-doc-files) $(pages-example-files) $(pages-lib-files) $(slow-pages) pages/dex-lang/index.md
pages/dex-lang/static/%: static/%
mkdir -p pages/dex-lang/static
cp $^ $@
pages-prelude: lib/prelude.dx
mkdir -p pages/dex-lang/lib
$(dex) --prelude /dev/null generate-html lib/prelude.dx dex-lang/lib/prelude
pages/dex-lang/examples/tutorial.html: tutorial-data
pages/dex-lang/examples/dither.html: dither-data
pages/dex-lang/examples/%.html: examples/%.dx
mkdir -p pages/dex-lang/examples
$(dex) generate-html $< dex-lang/examples/$*
pages/dex-lang/lib/%.html: lib/%.dx
mkdir -p pages/dex-lang/lib
$(dex) generate-html $^ dex-lang/lib/$*
pages/dex-lang/index.md: $(doc-files) $(example-files) $(lib-files)
python3 misc/build-web-index "$(doc-files)" "$(example-files)" "$(lib-files)" > $@
${pages-doc-files}:pages/dex-lang/%.html: doc/%.dx
mkdir -p pages/dex-lang
$(dex) generate-html $^ dex-lang/$*
clean:
$(STACK) clean
$(RM) src/lib/dexrt.bc
$(RM) $(tutorial-data)
$(RM) $(dither-data)