Skip to content

Commit 19cea00

Browse files
author
Jens
committed
Improved makefile
Makefile now only builds if there as been any changes to the relevant files. `make spec` will build `bin/spec` (if not otherwise specified) and run it; if it were to be run again with no changes to any files made, `bin/spec` will be reused. `make help` also looks much much better.
1 parent 2403b3e commit 19cea00

File tree

3 files changed

+123
-20
lines changed

3 files changed

+123
-20
lines changed

.gitignore

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
*~
22

3-
# Files created by sentry
4-
*sentry*
3+
# Local files
4+
/local/
55

66
# Build artifacts and dependencies
77
/lib/
@@ -10,7 +10,9 @@
1010

1111
# Crystal generated docs
1212
/docs/
13+
1314
# The myst executable
1415
/myst
16+
1517
# DWARF file from compiling on macOS
16-
/myst.dwarf
18+
*.dwarf

Makefile

Lines changed: 117 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,122 @@
1-
.PHONY: help clean spec mystspec
1+
# Because env `SHELL` might be
2+
# some extremely weird shell
3+
SHELL = bash
24

3-
spec: ## Runs all specs
4-
crystal spec
5-
crystal run src/myst_cli.cr -- spec/myst/spec.mt
5+
# Parse makefiles named *.mk in the dir `local`
6+
# for local extra makefile targets if wanted.
7+
# It is smart to set MYSTBUILD to your myst dev-build there
8+
-include local/*.mk
69

7-
myst-spec: ## Runs just the in-language specs
8-
crystal run src/myst_cli.cr -- spec/myst/spec.mt
9-
10-
build: ## Builds myst into an executable
11-
shards build
10+
# https://www.gnu.org/software/make/manual/html_node/One-Shell.html
11+
.ONESHELL:
1212

13-
check: ## Runs all crystal specs
14-
crystal spec/
13+
# The docs says i should do this
14+
.SUFFIXES: .cr .mt
1515

16-
clean: ## Cleans (deletes) docs and executables
17-
rm -rf docs
18-
rm bin/*
16+
MYST_CLI = src/myst_cli.cr
1917

20-
# https://gist.github.com/prwhite/8168133 "Help target"
21-
help: ## Show this help.
22-
@fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##//'
18+
MYST_INTERPRETER_SPEC = spec/all_spec.cr
19+
MYST_IN_LANG_SPEC = spec/myst/spec.mt
20+
21+
SOURCE_FILES := $(shell find src -type f -name '*.cr')
22+
SPEC_FILES := $(shell find spec -type f -name '*.cr' -o -name '*.mt')
23+
STDLIB_FILES := $(shell find stdlib -type f -name '*.mt')
24+
ALL_FILES := $(SPEC_FILES) $(STDLIB_FILES) $(SOURCE_FILES)
25+
26+
INSTALL_LOCATION ?= /usr/local/bin/myst
27+
MYSTBUILD ?= myst
28+
29+
O ?= bin
30+
31+
verbose ?= true
32+
33+
# If another default is intentionally wished for,
34+
# set it in local/*.mk, like this:
35+
# .DEFAULT_GOAL = goal
36+
#
37+
.DEFAULT_GOAL ?= spec
38+
39+
verbose_log = $(if $(subst false,,$(verbose)), $(info $(1)))
40+
41+
.PHONY: spec
42+
spec: $(O)/myst $(O)/spec ## Runs all specs
43+
@$(call verbose_log,Running interpreter spec)
44+
$(O)/spec
45+
@$(call verbose_log,Running in-language spec)
46+
$(O)/myst $(MYST_IN_LANG_SPEC)
47+
48+
myst-spec: $(O)/myst ## Runs just the in-language specs
49+
$(O)/myst $(MYST_IN_LANG_SPEC)
50+
51+
.PHONY: install
52+
install: $(INSTALL_LOCATION) ## Install myst to INSTALL_LOCATION
53+
54+
.PHONY: build
55+
build: $(O)/myst ## Builds myst into an executable
56+
57+
.PHONY: myst-spec_with_build
58+
myst-spec_with_build: ## Runs the in-language specs with MYSTBUILD
59+
$(MYSTBUILD) $(MYST_IN_LANG_SPEC)
60+
61+
$(O)/myst: $(SOURCE_FILES)
62+
@$(call verbose_log,Building myst...)
63+
@mkdir -p $(O)
64+
crystal build -o $(O)/myst $(MYST_CLI)
65+
66+
$(O)/spec: $(ALL_FILES)
67+
@$(call verbose_log,Building specs...)
68+
@mkdir -p $(O)
69+
crystal build -o $(O)/spec $(MYST_INTERPRETER_SPEC)
70+
71+
$(INSTALL_LOCATION): $(SOURCE_FILES)
72+
@mkdir -p $(dir $(INSTALL_LOCATION))
73+
sudo crystal build --release -o $(INSTALL_LOCATION) $(MYST_CLI)
74+
75+
.PHONY: clean
76+
clean: ## Cleans (deletes) docs and executables
77+
ifdef O
78+
@[ -f $(O)/myst ] && rm $(O)/myst
79+
@[ -f $(O)/spec ] && rm $(O)/spec
80+
endif
81+
@rm -rf docs
82+
83+
# Thanks https://stackoverflow.com/questions/4219255/how-do-you-get-the-list-of-targets-in-a-makefile/26339924#26339924
84+
define TARGET_LIST =
85+
$(shell \
86+
$(MAKE) -pRrq -f $(MAKEFILE_LIST) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' |\
87+
sort |\
88+
egrep -v -e '^[^[a-zA-Z0-9]]' -e '^$@$$' |\
89+
xargs )
90+
endef
91+
92+
# Used in help target
93+
list:
94+
@echo $(TARGET_LIST)
95+
96+
HELP_INDENTATION ?= 2
97+
HELP_NAME-DESC_SEP ?= 2
98+
99+
LENGTH_OF_LONGEST_TARGET_NAME = $(shell ruby -e 'puts ARGV.sort_by(&:size)[-1].size' $$(make list))
100+
101+
parse_help = perl -n -e \
102+
'if(/^(\S*)?(?=:).*$(HELP_MARK)\s*(.*)/){ \
103+
print((" " x $(HELP_INDENTATION)) . "$$1" . (" " x ($(LENGTH_OF_LONGEST_TARGET_NAME) + $(HELP_NAME-DESC_SEP) - length($$1))) . "- $$2\n") \
104+
}' $(1) |\
105+
sort
106+
107+
# Help target that reads text after two '#'s in a target definition and prints it after the target name
108+
.PHONY: help
109+
help: ## Show this help
110+
@echo "The main targets are:"
111+
@$(call parse_help, $(firstword $(MAKEFILE_LIST))); echo
112+
# Iterate through the extra optional makefiles
113+
@for makefile in $(wordlist 2, $(words $(MAKEFILE_LIST)), $(MAKEFILE_LIST)); do
114+
echo "Targets defined in $$makefile:"
115+
$(call parse_help, $$makefile)
116+
echo
117+
done
118+
@echo "The default target is '$(.DEFAULT_GOAL)'"
119+
120+
define HELP_MARK
121+
##
122+
endef

spec/all_spec.cr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
require "./**"

0 commit comments

Comments
 (0)