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