code / tomo

Lines41.8K C24.0K Markdown9.8K YAML5.0K Tomo2.3K
8 others 800
make256 Python231 Shell220 INI47 Text21 SVG16 Lua6 diff3
(267 lines)
1 SHELL=bash -o pipefail
2 # Run ./configure.sh to choose installation locations:
3 ifeq ($(wildcard config.mk),)
4 all: config.mk
5 $(MAKE) all
6 install: config.mk
7 $(MAKE) install
8 install-files: config.mk
9 $(MAKE) install-files
10 install-lib: config.mk
11 $(MAKE) install-lib
12 test: config.mk
13 $(MAKE) test
14 config.mk: configure.sh
15 bash ./configure.sh
16 else
18 include config.mk
20 # Modified progress counter based on: https://stackoverflow.com/a/35320895
21 ifndef NO_PROGRESS
22 ifndef ECHO
23 T := $(shell $(MAKE) ECHO="COUNTTHIS" $(MAKECMDGOALS) --no-print-directory \
24 -n | grep -c "COUNTTHIS")
25 N := x
26 C = $(words $N)$(eval N := x $N)
27 ECHO = echo -e "[`expr $C '*' 100 / $T`%]"
28 endif
29 endif
30 ifndef ECHO
31 ECHO = echo
32 endif
33 # End of progress counter
35 CC=$(DEFAULT_C_COMPILER)
36 CCONFIG=-std=c2x -fPIC \
37 -fno-signed-zeros -fno-trapping-math \
38 -fvisibility=hidden -fdollars-in-identifiers \
39 -DGC_THREADS
40 LDFLAGS=
41 INCLUDE_DIRS=
42 CWARN=-Wall -Wextra -Wno-format -Wno-format-security -Wshadow \
43 -Wno-pedantic \
44 -Wno-pointer-arith \
45 -Wtype-limits -Wunused-result -Wnull-dereference \
46 -Walloca -Wcast-align \
47 -Wdangling-else -Wdate-time -Wdisabled-optimization -Wdouble-promotion \
48 -Wexpansion-to-defined -Wno-float-equal \
49 -Wframe-address -Winline -Winvalid-pch \
50 -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn \
51 -Wno-missing-field-initializers \
52 -Wnull-dereference -Woverlength-strings -Wpacked \
53 -Wredundant-decls -Wshadow \
54 -Wno-stack-protector -Wswitch-default \
55 -Wundef -Wunused -Wunused-but-set-variable \
56 -Wunused-const-variable -Wunused-local-typedefs -Wunused-macros -Wvariadic-macros \
57 -Wwrite-strings
59 ifeq ($(SUDO),)
60 ifeq ($(shell command -v doas 2>/dev/null),)
61 SUDO=sudo
62 else
63 SUDO=doas
64 endif
65 endif
67 OWNER=$(shell ls -ld '$(PREFIX)' | awk '{print $$3}')
69 ifeq ($(shell $(CC) -v 2>&1 | grep -c "gcc version"), 1)
70 CWARN += -Werror -Wsign-conversion -Walloc-zero -Wduplicated-branches -Wduplicated-cond -Wjump-misses-init \
71 -Wlogical-op -Wpacked-not-aligned -Wshadow=compatible-local -Wshadow=global -Wshadow=local \
72 -Wsuggest-attribute=const -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure \
73 -Wsync-nand -Wtrampolines -Wvector-operation-performance -Wcast-align=strict
74 CCONFIG += -fsanitize=signed-integer-overflow -fno-sanitize-recover -fno-signaling-nans -fno-finite-math-only
75 endif
77 OS := $(shell uname -s)
79 OSFLAGS != case $(OS) in *BSD|Darwin) echo '-D_BSD_SOURCE';; Linux) echo '-D_GNU_SOURCE';; *) echo '-D_DEFAULT_SOURCE';; esac
80 EXTRA=
81 G=-ggdb
82 O=-O3
83 # Note: older versions of Make have buggy behavior with hash marks inside strings, so this ugly code is necessary:
84 TOMO_VERSION=$(shell awk 'BEGIN{hashes=sprintf("%c%c",35,35)} $$1==hashes {print $$2; exit}' CHANGES.md)
85 GIT_VERSION=$(shell git log -1 --pretty=format:"%as_%h" 2>/dev/null || echo "unknown")
86 CFLAGS+=$(CCONFIG) $(INCLUDE_DIRS) $(EXTRA) $(CWARN) $(G) $(O) $(OSFLAGS) \
87 -DSUDO='"$(SUDO)"' -DDEFAULT_C_COMPILER='"$(DEFAULT_C_COMPILER)"' \
88 -DGIT_VERSION='"$(GIT_VERSION)"' -ffunction-sections -fdata-sections
89 CFLAGS_PLACEHOLDER="$$(printf '\033[2m<flags...>\033[m\n')"
90 LDLIBS=-lm -lcrypto
92 AR_FILE=libtomo@$(TOMO_VERSION).a
93 ifeq ($(OS),Darwin)
94 INCLUDE_DIRS += -I/opt/homebrew/include
95 LDFLAGS += -L/opt/homebrew/lib -Wl,-w
96 endif
97 EXE_FILE=tomo@$(TOMO_VERSION)
99 COMPILER_OBJS=$(patsubst %.c,%.o,$(wildcard src/*.c src/compile/*.c src/parse/*.c src/formatter/*.c))
100 STDLIB_OBJS=$(patsubst %.c,%.o,$(wildcard src/stdlib/*.c))
101 TESTS=$(patsubst test/%.tm,test/results/%.tm.testresult,$(wildcard test/[!_]*.tm))
102 API_YAML=$(wildcard api/*.yaml)
103 API_MD=$(patsubst %.yaml,%.md,$(API_YAML))
105 all: config.mk check-c-compiler build test/api.tm
106 @$(ECHO) "All done!"
108 dist: all
109 rm -f build/tomo@$(TOMO_VERSION)_$$(uname -sm | tr ' ' '-').tar.gz
110 tar czf build/tomo@$(TOMO_VERSION)_$$(uname -sm | tr ' ' '-').tar.gz -C build tomo@$(TOMO_VERSION)
112 BUILD_DIR=build/tomo@$(TOMO_VERSION)
113 headers := $(wildcard src/stdlib/*.h)
114 build_headers := $(patsubst src/stdlib/%.h, $(BUILD_DIR)/include/tomo@$(TOMO_VERSION)/%.h, $(headers))
116 # generate corresponding build paths with .gz
117 build_manpages := $(patsubst %,$(BUILD_DIR)/%.gz,$(wildcard man/man*/*))
119 # Ensure directories exist
120 dirs := $(BUILD_DIR)/include/tomo@$(TOMO_VERSION) \
121 $(BUILD_DIR)/lib \
122 $(BUILD_DIR)/lib/tomo@$(TOMO_VERSION) \
123 $(BUILD_DIR)/bin \
124 $(BUILD_DIR)/man/man1 \
125 $(BUILD_DIR)/man/man3 \
126 $(BUILD_DIR)/share/licenses/tomo@$(TOMO_VERSION)
128 $(dirs):
129 mkdir -p $@
131 # Rule for copying headers
132 $(BUILD_DIR)/include/tomo@$(TOMO_VERSION)%.h: src/stdlib/%.h | $(BUILD_DIR)/include/tomo@$(TOMO_VERSION)
133 cp $< $@
135 # Rule for gzipping man pages
136 $(BUILD_DIR)/man/%.gz: man/% | $(BUILD_DIR)/man/man1 $(BUILD_DIR)/man/man3
137 gzip -c $< > $@
139 $(BUILD_DIR)/bin/tomo: $(BUILD_DIR)/bin/tomo@$(TOMO_VERSION) | $(BUILD_DIR)/bin
140 ln -sf tomo@$(TOMO_VERSION) $@
142 $(BUILD_DIR)/bin/$(EXE_FILE): $(STDLIB_OBJS) $(COMPILER_OBJS) build/gc/lib/libgc.a build/gmp/lib/libgmp.a build/unistring/lib/libunistring.a | $(BUILD_DIR)/bin deps
143 @$(ECHO) $(CC) $(CFLAGS_PLACEHOLDER) $(LDFLAGS) $(LDLIBS) $^ -o $@
144 @$(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) $^ -o $@
146 $(BUILD_DIR)/lib/$(AR_FILE): $(STDLIB_OBJS) build/gc/lib/libgc.a build/unistring/lib/libunistring.a build/gmp/lib/libgmp.a | $(BUILD_DIR)/lib
147 $(CC) -no-pie -r -nostdlib $^ -o libtomo.o
148 ar rcs $@ libtomo.o
149 rm -f libtomo.o
151 $(BUILD_DIR)/lib/tomo@$(TOMO_VERSION)/packages.ini: packages.ini | $(BUILD_DIR)/lib/tomo@$(TOMO_VERSION)
152 @cp $^ $@
154 $(BUILD_DIR)/share/licenses/tomo@$(TOMO_VERSION)/LICENSE.md: LICENSE.md | $(BUILD_DIR)/share/licenses/tomo@$(TOMO_VERSION)
155 cp $< $@
157 build: $(BUILD_DIR)/bin/tomo $(BUILD_DIR)/bin/tomo@$(TOMO_VERSION) \
158 $(BUILD_DIR)/lib/$(AR_FILE) $(BUILD_DIR)/lib/tomo@$(TOMO_VERSION)/packages.ini \
159 $(BUILD_DIR)/share/licenses/tomo@$(TOMO_VERSION)/LICENSE.md $(build_headers) $(build_manpages)
161 version:
162 @echo $(TOMO_VERSION)
164 check-c-compiler:
165 @$(DEFAULT_C_COMPILER) -v 2>/dev/null >/dev/null \
166 || { printf '\033[91;1m%s\033[m\n' "You have set your DEFAULT_C_COMPILER to $(DEFAULT_C_COMPILER) in your config.mk, but I can't run it!"; exit 1; }
168 # check-libs: check-c-compiler | deps
169 # @echo 'int main() { return 0; }' | $(DEFAULT_C_COMPILER) $(LDFLAGS) -x c - $(LDLIBS) -o /dev/null 2>/dev/null >/dev/null \
170 # || { printf '\033[91;1m%s\033[m\n' "I expected to find the following libraries on your system, but I can't find them: $(LDLIBS)"; exit 1; }
172 tags:
173 ctags src/*.{c,h} src/stdlib/*.{c,h} src/compile/*.{c,h} src/parse/*.{c,h} src/formatter/*.{c,h}
175 config.mk: configure.sh
176 bash ./configure.sh
178 %.o: %.c src/ast.h src/environment.h src/types.h config.mk
179 @$(ECHO) $(CC) $(CFLAGS_PLACEHOLDER) -c $< -o $@
180 @$(CC) $(CFLAGS) -c $< -o $@
182 # Integer implementations depend on the shared header:
183 src/stdlib/int64.o src/stdlib/int32.o src/stdlib/int16.o src/stdlib/int8.o: src/stdlib/intX.c.h src/stdlib/intX.h
185 # Num implementations depend on the shared header:
186 src/stdlib/num32.o src/stdlib/num64.o: src/stdlib/numX.c.h
188 %: %.tm
189 ./local-tomo -e $<
191 test/results/%.tm.testresult: test/%.tm build
192 @mkdir -p test/results
193 @printf '\033[93;1;4m%s\033[m\n' $<
194 @if ! COLOR=1 LC_ALL=C ./local-tomo -O 1 $< 2>&1 | tee $@; then \
195 rm -f $@; \
196 false; \
199 test: $(TESTS)
200 @printf '\033[92;7m ALL TESTS PASSED! \033[m\n'
202 clean:
203 rm -rf build/tomo*/{bin,lib} $(COMPILER_OBJS) $(STDLIB_OBJS) test/*.tm.testresult test/.build lib/*/.build examples/.build examples/*/.build
205 %: %.md
206 pandoc --lua-filter=docs/.pandoc/bold-code.lua -s $< -t man -o $@
208 %.md: %.yaml scripts/api_gen.py
209 ./scripts/api_gen.py $< >$@
211 api/api.md: $(API_YAML)
212 ./scripts/api_gen.py $^ >$@
214 test/api.tm: $(API_YAML) | ./scripts/api_tests.py
215 ./scripts/api_tests.py $^ >$@
217 .PHONY: api-docs
218 api-docs: $(API_MD) api/api.md
220 .PHONY: manpages
221 manpages: $(API_YAML) man/man1/tomo.1
222 ./scripts/mandoc_gen.py $(API_YAML)
224 man/man1/tomo.1: docs/tomo.1.md
225 pandoc --lua-filter=docs/.pandoc/bold-code.lua -s $< -t man -o $@
227 examples:
228 ./local-tomo examples/learnxiny.tm
230 core-libs:
231 ./local-tomo -L packages/core.ini
233 deps: build/gc/lib/libgc.a build/unistring/lib/libgc.a build/gmp/lib/libgmp.a
235 build/gc/lib/libgc.a build/unistring/lib/libgc.a build/gmp/lib/libgmp.a:
236 $(MAKE) -C vendor
238 install-files: build check-c-compiler
239 @if ! echo "$$PATH" | tr ':' '\n' | grep -qx "$(PREFIX)/bin"; then \
240 echo $$PATH; \
241 printf "\033[91;1mError: '$(PREFIX)/bin' is not in your \$$PATH variable!\033[m\n" >&2; \
242 printf "\033[91;1mSpecify a different prefix with 'make PREFIX=... install'\033[m\n" >&2; \
243 printf "\033[91;1mor add the following line to your .profile:\033[m\n" >&2; \
244 printf "\n\033[1mexport PATH=\"$(PREFIX):\$$PATH\"\033[m\n\n" >&2; \
245 exit 1; \
247 if ! [ -w "$(PREFIX)" ]; then \
248 $(SUDO) -u $(OWNER) $(MAKE) install-files; \
249 exit 0; \
250 fi; \
251 cp -R $(BUILD_DIR)/* $(PREFIX)/
253 install: install-files
255 uninstall:
256 if ! [ -w "$(PREFIX)" ]; then \
257 $(SUDO) -u $(OWNER) $(MAKE) uninstall; \
258 exit 0; \
259 fi; \
260 rm -rvf "$(PREFIX)/bin/tomo" "$(PREFIX)/bin/tomo"* "$(PREFIX)/include/tomo"* \
261 "$(PREFIX)/lib/libtomo@"* "$(PREFIX)/lib/tomo@"* "$(PREFIX)/share/licenses/tomo@"* \
262 ~/.local/tomo/state/tomo@$(TOMO_VERSION); \
264 endif
266 .SUFFIXES:
267 .PHONY: all build clean install install-files uninstall test tags core-libs examples deps check-c-compiler version