forked from josefs/Gradualizer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Makefile
248 lines (202 loc) · 7.68 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
# This Makefile has the following dependencies:
# GNU Make, OTP, Curl, Perl and basic Posix applications.
# Rebar3 can also be used to build the project, but note that
# gradualizer_prelude.beam must be rebuilt if any file under
# priv/prelude/ is changed, added or deleted.
# Overview of make targets:
#
# all Compile app and escript (the default target)
# app Compile the OTP application (beams and app file)
# escript Generate the gradualizer CLI as a self-contained escript
# located at bin/gradualizer
# shell Start an erlang shell with gradualizer in the code path
# eunit Run eunit tests
# tests Run all tests (eunit and CLI tests)
# cover Run tests and generate coverage reports (XML and plain)
# dialyze Run dialyzer
# gradualize Run gradualizer on itself
# check Run all checks (tests, dialyze, gradualize)
# clean Delete all generated files
#
# Capitalized variables can be overridden on the command line.
# Example:
#
# make tests EUNIT_OPTS=verbose
# Run tests with the eunit verbose option
#
# The directory structure is following what is described on
# http://erlang.org/doc/design_principles/applications.html
.PHONY: all
all: app escript
ERL_OPTS = -enable-feature maybe_expr
# Compilation
erls = $(wildcard src/*.erl)
beams = $(erls:src/%.erl=ebin/%.beam)
ERLC_OPTS = -I include -I src -pa ebin +debug_info
TEST_ERLC_OPTS = +debug_info
app: $(beams) ebin/gradualizer.app
ebin:
mkdir -p ebin
ebin/%.beam: src/%.erl | ebin
erlc $(ERLC_OPTS) -o ebin $<
# Compile-time dependencies between modules and other files
ebin/gradualizer_prelude.beam: priv/prelude \
ebin/gradualizer_prelude_parse_trans.beam
ebin/typechecker.beam: src/typelib.hrl
ebin/gradualizer_fmt.beam: src/typelib.hrl
# .app file
ebin/gradualizer.app: src/gradualizer.app.src | ebin
sed -e "s/{vsn, *\"git\"}/{vsn, \"`git describe --tags --always`\"}/" $< > $@
.PHONY: shell
shell: app
erl -pz ebin
.PHONY: escript
escript: bin/gradualizer
# legacy CLI location
gradualizer: bin/gradualizer
cp $< $@
define erl_build_escript
FileList = [{filename:join("gradualizer", Name), Bin} \
|| Name <- filelib:wildcard(filename:join("ebin", "*.{beam,app}")), \
{ok, Bin} <- [file:read_file(Name)]], \
{ok, {_Name, ZipBin}} = zip:zip("dummy-name", FileList, [memory]), \
EscriptBin = <<"#!/usr/bin/env escript\n" \
"%%\n" \
"%%! -escript main gradualizer_cli\n", \
ZipBin/binary>>, \
ok = file:write_file("bin/gradualizer", EscriptBin), halt().
endef
bin/gradualizer: $(beams) ebin/gradualizer.app
mkdir -p bin
erl -noinput -eval '$(erl_build_escript)'
chmod +x $@
.PHONY: gradualize
gradualize: escript
@bin/gradualizer --infer --solve_constraints --specs_override_dir priv/extra_specs/ \
-pa ebin --color ebin | grep -v -f gradualize-ignore.lst
.PHONY: nocrashongradualize
nocrashongradualize: escript
bin/gradualizer -pa ebin -- ebin; \
EXIT=$$?; \
if [ $$EXIT -eq 0 ] || [ $$EXIT -eq 1 ]; then \
exit 0; \
else \
exit $$EXIT; \
fi
.PHONY: clean
clean:
rm -rf _build # legacy rebar3 build directory
rm -f gradualizer # legacy CLI location
rm -rf bin/gradualizer ebin cover test/*.beam
.PHONY: tests eunit compile-tests cli-tests
tests: check_name_clashes build_test_data eunit cli-tests
test_erls=$(wildcard test/*.erl)
test_beams=$(test_erls:test/%.erl=test/%.beam)
compile-tests: app $(test_beams) test/any.beam test/records.beam
test/%.beam: test/%.erl
erlc $(ERLC_OPTS) -o test $<
# Extra beams used by some test cases
test/any.beam: test/should_pass/any.erl
erlc $(ERLC_OPTS) -o test $<
test/records.beam: test/should_pass/records.erl
erlc $(ERLC_OPTS) -o test $<
test/arg.beam: test/should_fail/arg.erl
erlc $(ERLC_OPTS) -o test $<
.PHONY: build_test_data
test_data_erls = $(wildcard test/known_problems/**/*.erl test/should_fail/*.erl test/should_pass/*.erl)
build_test_data:
mkdir -p "test_data"
erlc $(TEST_ERLC_OPTS) -o test_data $(test_data_erls)
EUNIT_OPTS =
define erl_run_eunit
case eunit:test("test", [$(EUNIT_OPTS)]) of \
ok -> ok; \
error -> halt(2) \
end
endef
eunit: compile-tests
erl $(ERL_OPTS) -noinput -pa ebin -pa test -eval \
'$(erl_run_eunit), halt().'
cli-tests: bin/gradualizer test/arg.beam
# CLI test cases
# 1. When checking a dir with erl files, erl file names are printed
bin/gradualizer test/dir \
2>&1|perl -0777 -ne 'm%^test/dir/test_in_dir.erl:% or die "CLI 1 ($$_)"'
# 2. When checking a beam file; beam file name is printed
bin/gradualizer test/arg.beam \
2>&1|perl -0777 -ne 'm%^test/arg.beam:% or die "CLI 1 ($$_)"'
# 3. Brief formatting
bin/gradualizer --fmt_location brief test/dir \
2>&1|perl -0777 -ne '/^test\/dir\/test_in_dir.erl:6:12: The variable/ or die "CLI 6 ($$_)"'
# 4. Verbose formatting
bin/gradualizer --fmt_location verbose --no_fancy test/dir \
2>&1|perl -ne '/^test\/dir\/test_in_dir.erl: The variable N on line 6 at column 12/ or die "CLI 7 ($$_)"'
# 5. Possible to exclude prelude (-0777 from https://stackoverflow.com/a/30594643/497116)
bin/gradualizer --no_prelude test/should_pass/cyclic_otp_specs.erl \
2>&1|perl -0777 -ne '/^test\/should_pass\/cyclic_otp_specs.erl: The type spec/g or die "CLI 9 ($$_)"'
# 6. Excluding prelude and then including it is a no-op
bin/gradualizer --no_prelude --specs_override_dir priv/prelude \
test/should_pass/cyclic_otp_specs.erl || (echo "CLI 10"; exit 1)
# Cover compile, run eunit, export and generate reports
define erl_cover_run
case cover:compile_beam_directory("ebin") of \
{error, _} -> halt(2); \
_List -> ok \
end, \
$(erl_run_eunit), \
cover:export("cover/eunit.coverdata"), \
cover:analyse_to_file([{outdir, "cover"}]), \
cover:analyse_to_file([{outdir, "cover"}, html])
endef
.PHONY: cover
cover: compile-tests
mkdir -p cover
erl $(ERL_OPTS) -noinput -pa ebin -pa test -eval '$(erl_cover_run), halt().'
cover/coverage.xml: cover test/covertool.beam
erl -noinput -pa test -eval \
'covertool:main(["-cover", "cover/eunit.coverdata", % \
"-output", "cover/coverage.xml", % \
"-appname", "gradualizer"]), % \
halt().'
test/covertool.beam: test/covertool.erl test/covertool.hrl
erlc $(ERLC_OPTS) -I test -o test $<
# Download the deps for generating XML cover report
test/covertool.erl:
curl -Ls https://github.com/covertool/covertool/raw/2.0.2/src/covertool.erl \
-o $@
test/covertool.hrl:
curl -Ls https://github.com/covertool/covertool/raw/2.0.2/include/covertool.hrl \
-o $@
DIALYZER_PLT = .dialyzer_plt
export DIALYZER_PLT
PLT_APPS = erts kernel stdlib syntax_tools
DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions
# -Wunmatched_returns -Wunknown
# -Wunderspecs -Woverspec -Wspecdiffs
.PHONY: dialyze
dialyze: app $(DIALYZER_PLT)
dialyzer $(DIALYZER_OPTS) ebin
.PHONY: dialyze-tests
dialyze-tests: app $(DIALYZER_PLT)
dialyzer $(DIALYZER_OPTS) $(test_data_erls)
.PHONY: check_name_clashes
check_name_clashes:
test/check_name_clashes.sh
# DIALYZER_PLT is a variable understood directly by Dialyzer.
# Exit status 2 = warnings were emitted
$(DIALYZER_PLT):
dialyzer --build_plt --apps $(PLT_APPS) || test $$? -eq 2
.PHONY: check
check: tests dialyze gradualize
.PHONY: travischeck
travischeck: cover/coverage.xml dialyze nocrashongradualize
.PHONY: install-asdf
install-asdf: bin/gradualizer
@if asdf current erlang 2>/dev/null >/dev/null; then \
ASDF_ERLANG_BIN=$$(dirname $$(asdf which erl)); \
cp bin/gradualizer $$ASDF_ERLANG_BIN/; \
asdf reshim; \
echo "Installed gradualizer to $$ASDF_ERLANG_BIN"; \
else \
echo "Couldn't find Erlang managed by asdf"; \
fi