1#
2# QuickJS Javascript Engine
3#
4# Copyright (c) 2017-2021 Fabrice Bellard
5# Copyright (c) 2017-2021 Charlie Gordon
6#
7# Permission is hereby granted, free of charge, to any person obtaining a copy
8# of this software and associated documentation files (the "Software"), to deal
9# in the Software without restriction, including without limitation the rights
10# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11# copies of the Software, and to permit persons to whom the Software is
12# furnished to do so, subject to the following conditions:
13#
14# The above copyright notice and this permission notice shall be included in
15# all copies or substantial portions of the Software.
16#
17# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23# THE SOFTWARE.
24
25ifeq ($(shell uname -s),Darwin)
26CONFIG_DARWIN=y
27endif
28ifeq ($(shell uname -s),DragonFly)
29CONFIG_DRAGONFLY=y
30endif
31ifeq ($(shell uname -s),FreeBSD)
32CONFIG_FREEBSD=y
33endif
34# Windows cross compilation from Linux
35#CONFIG_WIN32=y
36# use link time optimization (smaller and faster executables but slower build)
37CONFIG_LTO=y
38# consider warnings as errors (for development)
39#CONFIG_WERROR=y
40# force 32 bit build for some utilities
41#CONFIG_M32=y
42
43ifdef CONFIG_DARWIN
44# use clang instead of gcc
45CONFIG_CLANG=y
46CONFIG_DEFAULT_AR=y
47endif
48ifdef CONFIG_DRAGONFLY
49CONFIG_DEFAULT_AR=y
50CONFIG_LTO=
51endif
52ifdef CONFIG_FREEBSD
53# use clang instead of gcc
54CONFIG_CLANG=
55CONFIG_DEFAULT_AR=y
56CONFIG_LTO=
57endif
58
59# installation directory
60prefix=/usr/local
61
62# use the gprof profiler
63#CONFIG_PROFILE=y
64# use address sanitizer
65#CONFIG_ASAN=y
66# include the code for BigInt/BigFloat/BigDecimal and math mode
67CONFIG_BIGNUM=y
68
69OBJDIR=.obj
70
71ifdef CONFIG_WIN32
72  ifdef CONFIG_M32
73    CROSS_PREFIX=i686-w64-mingw32-
74  else
75    CROSS_PREFIX=x86_64-w64-mingw32-
76  endif
77  EXE=.exe
78else
79  CROSS_PREFIX=
80  EXE=
81endif
82ifdef CONFIG_CLANG
83  HOST_CC=gcc
84  CC=gcc
85  CFLAGS=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d
86  CFLAGS += -Wextra
87  CFLAGS += -Wno-sign-compare
88  CFLAGS += -Wno-missing-field-initializers
89  CFLAGS += -Wundef -Wuninitialized
90  CFLAGS += -Wunused -Wno-unused-parameter
91  CFLAGS += -Wwrite-strings
92  CFLAGS += -Wchar-subscripts -funsigned-char
93  CFLAGS += -MMD -MF $(OBJDIR)/$(@F).d
94  ifdef CONFIG_DEFAULT_AR
95    AR=$(CROSS_PREFIX)ar
96  else
97    ifdef CONFIG_LTO
98      AR=$(CROSS_PREFIX)llvm-ar
99    else
100      AR=$(CROSS_PREFIX)ar
101    endif
102  endif
103else
104  HOST_CC=gcc
105  CC=gcc
106  CFLAGS=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d
107  CFLAGS += -Wno-array-bounds -Wno-format-truncation
108  ifdef CONFIG_LTO
109    AR=$(CROSS_PREFIX)gcc-ar
110  else
111    AR=$(CROSS_PREFIX)ar
112  endif
113endif
114STRIP=$(CROSS_PREFIX)strip
115ifdef CONFIG_WERROR
116CFLAGS+=-Werror
117endif
118DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\"
119ifdef CONFIG_BIGNUM
120DEFINES+=-DCONFIG_BIGNUM
121endif
122ifdef CONFIG_WIN32
123DEFINES+=-D__USE_MINGW_ANSI_STDIO # for standard snprintf behavior
124endif
125
126CFLAGS+=$(DEFINES)
127CFLAGS_DEBUG=$(CFLAGS) -O0
128CFLAGS_SMALL=$(CFLAGS) -Os
129CFLAGS_OPT=$(CFLAGS) -O2
130CFLAGS_NOLTO:=$(CFLAGS_OPT)
131LDFLAGS=-g
132ifdef CONFIG_LTO
133CFLAGS_SMALL+=-flto
134CFLAGS_OPT+=-flto
135LDFLAGS+=-flto
136endif
137ifdef CONFIG_PROFILE
138CFLAGS+=-p
139LDFLAGS+=-p
140endif
141ifdef CONFIG_ASAN
142CFLAGS+=-fsanitize=address -fno-omit-frame-pointer
143LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer
144endif
145ifdef CONFIG_WIN32
146LDEXPORT=
147else
148LDEXPORT=-rdynamic
149endif
150
151PROGS=qjs$(EXE) qjsc$(EXE) run-test262
152ifneq ($(CROSS_PREFIX),)
153QJSC_CC=gcc
154QJSC=./host-qjsc
155PROGS+=$(QJSC)
156else
157QJSC_CC=$(CC)
158QJSC=./qjsc$(EXE)
159endif
160ifndef CONFIG_WIN32
161PROGS+=qjscalc
162endif
163ifdef CONFIG_M32
164PROGS+=qjs32 qjs32_s
165endif
166PROGS+=libquickjs.a
167ifdef CONFIG_LTO
168PROGS+=libquickjs.lto.a
169endif
170
171# examples
172ifeq ($(CROSS_PREFIX),)
173ifdef CONFIG_ASAN
174PROGS+=
175else
176PROGS+=examples/hello examples/hello_module examples/test_fib
177ifndef CONFIG_DARWIN
178PROGS+=examples/fib.so examples/point.so
179endif
180endif
181endif
182
183all: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS)
184
185QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o
186
187QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS)
188ifdef CONFIG_BIGNUM
189QJS_LIB_OBJS+=$(OBJDIR)/libbf.o
190QJS_OBJS+=$(OBJDIR)/qjscalc.o
191endif
192
193HOST_LIBS=-lm -ldl -lpthread
194LIBS=-lm
195ifndef CONFIG_WIN32
196LIBS+=-ldl -lpthread
197endif
198LIBS+=$(EXTRA_LIBS)
199
200$(OBJDIR):
201	mkdir -p $(OBJDIR) $(OBJDIR)/examples $(OBJDIR)/tests
202
203qjs$(EXE): $(QJS_OBJS)
204	$(CC) $(LDFLAGS) $(LDEXPORT) -o $@ $^ $(LIBS)
205
206qjs-debug$(EXE): $(patsubst %.o, %.debug.o, $(QJS_OBJS))
207	$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
208
209qjsc$(EXE): $(OBJDIR)/qjsc.o $(QJS_LIB_OBJS)
210	$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
211
212ifneq ($(CROSS_PREFIX),)
213
214$(QJSC): $(OBJDIR)/qjsc.host.o \
215    $(patsubst %.o, %.host.o, $(QJS_LIB_OBJS))
216	$(HOST_CC) $(LDFLAGS) -o $@ $^ $(HOST_LIBS)
217
218endif #CROSS_PREFIX
219
220QJSC_DEFINES:=-DCONFIG_CC=\"$(QJSC_CC)\" -DCONFIG_PREFIX=\"$(prefix)\"
221ifdef CONFIG_LTO
222QJSC_DEFINES+=-DCONFIG_LTO
223endif
224QJSC_HOST_DEFINES:=-DCONFIG_CC=\"$(HOST_CC)\" -DCONFIG_PREFIX=\"$(prefix)\"
225
226$(OBJDIR)/qjsc.o: CFLAGS+=$(QJSC_DEFINES)
227$(OBJDIR)/qjsc.host.o: CFLAGS+=$(QJSC_HOST_DEFINES)
228
229qjs32: $(patsubst %.o, %.m32.o, $(QJS_OBJS))
230	$(CC) -m32 $(LDFLAGS) $(LDEXPORT) -o $@ $^ $(LIBS)
231
232qjs32_s: $(patsubst %.o, %.m32s.o, $(QJS_OBJS))
233	$(CC) -m32 $(LDFLAGS) -o $@ $^ $(LIBS)
234	@size $@
235
236qjscalc: qjs
237	ln -sf $< $@
238
239ifdef CONFIG_LTO
240LTOEXT=.lto
241else
242LTOEXT=
243endif
244
245libquickjs$(LTOEXT).a: $(QJS_LIB_OBJS)
246	$(AR) rcs $@ $^
247
248ifdef CONFIG_LTO
249libquickjs.a: $(patsubst %.o, %.nolto.o, $(QJS_LIB_OBJS))
250	$(AR) rcs $@ $^
251endif # CONFIG_LTO
252
253repl.c: $(QJSC) repl.js
254	$(QJSC) -c -o $@ -m repl.js
255
256qjscalc.c: $(QJSC) qjscalc.js
257	$(QJSC) -fbignum -c -o $@ qjscalc.js
258
259ifneq ($(wildcard unicode/UnicodeData.txt),)
260$(OBJDIR)/libunicode.o $(OBJDIR)/libunicode.m32.o $(OBJDIR)/libunicode.m32s.o \
261    $(OBJDIR)/libunicode.nolto.o: libunicode-table.h
262
263libunicode-table.h: unicode_gen
264	./unicode_gen unicode $@
265endif
266
267run-test262: $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS)
268	$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
269
270run-test262-debug: $(patsubst %.o, %.debug.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS))
271	$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
272
273run-test262-32: $(patsubst %.o, %.m32.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS))
274	$(CC) -m32 $(LDFLAGS) -o $@ $^ $(LIBS)
275
276# object suffix order: nolto, [m32|m32s]
277
278$(OBJDIR)/%.o: %.c | $(OBJDIR)
279	$(CC) $(CFLAGS_OPT) -c -o $@ $<
280
281$(OBJDIR)/%.host.o: %.c | $(OBJDIR)
282	$(HOST_CC) $(CFLAGS_OPT) -c -o $@ $<
283
284$(OBJDIR)/%.pic.o: %.c | $(OBJDIR)
285	$(CC) $(CFLAGS_OPT) -fPIC -DJS_SHARED_LIBRARY -c -o $@ $<
286
287$(OBJDIR)/%.nolto.o: %.c | $(OBJDIR)
288	$(CC) $(CFLAGS_NOLTO) -c -o $@ $<
289
290$(OBJDIR)/%.m32.o: %.c | $(OBJDIR)
291	$(CC) -m32 $(CFLAGS_OPT) -c -o $@ $<
292
293$(OBJDIR)/%.m32s.o: %.c | $(OBJDIR)
294	$(CC) -m32 $(CFLAGS_SMALL) -c -o $@ $<
295
296$(OBJDIR)/%.debug.o: %.c | $(OBJDIR)
297	$(CC) $(CFLAGS_DEBUG) -c -o $@ $<
298
299$(OBJDIR)/%.check.o: %.c | $(OBJDIR)
300	$(CC) $(CFLAGS) -DCONFIG_CHECK_JSVALUE -c -o $@ $<
301
302regexp_test: libregexp.c libunicode.c cutils.c
303	$(CC) $(LDFLAGS) $(CFLAGS) -DTEST -o $@ libregexp.c libunicode.c cutils.c $(LIBS)
304
305unicode_gen: $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o libunicode.c unicode_gen_def.h
306	$(HOST_CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o
307
308clean:
309	rm -f repl.c qjscalc.c out.c
310	rm -f *.a *.o *.d *~ unicode_gen regexp_test $(PROGS)
311	rm -f hello.c test_fib.c
312	rm -f examples/*.so tests/*.so
313	rm -rf $(OBJDIR)/ *.dSYM/ qjs-debug
314	rm -rf run-test262-debug run-test262-32
315
316install: all
317	mkdir -p "$(DESTDIR)$(prefix)/bin"
318	$(STRIP) qjs qjsc
319	install -m755 qjs qjsc "$(DESTDIR)$(prefix)/bin"
320	ln -sf qjs "$(DESTDIR)$(prefix)/bin/qjscalc"
321	mkdir -p "$(DESTDIR)$(prefix)/lib/quickjs"
322	install -m644 libquickjs.a "$(DESTDIR)$(prefix)/lib/quickjs"
323ifdef CONFIG_LTO
324	install -m644 libquickjs.lto.a "$(DESTDIR)$(prefix)/lib/quickjs"
325endif
326	mkdir -p "$(DESTDIR)$(prefix)/include/quickjs"
327	install -m644 quickjs.h quickjs-libc.h "$(DESTDIR)$(prefix)/include/quickjs"
328
329###############################################################################
330# examples
331
332# example of static JS compilation
333HELLO_SRCS=examples/hello.js
334HELLO_OPTS=-fno-string-normalize -fno-map -fno-promise -fno-typedarray \
335           -fno-typedarray -fno-regexp -fno-json -fno-eval -fno-proxy \
336           -fno-date -fno-module-loader
337ifdef CONFIG_BIGNUM
338HELLO_OPTS+=-fno-bigint
339endif
340
341hello.c: $(QJSC) $(HELLO_SRCS)
342	$(QJSC) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS)
343
344ifdef CONFIG_M32
345examples/hello: $(OBJDIR)/hello.m32s.o $(patsubst %.o, %.m32s.o, $(QJS_LIB_OBJS))
346	$(CC) -m32 $(LDFLAGS) -o $@ $^ $(LIBS)
347else
348examples/hello: $(OBJDIR)/hello.o $(QJS_LIB_OBJS)
349	$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
350endif
351
352# example of static JS compilation with modules
353HELLO_MODULE_SRCS=examples/hello_module.js
354HELLO_MODULE_OPTS=-fno-string-normalize -fno-map -fno-promise -fno-typedarray \
355           -fno-typedarray -fno-regexp -fno-json -fno-eval -fno-proxy \
356           -fno-date -m
357examples/hello_module: $(QJSC) libquickjs$(LTOEXT).a $(HELLO_MODULE_SRCS)
358	$(QJSC) $(HELLO_MODULE_OPTS) -o $@ $(HELLO_MODULE_SRCS)
359
360# use of an external C module (static compilation)
361
362test_fib.c: $(QJSC) examples/test_fib.js
363	$(QJSC) -e -M examples/fib.so,fib -m -o $@ examples/test_fib.js
364
365examples/test_fib: $(OBJDIR)/test_fib.o $(OBJDIR)/examples/fib.o libquickjs$(LTOEXT).a
366	$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
367
368examples/fib.so: $(OBJDIR)/examples/fib.pic.o
369	$(CC) $(LDFLAGS) -shared -o $@ $^
370
371examples/point.so: $(OBJDIR)/examples/point.pic.o
372	$(CC) $(LDFLAGS) -shared -o $@ $^
373
374###############################################################################
375# documentation
376
377DOCS=doc/quickjs.pdf doc/quickjs.html doc/jsbignum.pdf doc/jsbignum.html
378
379build_doc: $(DOCS)
380
381clean_doc:
382	rm -f $(DOCS)
383
384doc/%.pdf: doc/%.texi
385	texi2pdf --clean -o $@ -q $<
386
387doc/%.html.pre: doc/%.texi
388	makeinfo --html --no-headers --no-split --number-sections -o $@ $<
389
390doc/%.html: doc/%.html.pre
391	sed -e 's|</style>|</style>\n<meta name="viewport" content="width=device-width, initial-scale=1.0">|' < $< > $@
392
393###############################################################################
394# tests
395
396ifndef CONFIG_DARWIN
397test: tests/bjson.so examples/point.so
398endif
399ifdef CONFIG_M32
400test: qjs32
401endif
402
403test: qjs
404	./qjs tests/test_closure.js
405	./qjs tests/test_language.js
406	./qjs tests/test_builtin.js
407	./qjs tests/test_loop.js
408	./qjs tests/test_std.js
409	./qjs tests/test_worker.js
410ifndef CONFIG_DARWIN
411ifdef CONFIG_BIGNUM
412	./qjs --bignum tests/test_bjson.js
413else
414	./qjs tests/test_bjson.js
415endif
416	./qjs examples/test_point.js
417endif
418ifdef CONFIG_BIGNUM
419	./qjs --bignum tests/test_op_overloading.js
420	./qjs --bignum tests/test_bignum.js
421	./qjs --qjscalc tests/test_qjscalc.js
422endif
423ifdef CONFIG_M32
424	./qjs32 tests/test_closure.js
425	./qjs32 tests/test_language.js
426	./qjs32 tests/test_builtin.js
427	./qjs32 tests/test_loop.js
428	./qjs32 tests/test_std.js
429	./qjs32 tests/test_worker.js
430ifdef CONFIG_BIGNUM
431	./qjs32 --bignum tests/test_op_overloading.js
432	./qjs32 --bignum tests/test_bignum.js
433	./qjs32 --qjscalc tests/test_qjscalc.js
434endif
435endif
436
437stats: qjs qjs32
438	./qjs -qd
439	./qjs32 -qd
440
441microbench: qjs
442	./qjs tests/microbench.js
443
444microbench-32: qjs32
445	./qjs32 tests/microbench.js
446
447# ES5 tests (obsolete)
448test2o: run-test262
449	time ./run-test262 -m -c test262o.conf
450
451test2o-32: run-test262-32
452	time ./run-test262-32 -m -c test262o.conf
453
454test2o-update: run-test262
455	./run-test262 -u -c test262o.conf
456
457# Test262 tests
458test2-default: run-test262
459	time ./run-test262 -m -c test262.conf
460
461test2: run-test262
462	time ./run-test262 -m -c test262.conf -a
463
464test2-32: run-test262-32
465	time ./run-test262-32 -m -c test262.conf -a
466
467test2-update: run-test262
468	./run-test262 -u -c test262.conf -a
469
470test2-check: run-test262
471	time ./run-test262 -m -c test262.conf -E -a
472
473testall: all test microbench test2o test2
474
475testall-32: all test-32 microbench-32 test2o-32 test2-32
476
477testall-complete: testall testall-32
478
479bench-v8: qjs
480	make -C tests/bench-v8
481	./qjs -d tests/bench-v8/combined.js
482
483tests/bjson.so: $(OBJDIR)/tests/bjson.pic.o
484	$(CC) $(LDFLAGS) -shared -o $@ $^ $(LIBS)
485
486-include $(wildcard $(OBJDIR)/*.d)
487