v2 / GNUmakefile
407 lines · 369 sloc · 11.93 KB · 5be2b1d9cd1f93efc8a776455991080648a51fb9
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 :=
147ifeq ($(LINUX),1)
148ifneq ($(filter $(TCCARCH),arm64 aarch64),)
149ifeq ($(filter -cc,$(VFLAGS)),)
150ifeq ($(findstring -cc=,$(VFLAGS)),)
151 # Bundled TCC can hang or miscompile V while bootstrapping on Linux ARM64,
152 # so keep both `v1 -> v2` and `v2 -> v` on the same system compiler
153 # unless the user overrode it explicitly.
154 BOOTSTRAP_CCOMPILER_VFLAG := -cc "$(CC)"
155 BOOTSTRAP_VC_CCOMPILER_VFLAG := $(BOOTSTRAP_CCOMPILER_VFLAG)
156endif
157endif
158endif
159ifneq ($(BOOTSTRAP_TCC_REQUESTED),)
160ifneq ($(CC),tcc)
161 # The external vc bootstrap snapshot may still emit Windows-only stdio
162 # declarations for non-Windows TCC. Use the system compiler just for v1 -> v2.
163 BOOTSTRAP_VC_CCOMPILER_VFLAG := -cc "$(CC)"
164endif
165endif
166endif
167BOOTSTRAP_VC_VFLAGS := $(BOOTSTRAP_VC_CCOMPILER_VFLAG) $(if $(strip $(BOOTSTRAP_VC_CFLAGS)),-cflags "$(BOOTSTRAP_VC_CFLAGS)") $(if $(strip $(BOOTSTRAP_LDFLAGS)),-ldflags "$(BOOTSTRAP_LDFLAGS)")
168BOOTSTRAP_VFLAGS := $(BOOTSTRAP_CCOMPILER_VFLAG) $(if $(strip $(BOOTSTRAP_CFLAGS)),-cflags "$(BOOTSTRAP_CFLAGS)") $(if $(strip $(BOOTSTRAP_LDFLAGS)),-ldflags "$(BOOTSTRAP_LDFLAGS)")
169
170all: latest_vc latest_tcc latest_legacy
171ifdef WIN32
172 $(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
173 ./v1$(EXE_EXT) -no-parallel -o v2$(EXE_EXT) $(VFLAGS) $(BOOTSTRAP_VC_VFLAGS) cmd/v
174 ./v2$(EXE_EXT) -o $(VEXE)$(EXE_EXT) $(VFLAGS) $(BOOTSTRAP_VFLAGS) cmd/v
175 $(RM) v1$(EXE_EXT)
176 $(RM) v2$(EXE_EXT)
177else
178ifdef LEGACY
179 $(MAKE) -C $(TMPLEGACY) CPPFLAGS='$(CPPFLAGS)' CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS)'
180 $(MAKE) -C $(TMPLEGACY) PREFIX=$(realpath $(LEGACYLIBS)) CPPFLAGS='$(CPPFLAGS)' CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS)' install
181 rm -rf $(TMPLEGACY)
182 $(eval override LDFLAGS+=-L$(realpath $(LEGACYLIBS))/lib -lMacportsLegacySupport)
183endif
184 $(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
185ifdef NETBSD
186 paxctl +m v1$(EXE_EXT)
187endif
188 ./v1$(EXE_EXT) -no-parallel -o v2$(EXE_EXT) $(VFLAGS) $(BOOTSTRAP_VC_VFLAGS) cmd/v
189ifdef NETBSD
190 paxctl +m v2$(EXE_EXT)
191endif
192 ./v2$(EXE_EXT) -nocache -o $(VEXE)$(EXE_EXT) $(VFLAGS) $(BOOTSTRAP_VFLAGS) cmd/v
193ifdef NETBSD
194 paxctl +m $(VEXE)$(EXE_EXT)
195endif
196 rm -rf v1$(EXE_EXT) v2$(EXE_EXT)
197endif
198 @$(VEXE)$(EXE_EXT) run cmd/tools/detect_tcc.v
199 @echo "V has been successfully built"
200 @$(VEXE)$(EXE_EXT) -version
201 @$(VEXE)$(EXE_EXT) run .github/problem-matchers/register_all.vsh
202
203clean:
204 rm -rf $(TMPTCC)
205 rm -rf $(LEGACYLIBS)
206 rm -rf $(VC)
207
208rebuild: clean all
209
210ifndef local
211latest_vc: $(VC)/.git/config
212ifeq ($(HAS_GIT),1)
213 cd $(VC) && $(GITCLEANPULL)
214else
215 @echo "git not found; using existing $(VC)/$(VCFILE)"
216endif
217else
218latest_vc:
219 @echo "Using local vc"
220endif
221
222check_for_working_tcc:
223 @$(TMPTCC)/tcc.exe --version > /dev/null 2> /dev/null || echo "The executable '$(TMPTCC)/tcc.exe' does not work."
224
225fresh_vc:
226 rm -rf $(VC)
227ifeq ($(HAS_GIT),1)
228 $(GITFASTCLONE) $(VCREPO) $(VC)
229else
230 @echo "git is required to clone $(VCREPO) into $(VC)"
231 @exit 1
232endif
233
234ifndef local
235latest_tcc: $(TMPTCC)/.git/config
236ifeq ($(HAS_GIT),1)
237ifdef WIN32
238 @if [ -f "$(TMPTCC)/lib/advapi32.def" ]; then \
239 cd "$(TMPTCC)" && $(GIT) checkout -- lib/advapi32.def > /dev/null 2> /dev/null || true; \
240 fi
241endif
242 cd $(TMPTCC) && $(GITCLEANPULL)
243ifdef WIN32
244 @if [ -f "$(TMPTCC)/lib/advapi32.def" ]; then \
245 for sym in RegEnumKeyExW RegEnumValueW RegQueryInfoKeyW; do \
246 grep -qx "$$sym" "$(TMPTCC)/lib/advapi32.def" || printf '%s\n' "$$sym" >> "$(TMPTCC)/lib/advapi32.def"; \
247 done; \
248 fi
249endif
250else
251 @echo "git not found; skipping update of $(TMPTCC)"
252endif
253ifneq (,$(wildcard ./tcc.exe))
254 @$(MAKE) --quiet check_for_working_tcc 2> /dev/null
255endif
256
257else
258latest_tcc:
259 @echo "Using local tcc"
260 @$(MAKE) --quiet check_for_working_tcc 2> /dev/null
261endif
262
263# Rebuild the bundled TCC in-place from upstream tinycc, while preserving the
264# V-specific libgc/openlibm files already stored in $(TMPTCC).
265latest_tcc_source: $(TMPTCC)/.git/config
266ifeq ($(HAS_GIT),1)
267ifneq (,$(wildcard $(TCCBUILDSCRIPT)))
268 @TCC_FOLDER='$(TMPTCC)' $(if $(strip $(TCC_COMMIT)),TCC_COMMIT='$(TCC_COMMIT)') CC='$(CC)' bash '$(TCCBUILDSCRIPT)'
269 @$(MAKE) --quiet check_for_working_tcc 2> /dev/null
270else
271 @echo 'No upstream TinyCC build script is available for thirdparty-$(TCCOS)-$(TCCARCH).'
272 @echo 'Use `make latest_tcc` to refresh the prebuilt bundle from $(TCCREPO).'
273 @exit 1
274endif
275else
276 @echo "git is required to bootstrap $(TMPTCC) before rebuilding it from source"
277 @exit 1
278endif
279
280fresh_tcc:
281 rm -rf $(TMPTCC)
282ifndef local
283ifeq ($(HAS_GIT),1)
284 @set -e; \
285 branches="$$( $(GIT) ls-remote --heads $(TCCREPO) 2> /dev/null | awk '{sub("refs/heads/","",$$2); print $$2}' || true )"; \
286 preferred_branch='thirdparty-$(TCCOS)-$(TCCARCH)'; \
287 fallback_branch=''; \
288 if [ "$(LINUX)" = "1" ]; then \
289 fallback_branch='thirdparty-linuxmusl-$(TCCARCH)'; \
290 fi; \
291 selected_branch=''; \
292 if printf '%s\n' "$$branches" | grep -Fx "$$preferred_branch" > /dev/null; then \
293 selected_branch="$$preferred_branch"; \
294 elif [ "$$fallback_branch" != '' ] && [ "$$fallback_branch" != "$$preferred_branch" ] \
295 && printf '%s\n' "$$branches" | grep -Fx "$$fallback_branch" > /dev/null; then \
296 selected_branch="$$fallback_branch"; \
297 fi; \
298 if [ "$$selected_branch" = '' ]; then \
299 echo "Pre-built TCC not available for $$preferred_branch at $(TCCREPO), will use the system compiler: $(CC)"; \
300 $(GITFASTCLONE) --branch thirdparty-unknown-unknown $(TCCREPO) "$(TMPTCC)"; \
301 else \
302 $(GITFASTCLONE) --branch "$$selected_branch" $(TCCREPO) "$(TMPTCC)"; \
303 if [ -f "$(TMPTCC)/lib/advapi32.def" ]; then \
304 for sym in RegEnumKeyExW RegEnumValueW RegQueryInfoKeyW; do \
305 grep -qx "$$sym" "$(TMPTCC)/lib/advapi32.def" || printf '%s\n' "$$sym" >> "$(TMPTCC)/lib/advapi32.def"; \
306 done; \
307 fi; \
308 if ! "$(TMPTCC)/tcc.exe" --version > /dev/null 2> /dev/null; then \
309 if [ "$$fallback_branch" != '' ] && [ "$$fallback_branch" != "$$selected_branch" ] \
310 && printf '%s\n' "$$branches" | grep -Fx "$$fallback_branch" > /dev/null; then \
311 echo "Pre-built TCC bundle $$selected_branch did not run; retrying with $$fallback_branch."; \
312 rm -rf "$(TMPTCC)"; \
313 $(GITFASTCLONE) --branch "$$fallback_branch" $(TCCREPO) "$(TMPTCC)"; \
314 fi; \
315 $(MAKE) --quiet check_for_working_tcc 2> /dev/null; \
316 else \
317 $(MAKE) --quiet check_for_working_tcc 2> /dev/null; \
318 fi; \
319 fi
320else
321 @echo "git is required to clone $(TCCREPO)"
322 @exit 1
323endif
324else
325 @echo "Using local tccbin"
326 @$(MAKE) --quiet check_for_working_tcc 2> /dev/null
327endif
328
329ifndef local
330latest_legacy: $(TMPLEGACY)/.git/config
331ifdef LEGACY
332ifeq ($(HAS_GIT),1)
333 cd $(TMPLEGACY) && $(GITCLEANPULL)
334else
335 @echo "git not found; using existing $(TMPLEGACY)"
336endif
337endif
338else
339latest_legacy:
340ifdef LEGACY
341 @echo "Using local legacysupport"
342endif
343endif
344
345fresh_legacy:
346 rm -rf $(LEGACYLIBS)
347ifeq ($(HAS_GIT),1)
348 $(GITFASTCLONE) $(LEGACYREPO) $(TMPLEGACY)
349else
350 @echo "git is required to clone $(LEGACYREPO)"
351 @exit 1
352endif
353
354$(TMPTCC)/.git/config:
355ifeq ($(HAS_GIT),1)
356 $(MAKE) fresh_tcc
357else
358 @echo "git not found; skipping bootstrap of $(TMPTCC), system compiler $(CC) will be used"
359endif
360
361$(VC)/.git/config:
362ifeq ($(HAS_GIT),1)
363 $(MAKE) fresh_vc
364else
365 @if [ -f "$(VC)/$(VCFILE)" ]; then \
366 echo "git not found; using existing $(VC)/$(VCFILE)"; \
367 else \
368 echo "git is required to download $(VC)/$(VCFILE). Install git or provide the file manually."; \
369 exit 1; \
370 fi
371endif
372
373$(TMPLEGACY)/.git/config:
374ifdef LEGACY
375ifeq ($(HAS_GIT),1)
376 $(MAKE) fresh_legacy
377else
378 @if [ -d "$(TMPLEGACY)" ]; then \
379 echo "git not found; using existing $(TMPLEGACY)"; \
380 else \
381 echo "git is required to download legacy support sources ($(LEGACYREPO))"; \
382 exit 1; \
383 fi
384endif
385endif
386
387asan:
388 $(MAKE) all CFLAGS='-fsanitize=address,undefined'
389
390selfcompile:
391 $(VEXE)$(EXE_EXT) -cg -o v cmd/v
392
393selfcompile-static:
394 $(VEXE)$(EXE_EXT) -cg -cflags '--static' -o v-static cmd/v
395
396### NB: Please keep this Makefile and makev.bat simple.
397install:
398 @echo 'Please use `sudo ./v symlink` instead, or manually add the current directory to your PATH.'
399
400check:
401 $(VEXE)$(EXE_EXT) test-all
402
403etags:
404 ./v$(EXE_EXT) -print-v-files cmd/v | grep -v :parse_text| etags -L -
405
406ctags:
407 ./v$(EXE_EXT) -print-v-files cmd/v | grep -v :parse_text| ctags -L -
408