v / GNUmakefile
411 lines · 373 sloc · 12.12 KB · 9aa967953d75e284dfb9bbe87668ac39a9d827fe
Raw
1CC ?= cc
2CPPFLAGS ?=
3CFLAGS ?=
4LDFLAGS ?=
5TMPDIR ?= /tmp
6VROOT ?= .
7VC ?= ./vc
8VEXE ?= ./v
9VCREPO ?= https://github.com/vlang/vc
10TCCREPO ?= https://github.com/vlang/tccbin
11LEGACYREPO ?= https://github.com/macports/macports-legacy-support
12GIT ?= git
13
14VCFILE := v.c
15TMPTCC := $(VROOT)/thirdparty/tcc
16LEGACYLIBS := $(VROOT)/thirdparty/legacy
17TMPLEGACY := $(LEGACYLIBS)/source
18TCCOS := unknown
19TCCARCH := unknown
20HAS_GIT := $(shell command -v $(GIT) >/dev/null 2>&1 && echo 1 || echo 0)
21GITCLEANPULL := $(GIT) clean -xf && $(GIT) pull --rebase --quiet
22GITFASTCLONE := $(GIT) clone --filter=blob:none --quiet
23
24#### Platform detections and overrides:
25_SYS := $(shell uname 2>/dev/null || echo Unknown)
26_SYS := $(patsubst MSYS%,MSYS,$(_SYS))
27_SYS := $(patsubst MINGW%,MinGW,$(_SYS))
28
29ifneq ($(filter $(_SYS),MSYS MinGW),)
30WIN32 := 1
31EXE_EXT := .exe
32# GNU make defaults CC to `cc`, but mingw32-make installations often only
33# provide `gcc`. Switch only the implicit default and preserve explicit CC=...
34ifneq ($(filter $(origin CC),default file),)
35ifeq ($(CC),cc)
36CC := gcc
37endif
38endif
39endif
40
41ifeq ($(_SYS),Linux)
42LINUX := 1
43TCCOS := linux
44ifneq ($(shell ldd --version 2>&1 | grep -i musl),)
45TCCOS := linuxmusl
46endif
47endif
48
49ifeq ($(_SYS),Darwin)
50MAC := 1
51TCCOS := macos
52ifeq ($(shell expr $(shell uname -r | cut -d. -f1) \<= 16), 1)
53LEGACY := 1
54CPPFLAGS += -I$(LEGACYLIBS)/include/LegacySupport
55LDFLAGS += -L$(LEGACYLIBS)/lib
56LDFLAGS += -lMacportsLegacySupport
57VFLAGS += -cc $(CC)
58VFLAGS += -cflags "$(strip $(CPPFLAGS) $(CFLAGS))"
59VFLAGS += -ldflags -L$(LEGACYLIBS)/lib
60VFLAGS += -cflags $(LEGACYLIBS)/lib/libMacportsLegacySupport.a
61endif
62endif
63
64ifeq ($(_SYS),FreeBSD)
65TCCOS := freebsd
66LDFLAGS += -lexecinfo
67endif
68
69ifeq ($(_SYS),NetBSD)
70NETBSD := 1
71TCCOS := netbsd
72LDFLAGS += -lexecinfo
73endif
74
75ifeq ($(_SYS),OpenBSD)
76TCCOS := openbsd
77LDFLAGS += -lexecinfo
78endif
79
80ifdef ANDROID_ROOT
81ANDROID := 1
82undefine LINUX
83TCCOS := android
84ifneq ($(wildcard $(PREFIX)/lib/libexecinfo.*),)
85LDFLAGS += -lexecinfo
86endif
87endif
88#####
89
90ifdef WIN32
91TCCOS := windows
92endif
93
94TCCARCH := $(shell uname -m 2>/dev/null || echo unknown)
95
96ifeq ($(TCCARCH),x86_64)
97 TCCARCH := amd64
98else
99ifneq ($(filter x86%,$(TCCARCH)),)
100 TCCARCH := i386
101else
102ifeq ($(TCCARCH),arm64)
103 TCCARCH := arm64
104else
105ifneq ($(filter arm%,$(TCCARCH)),)
106 TCCARCH := arm
107# otherwise, just use the arch name
108endif
109endif
110endif
111endif
112
113TCCBUILDSCRIPT = $(VROOT)/thirdparty/build_scripts/thirdparty-$(TCCOS)-$(TCCARCH)_tcc.sh
114
115.PHONY: all clean rebuild check fresh_vc fresh_tcc fresh_legacy latest_tcc_source check_for_working_tcc etags ctags
116
117ifdef prod
118VFLAGS+=-prod
119endif
120
121# Keep bootstrap C compiler/linker flags aligned with the initial `v1` build.
122BOOTSTRAP_CC_CFLAGS := $(strip $(CFLAGS))
123BOOTSTRAP_CFLAGS := $(strip $(CPPFLAGS) $(CFLAGS))
124BOOTSTRAP_VC_CC_CFLAGS := $(BOOTSTRAP_CC_CFLAGS)
125BOOTSTRAP_VC_CFLAGS := $(BOOTSTRAP_CFLAGS)
126BOOTSTRAP_LDFLAGS := $(strip $(LDFLAGS))
127ifeq ($(LINUX),1)
128ifeq ($(TCCARCH),arm)
129BOOTSTRAP_LDFLAGS := $(strip $(BOOTSTRAP_LDFLAGS) -latomic)
130endif
131ifneq ($(filter $(TCCARCH),arm64 aarch64),)
132BOOTSTRAP_VC_UNSAFE_OPTFLAGS := $(filter-out -O -O0 -O1,$(filter -O%,$(BOOTSTRAP_CC_CFLAGS)))
133ifneq ($(BOOTSTRAP_VC_UNSAFE_OPTFLAGS),)
134 # Some Linux ARM64 system compilers miscompile the external vc bootstrap
135 # snapshot at -O2/-O3, making `v1` segfault before it can build `v2`.
136 # Keep the bootstrap stages at -O1, but preserve the requested flags for
137 # the final `v` build.
138 BOOTSTRAP_VC_SAFE_CFLAGS := $(strip $(filter-out -O%,$(BOOTSTRAP_CC_CFLAGS)) -O1)
139 BOOTSTRAP_VC_CC_CFLAGS := $(BOOTSTRAP_VC_SAFE_CFLAGS)
140 BOOTSTRAP_VC_CFLAGS := $(strip $(CPPFLAGS) $(BOOTSTRAP_VC_SAFE_CFLAGS))
141endif
142endif
143endif
144BOOTSTRAP_TCC_REQUESTED := $(or $(findstring -cc tcc,$(strip $(VFLAGS))),$(findstring -cc=tcc,$(strip $(VFLAGS))))
145BOOTSTRAP_CCOMPILER_VFLAG :=
146BOOTSTRAP_VC_CCOMPILER_VFLAG :=
147BOOTSTRAP_GC_VFLAG :=
148ifeq ($(filter -gc -gc=%,$(VFLAGS)),)
149 BOOTSTRAP_GC_VFLAG := -gc none
150endif
151ifeq ($(LINUX),1)
152ifneq ($(filter $(TCCARCH),arm64 aarch64),)
153ifeq ($(filter -cc,$(VFLAGS)),)
154ifeq ($(findstring -cc=,$(VFLAGS)),)
155 # Bundled TCC can hang or miscompile V while bootstrapping on Linux ARM64,
156 # so keep both `v1 -> v2` and `v2 -> v` on the same system compiler
157 # unless the user overrode it explicitly.
158 BOOTSTRAP_CCOMPILER_VFLAG := -cc "$(CC)"
159 BOOTSTRAP_VC_CCOMPILER_VFLAG := $(BOOTSTRAP_CCOMPILER_VFLAG)
160endif
161endif
162endif
163ifneq ($(BOOTSTRAP_TCC_REQUESTED),)
164ifneq ($(CC),tcc)
165 # The external vc bootstrap snapshot may still emit Windows-only stdio
166 # declarations for non-Windows TCC. Use the system compiler just for v1 -> v2.
167 BOOTSTRAP_VC_CCOMPILER_VFLAG := -cc "$(CC)"
168endif
169endif
170endif
171BOOTSTRAP_VC_VFLAGS := $(BOOTSTRAP_VC_CCOMPILER_VFLAG) $(if $(strip $(BOOTSTRAP_VC_CFLAGS)),-cflags "$(BOOTSTRAP_VC_CFLAGS)") $(if $(strip $(BOOTSTRAP_LDFLAGS)),-ldflags "$(BOOTSTRAP_LDFLAGS)")
172BOOTSTRAP_VFLAGS := $(BOOTSTRAP_CCOMPILER_VFLAG) $(if $(strip $(BOOTSTRAP_CFLAGS)),-cflags "$(BOOTSTRAP_CFLAGS)") $(if $(strip $(BOOTSTRAP_LDFLAGS)),-ldflags "$(BOOTSTRAP_LDFLAGS)")
173
174all: latest_vc latest_tcc latest_legacy
175ifdef WIN32
176 $(CC) $(CPPFLAGS) $(BOOTSTRAP_VC_CC_CFLAGS) -std=c99 -municode -w -o v1$(EXE_EXT) $(VC)/$(VCFILE) $(LDFLAGS) -lws2_32 || cmd/tools/cc_compilation_failed_windows.sh
177 ./v1$(EXE_EXT) -no-parallel -o v2$(EXE_EXT) $(BOOTSTRAP_GC_VFLAG) $(VFLAGS) $(BOOTSTRAP_VC_VFLAGS) cmd/v
178 ./v2$(EXE_EXT) -o $(VEXE)$(EXE_EXT) $(BOOTSTRAP_GC_VFLAG) $(VFLAGS) $(BOOTSTRAP_VFLAGS) cmd/v
179 $(RM) v1$(EXE_EXT)
180 $(RM) v2$(EXE_EXT)
181else
182ifdef LEGACY
183 $(MAKE) -C $(TMPLEGACY) CPPFLAGS='$(CPPFLAGS)' CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS)'
184 $(MAKE) -C $(TMPLEGACY) PREFIX=$(realpath $(LEGACYLIBS)) CPPFLAGS='$(CPPFLAGS)' CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS)' install
185 rm -rf $(TMPLEGACY)
186 $(eval override LDFLAGS+=-L$(realpath $(LEGACYLIBS))/lib -lMacportsLegacySupport)
187endif
188 $(CC) $(CPPFLAGS) $(BOOTSTRAP_VC_CC_CFLAGS) -std=c99 -w -o v1$(EXE_EXT) $(VC)/$(VCFILE) -lm -lpthread $(BOOTSTRAP_LDFLAGS) || cmd/tools/cc_compilation_failed_non_windows.sh
189ifdef NETBSD
190 paxctl +m v1$(EXE_EXT)
191endif
192 ./v1$(EXE_EXT) -no-parallel -o v2$(EXE_EXT) $(BOOTSTRAP_GC_VFLAG) $(VFLAGS) $(BOOTSTRAP_VC_VFLAGS) cmd/v
193ifdef NETBSD
194 paxctl +m v2$(EXE_EXT)
195endif
196 ./v2$(EXE_EXT) -nocache -o $(VEXE)$(EXE_EXT) $(BOOTSTRAP_GC_VFLAG) $(VFLAGS) $(BOOTSTRAP_VFLAGS) cmd/v
197ifdef NETBSD
198 paxctl +m $(VEXE)$(EXE_EXT)
199endif
200 rm -rf v1$(EXE_EXT) v2$(EXE_EXT)
201endif
202 @$(VEXE)$(EXE_EXT) run cmd/tools/detect_tcc.v
203 @echo "V has been successfully built"
204 @$(VEXE)$(EXE_EXT) -version
205 @$(VEXE)$(EXE_EXT) run .github/problem-matchers/register_all.vsh
206
207clean:
208 rm -rf $(TMPTCC)
209 rm -rf $(LEGACYLIBS)
210 rm -rf $(VC)
211
212rebuild: clean all
213
214ifndef local
215latest_vc: $(VC)/.git/config
216ifeq ($(HAS_GIT),1)
217 cd $(VC) && $(GITCLEANPULL)
218else
219 @echo "git not found; using existing $(VC)/$(VCFILE)"
220endif
221else
222latest_vc:
223 @echo "Using local vc"
224endif
225
226check_for_working_tcc:
227 @$(TMPTCC)/tcc.exe --version > /dev/null 2> /dev/null || echo "The executable '$(TMPTCC)/tcc.exe' does not work."
228
229fresh_vc:
230 rm -rf $(VC)
231ifeq ($(HAS_GIT),1)
232 $(GITFASTCLONE) $(VCREPO) $(VC)
233else
234 @echo "git is required to clone $(VCREPO) into $(VC)"
235 @exit 1
236endif
237
238ifndef local
239latest_tcc: $(TMPTCC)/.git/config
240ifeq ($(HAS_GIT),1)
241ifdef WIN32
242 @if [ -f "$(TMPTCC)/lib/advapi32.def" ]; then \
243 cd "$(TMPTCC)" && $(GIT) checkout -- lib/advapi32.def > /dev/null 2> /dev/null || true; \
244 fi
245endif
246 cd $(TMPTCC) && $(GITCLEANPULL)
247ifdef WIN32
248 @if [ -f "$(TMPTCC)/lib/advapi32.def" ]; then \
249 for sym in RegEnumKeyExW RegEnumValueW RegQueryInfoKeyW; do \
250 grep -qx "$$sym" "$(TMPTCC)/lib/advapi32.def" || printf '%s\n' "$$sym" >> "$(TMPTCC)/lib/advapi32.def"; \
251 done; \
252 fi
253endif
254else
255 @echo "git not found; skipping update of $(TMPTCC)"
256endif
257ifneq (,$(wildcard ./tcc.exe))
258 @$(MAKE) --quiet check_for_working_tcc 2> /dev/null
259endif
260
261else
262latest_tcc:
263 @echo "Using local tcc"
264 @$(MAKE) --quiet check_for_working_tcc 2> /dev/null
265endif
266
267# Rebuild the bundled TCC in-place from upstream tinycc, while preserving the
268# V-specific libgc/openlibm files already stored in $(TMPTCC).
269latest_tcc_source: $(TMPTCC)/.git/config
270ifeq ($(HAS_GIT),1)
271ifneq (,$(wildcard $(TCCBUILDSCRIPT)))
272 @TCC_FOLDER='$(TMPTCC)' $(if $(strip $(TCC_COMMIT)),TCC_COMMIT='$(TCC_COMMIT)') CC='$(CC)' bash '$(TCCBUILDSCRIPT)'
273 @$(MAKE) --quiet check_for_working_tcc 2> /dev/null
274else
275 @echo 'No upstream TinyCC build script is available for thirdparty-$(TCCOS)-$(TCCARCH).'
276 @echo 'Use `make latest_tcc` to refresh the prebuilt bundle from $(TCCREPO).'
277 @exit 1
278endif
279else
280 @echo "git is required to bootstrap $(TMPTCC) before rebuilding it from source"
281 @exit 1
282endif
283
284fresh_tcc:
285 rm -rf $(TMPTCC)
286ifndef local
287ifeq ($(HAS_GIT),1)
288 @set -e; \
289 branches="$$( $(GIT) ls-remote --heads $(TCCREPO) 2> /dev/null | awk '{sub("refs/heads/","",$$2); print $$2}' || true )"; \
290 preferred_branch='thirdparty-$(TCCOS)-$(TCCARCH)'; \
291 fallback_branch=''; \
292 if [ "$(LINUX)" = "1" ]; then \
293 fallback_branch='thirdparty-linuxmusl-$(TCCARCH)'; \
294 fi; \
295 selected_branch=''; \
296 if printf '%s\n' "$$branches" | grep -Fx "$$preferred_branch" > /dev/null; then \
297 selected_branch="$$preferred_branch"; \
298 elif [ "$$fallback_branch" != '' ] && [ "$$fallback_branch" != "$$preferred_branch" ] \
299 && printf '%s\n' "$$branches" | grep -Fx "$$fallback_branch" > /dev/null; then \
300 selected_branch="$$fallback_branch"; \
301 fi; \
302 if [ "$$selected_branch" = '' ]; then \
303 echo "Pre-built TCC not available for $$preferred_branch at $(TCCREPO), will use the system compiler: $(CC)"; \
304 $(GITFASTCLONE) --branch thirdparty-unknown-unknown $(TCCREPO) "$(TMPTCC)"; \
305 else \
306 $(GITFASTCLONE) --branch "$$selected_branch" $(TCCREPO) "$(TMPTCC)"; \
307 if [ -f "$(TMPTCC)/lib/advapi32.def" ]; then \
308 for sym in RegEnumKeyExW RegEnumValueW RegQueryInfoKeyW; do \
309 grep -qx "$$sym" "$(TMPTCC)/lib/advapi32.def" || printf '%s\n' "$$sym" >> "$(TMPTCC)/lib/advapi32.def"; \
310 done; \
311 fi; \
312 if ! "$(TMPTCC)/tcc.exe" --version > /dev/null 2> /dev/null; then \
313 if [ "$$fallback_branch" != '' ] && [ "$$fallback_branch" != "$$selected_branch" ] \
314 && printf '%s\n' "$$branches" | grep -Fx "$$fallback_branch" > /dev/null; then \
315 echo "Pre-built TCC bundle $$selected_branch did not run; retrying with $$fallback_branch."; \
316 rm -rf "$(TMPTCC)"; \
317 $(GITFASTCLONE) --branch "$$fallback_branch" $(TCCREPO) "$(TMPTCC)"; \
318 fi; \
319 $(MAKE) --quiet check_for_working_tcc 2> /dev/null; \
320 else \
321 $(MAKE) --quiet check_for_working_tcc 2> /dev/null; \
322 fi; \
323 fi
324else
325 @echo "git is required to clone $(TCCREPO)"
326 @exit 1
327endif
328else
329 @echo "Using local tccbin"
330 @$(MAKE) --quiet check_for_working_tcc 2> /dev/null
331endif
332
333ifndef local
334latest_legacy: $(TMPLEGACY)/.git/config
335ifdef LEGACY
336ifeq ($(HAS_GIT),1)
337 cd $(TMPLEGACY) && $(GITCLEANPULL)
338else
339 @echo "git not found; using existing $(TMPLEGACY)"
340endif
341endif
342else
343latest_legacy:
344ifdef LEGACY
345 @echo "Using local legacysupport"
346endif
347endif
348
349fresh_legacy:
350 rm -rf $(LEGACYLIBS)
351ifeq ($(HAS_GIT),1)
352 $(GITFASTCLONE) $(LEGACYREPO) $(TMPLEGACY)
353else
354 @echo "git is required to clone $(LEGACYREPO)"
355 @exit 1
356endif
357
358$(TMPTCC)/.git/config:
359ifeq ($(HAS_GIT),1)
360 $(MAKE) fresh_tcc
361else
362 @echo "git not found; skipping bootstrap of $(TMPTCC), system compiler $(CC) will be used"
363endif
364
365$(VC)/.git/config:
366ifeq ($(HAS_GIT),1)
367 $(MAKE) fresh_vc
368else
369 @if [ -f "$(VC)/$(VCFILE)" ]; then \
370 echo "git not found; using existing $(VC)/$(VCFILE)"; \
371 else \
372 echo "git is required to download $(VC)/$(VCFILE). Install git or provide the file manually."; \
373 exit 1; \
374 fi
375endif
376
377$(TMPLEGACY)/.git/config:
378ifdef LEGACY
379ifeq ($(HAS_GIT),1)
380 $(MAKE) fresh_legacy
381else
382 @if [ -d "$(TMPLEGACY)" ]; then \
383 echo "git not found; using existing $(TMPLEGACY)"; \
384 else \
385 echo "git is required to download legacy support sources ($(LEGACYREPO))"; \
386 exit 1; \
387 fi
388endif
389endif
390
391asan:
392 $(MAKE) all CFLAGS='-fsanitize=address,undefined'
393
394selfcompile:
395 $(VEXE)$(EXE_EXT) -cg -o v cmd/v
396
397selfcompile-static:
398 $(VEXE)$(EXE_EXT) -cg -cflags '--static' -o v-static cmd/v
399
400### NB: Please keep this Makefile and makev.bat simple.
401install:
402 @echo 'Please use `sudo ./v symlink` instead, or manually add the current directory to your PATH.'
403
404check:
405 $(VEXE)$(EXE_EXT) test-all
406
407etags:
408 ./v$(EXE_EXT) -print-v-files cmd/v | grep -v :parse_text| etags -L -
409
410ctags:
411 ./v$(EXE_EXT) -print-v-files cmd/v | grep -v :parse_text| ctags -L -
412